.
*/
// Include constants file
require_once( dirname( __FILE__ ) . '/lib/constants.php' );
class AuthorRecommendedPosts {
static $html_newline = "\n";
var $namespace = "author_recommended_posts";
var $version = "1.0.1";
// Default plugin options
var $defaults = array(
'author_recommended_posts_title' => "Author Recommended Posts",
'author_recommended_posts_show_title' => true,
'author_recommended_posts_show_featured_image' => false,
'author_recommended_posts_format_is_horizontal' => true,
'author_recommended_posts_post_types' => array( 'post' ),
'author_recommended_posts_output_after_content' => true,
'author_recommended_posts_auto_output' => array( 'post' )
);
/**
* Instantiation construction
*
* @uses add_action()
* @uses AuthorRecommendedPosts::wp_register_scripts()
* @uses AuthorRecommendedPosts::wp_register_styles()
*/
function __construct() {
// Name of the option_value to store plugin options in
$this->option_name = '_' . $this->namespace . '--options';
// Set and Translate the friendly name
$this->friendly_name = __( "Author Recommended Posts", $this->namespace );
// Load all library files used by this plugin
$libs = glob( AUTHOR_RECOMMENDED_POSTS_DIRNAME . '/lib/*.php' );
foreach( $libs as $lib ) {
include_once( $lib );
}
/**
* Make this plugin available for translation.
* Translations can be added to the /languages/ directory.
*/
load_theme_textdomain( $this->namespace, AUTHOR_RECOMMENDED_POSTS_DIRNAME . '/languages' );
// Add all action, filter and shortcode hooks
$this->_add_hooks();
}
/**
* Add in various hooks
*
* Place all add_action, add_filter, add_shortcode hook-ins here
*/
private function _add_hooks() {
// Options page for configuration
add_action( 'admin_menu', array( &$this, 'admin_menu' ) );
// Route requests for form processing
add_action( 'init', array( &$this, 'route' ) );
// Add the meta boxes
add_action( 'add_meta_boxes', array( &$this, 'add_recommended_meta_box' ) );
// Save post meta to the post
add_action( 'save_post', array( &$this, 'saving_recommended_posts_ids' ), 10, 2 );
// Filter the content of the post and output at the end of the content
add_filter( 'the_content', array( &$this, 'recommended_posts_output' ) );
// Add a settings link next to the "Deactivate" link on the plugin listing page
add_filter( 'plugin_action_links', array( &$this, 'plugin_action_links' ), 10, 2 );
// Register all JavaScripts for this plugin
add_action( 'init', array( &$this, 'wp_register_scripts' ), 1 );
// Register all Stylesheets for this plugin
add_action( 'init', array( &$this, 'wp_register_styles' ), 1 );
// Enqueue all Public Stylesheets for this plugin
add_action( 'wp_head', array( &$this, 'enqueue_custom_styles' ), 1 );
// Ajax handler for searching/filter posts
add_action( 'wp_ajax_author_recommended_posts_search', array( &$this, 'author_recommended_posts_search') );
add_shortcode( 'AuthorRecommendedPosts', array( &$this, 'shortcode') );
}
/**
* Process update page form submissions
*
* @uses AuthorRecommendedPosts::sanitize()
* @uses wp_redirect()
* @uses wp_verify_nonce()
*/
private function _admin_options_update() {
// Verify submission for processing using wp_nonce
if( wp_verify_nonce( $_REQUEST['_wpnonce'], "{$this->namespace}-update-options" ) ) {
$data = array();
/**
* Loop through each POSTed value and sanitize it to protect against malicious code. Please
* note that rich text (or full HTML fields) should not be processed by this function and
* dealt with directly.
*/
foreach( $_POST['data'] as $key => $val ) {
$data[$key] = $this->_sanitize( $val );
}
/**
* Place your options processing and storage code here
*/
// Checking to see if Output Options are empty, if they are we are setting an empty array so it does not pull in defaults
// Defaults come in when the option is not set, so basically this sets the option to nothing
if( empty( $data["author_recommended_posts_auto_output"] ) ){
$data["author_recommended_posts_auto_output"] = array();
}
// Update the options value with the data submitted
update_option( $this->option_name, $data );
// Redirect back to the options page with the message flag to show the saved message
wp_safe_redirect( $_REQUEST['_wp_http_referer'] . '&message=1' );
exit;
}
}
/**
* Sanitize data
*
* @param mixed $str The data to be sanitized
*
* @uses wp_kses()
*
* @return mixed The sanitized version of the data
*/
private function _sanitize( $str ) {
if ( !function_exists( 'wp_kses' ) ) {
require_once( ABSPATH . 'wp-includes/kses.php' );
}
global $allowedposttags;
global $allowedprotocols;
if ( is_string( $str ) ) {
$str = wp_kses( $str, $allowedposttags, $allowedprotocols );
} elseif( is_array( $str ) ) {
$arr = array();
foreach( (array) $str as $key => $val ) {
$arr[$key] = $this->_sanitize( $val );
}
$str = $arr;
}
return $str;
}
/**
* Hook into register_activation_hook action
*
* Put code here that needs to happen when your plugin is first activated (database
* creation, permalink additions, etc.)
*/
static function activate() {
// Do activation actions
}
/**
* Add Recommended Meta Box
*
* runs the add_meta_box() method to create the Meta Box in the post
*/
function add_recommended_meta_box() {
// set post_types that this meta box shows up on.
$author_recommended_posts_post_types = $this->get_option( "{$this->namespace}_post_types" );
foreach( $author_recommended_posts_post_types as $author_recommended_posts_post_type ) {
// adds to posts $post_type
add_meta_box(
$this->namespace . '-recommended_meta_box',
__( 'Author Recommended Posts', $this->namespace ),
array( &$this, 'recommended_meta_box' ),
$author_recommended_posts_post_type,
'side',
'high'
);
}
}
/**
* Recommended Meta Box
*
* Adds the meta box to post types that allows the author to set
* which posts they want to pull into the Recommended Author Reading section
*/
function recommended_meta_box( $object, $box ) {
$author_recommended_posts = get_post_meta( $object->ID, $this->namespace, true );
$author_recommended_posts_post_types = $this->get_option( "{$this->namespace}_post_types" );
$author_recommended_posts_search_results = $this->author_recommended_posts_search();
$author_recommended_posts_options_url = admin_url() . '/options-general.php?page=' . $this->namespace;
include( AUTHOR_RECOMMENDED_POSTS_DIRNAME . '/views/_recommended-meta-box.php' );
}
function author_recommended_posts_search(){
global $post;
$post_id = $post->ID;
$html = '';
// set post_types that get filtered in the search box.
$author_recommended_posts_post_types = $this->get_option( "{$this->namespace}_post_types" );
// set default query options
$options = array(
'post_type' => $author_recommended_posts_post_types,
'posts_per_page' => 10,
'paged' => 0,
'order' => 'DESC',
'post_status' => array('publish'),
'suppress_filters' => false,
'post__not_in' => array($post_id),
's' => ''
);
// check if ajax
$ajax = isset( $_POST['action'] ) ? true : false;
// if ajax merge $_POST
if( $ajax ) {
$options = array_merge($options, $_POST);
}
// search
if( $options['s'] ) {
// set temp title to search query
$options['like_title'] = $options['s'];
// filter query by title
add_filter( 'posts_where', array($this, 'posts_where'), 10, 2 );
}
// unset search so results are accurate and not muddled
unset( $options['s'] );
$searchable_posts = get_posts( $options );
if( $searchable_posts ) {
foreach( $searchable_posts as $searchable_post ) {
// right aligned info
$title = '';
$title .= $searchable_post->post_type;
$title .= '';
$title .= '';
$title .= apply_filters( 'the_title', $searchable_post->post_title, $searchable_post->ID );
$title .= '';
$html .= '
' . $title . '' . "\n";
}
}
// if ajax, die and echo $html otherwise just return
if( $ajax ) {
die( $html );
} else {
return $html;
}
}
function posts_where( $where, &$wp_query ) {
global $wpdb;
if ( $title = $wp_query->get('like_title') ) {
$where .= " AND " . $wpdb->posts . ".post_title LIKE '%" . esc_sql( like_escape( $title ) ) . "%'";
}
return $where;
}
function saving_recommended_posts_ids( $post_id, $post ) {
if( isset( $_REQUEST['_post_ids_nonce'] ) && !empty( $_REQUEST['_post_ids_nonce'] ) ){
// Verfiy the nonce before proceeding
if( !wp_verify_nonce( $_REQUEST['_post_ids_nonce'], "{$this->namespace}_post_ids_nonce" ) ) {
return $post_id;
}
// Get the post type object.
$post_type = get_post_type_object( $post->post_type );
// Check if the current user has permissions to edit the post.
if( !current_user_can( $post_type->cap->edit_post, $post_id ) ) {
return $post_id;
}
// Get the posted data and sanitize
$new_meta_value = ( isset( $_POST['author-recommended-posts'] ) ? $this->_sanitize( $_POST['author-recommended-posts'] ) : '' );
// Get the meta key
$meta_key = $this->namespace;
// Get the meta value of the custom field key
$meta_value = get_post_meta( $post_id, $meta_key, true );
// If the new meta value was added and there was no previous value, add it.
if ( $new_meta_value && ( '' == $meta_value ) ) {
add_post_meta( $post_id, $meta_key, $new_meta_value, true );
// If the new meta value does not match the old value, update it.
} elseif ( $new_meta_value && $new_meta_value != $meta_value ) {
update_post_meta( $post_id, $meta_key, $new_meta_value );
// If there is no new meta value but an old value exists, delete it.
} elseif ( ( '' == $new_meta_value ) && $meta_value ) {
delete_post_meta( $post_id, $meta_key, $meta_value );
}
}
}
/**
* Runs the shortcode in the content filter if single view
*
* @param string $content The content of the post
*
* @uses do_shortcode()
*
* @return string The content with Author Recommended Posts appended if single and if exists
*/
function recommended_posts_output( $content ){
global $post;
$author_recommended_posts_auto_output = $this->get_option( "{$this->namespace}_auto_output" );
if( is_singular() ) {
if ( in_array( $post->post_type, $author_recommended_posts_auto_output ) ) {
$html = do_shortcode('[AuthorRecommendedPosts post_id='. $post->ID .']');
$content = $content . $html;
}
}
return $content;
}
/**
* Process the SlideDeck shortcode
*
* @param object $atts Attributes of the shortcode
*
* @uses shortcode_atts()
* @uses slidedeck_process_template()
*
* @return object The processed shortcode
*/
function shortcode( $atts ) {
global $post;
if ( isset( $atts['post_id'] ) && !empty( $atts['post_id'] ) ){
$shortcode_post_id = $atts['post_id'];
}else{
$shortcode_post_id = $post->ID;
}
$recommended_ids = get_post_meta( $shortcode_post_id, $this->namespace, true );
$html = '';
if( $recommended_ids ){
$html_title = $this->get_option( "{$this->namespace}_title" );
$show_title = $this->get_option( "{$this->namespace}_show_title" );
$show_featured_image = $this->get_option( "{$this->namespace}_show_featured_image" );
$format_horizontal = $this->get_option( "{$this->namespace}_format_is_horizontal" );
$author_recommended_posts_post_types = $this->get_option( "{$this->namespace}_post_types" );
ob_start( );
include( AUTHOR_RECOMMENDED_POSTS_DIRNAME . '/views/_author-recommended-posts-list.php' );
$html .= ob_get_contents( );
ob_end_clean( );
}
return $html;
}
/**
* Define the admin menu options for this plugin
*
* @uses add_action()
* @uses add_options_page()
*/
function admin_menu() {
$page_hook = add_options_page( $this->friendly_name, $this->friendly_name, 'administrator', $this->namespace, array( &$this, 'admin_options_page' ) );
// Add print scripts and styles action based off the option page hook
add_action( 'admin_print_scripts-' . $page_hook, array( &$this, 'admin_print_scripts' ) );
add_action( 'admin_print_styles-' . $page_hook, array( &$this, 'admin_print_styles' ) );
add_action( 'admin_print_scripts-post.php', array( &$this, 'admin_print_scripts' ) );
add_action( 'admin_print_styles-post.php', array( &$this, 'admin_print_styles' ) );
add_action( 'admin_print_scripts-post-new.php', array( &$this, 'admin_print_scripts' ) );
add_action( 'admin_print_styles-post-new.php', array( &$this, 'admin_print_styles' ) );
}
/**
* The admin section options page rendering method
*
* @uses current_user_can()
* @uses wp_die()
*/
function admin_options_page() {
if( !current_user_can( 'manage_options' ) ) {
wp_die( 'You do not have sufficient permissions to access this page' );
}
$page_title = $this->friendly_name . ' Options';
$namespace = $this->namespace;
// Look Up Data and Build Array of Posts
$registered_post_types = get_post_types( array( 'exclude_from_search' => false ), 'objects' );
// Rebuild the array into something more usable
$author_recommended_posts_post_types = array();
foreach( $registered_post_types as $key => $val ){
$author_recommended_posts_post_types[] = array(
'slug' => $key,
'name' => $val->labels->name
);
}
include( AUTHOR_RECOMMENDED_POSTS_DIRNAME . "/views/options.php" );
}
/**
* Load JavaScript for the admin options page
*
* @uses wp_enqueue_script()
*/
function admin_print_scripts() {
global $post;
// =====================================================================
// check to see if the post type is included in the options set by user
// =====================================================================
wp_enqueue_script( "{$this->namespace}-admin" );
}
/**
* Load Stylesheet for the admin options page
*
* @uses wp_enqueue_style()
*/
function admin_print_styles() {
wp_enqueue_style( "{$this->namespace}-admin" );
}
/**
* Hook into register_deactivation_hook action
*
* Put code here that needs to happen when your plugin is deactivated
*/
static function deactivate() {
// Do deactivation actions
}
/**
* Retrieve the stored plugin option or the default if no user specified value is defined
*
* @param string $option_name The name of the TrialAccount option you wish to retrieve
*
* @uses get_option()
*
* @return mixed Returns the option value or false(boolean) if the option is not found
*/
function get_option( $option_name ) {
// Load option values if they haven't been loaded already
if( !isset( $this->options ) || empty( $this->options ) ) {
$this->options = get_option( $this->option_name, $this->defaults );
}
if( isset( $this->options[$option_name] ) ) {
return $this->options[$option_name]; // Return user's specified option value
} elseif( isset( $this->defaults[$option_name] ) ) {
return $this->defaults[$option_name]; // Return default option value
}
return false;
}
/**
* Initialization function to hook into the WordPress init action
*
* Instantiates the class on a global variable and sets the class, actions
* etc. up for use.
*/
static function instance() {
global $AuthorRecommendedPosts;
// Only instantiate the Class if it hasn't been already
if( !isset( $AuthorRecommendedPosts ) ) $AuthorRecommendedPosts = new AuthorRecommendedPosts();
}
/**
* Hook into plugin_action_links filter
*
* Adds a "Settings" link next to the "Deactivate" link in the plugin listing page
* when the plugin is active.
*
* @param object $links An array of the links to show, this will be the modified variable
* @param string $file The name of the file being processed in the filter
*/
function plugin_action_links( $links, $file ) {
if( $file == plugin_basename( AUTHOR_RECOMMENDED_POSTS_DIRNAME . '/' . basename( __FILE__ ) ) ) {
$old_links = $links;
$new_links = array(
"settings" => '' . __( 'Settings' ) . ''
);
$links = array_merge( $new_links, $old_links );
}
return $links;
}
/**
* Route the user based off of environment conditions
*
* This function will handling routing of form submissions to the appropriate
* form processor.
*
* @uses AuthorRecommendedPosts::_admin_options_update()
*/
function route() {
$uri = $_SERVER['REQUEST_URI'];
$protocol = isset( $_SERVER['HTTPS'] ) ? 'https' : 'http';
$hostname = $_SERVER['HTTP_HOST'];
$url = "{$protocol}://{$hostname}{$uri}";
$is_post = (bool) ( strtoupper( $_SERVER['REQUEST_METHOD'] ) == "POST" );
// Check if a nonce was passed in the request
if( isset( $_REQUEST['_wpnonce'] ) ) {
$nonce = $_REQUEST['_wpnonce'];
// Handle POST requests
if( $is_post ) {
if( wp_verify_nonce( $nonce, "{$this->namespace}-update-options" ) ) {
$this->_admin_options_update();
}
}
// Handle GET requests
else {
}
}
}
/**
* Register scripts used by this plugin for enqueuing elsewhere
*
* @uses wp_register_script()
*/
function wp_register_scripts() {
// Admin JavaScript
wp_register_script( "{$this->namespace}-admin", AUTHOR_RECOMMENDED_POSTS_URLPATH . "/js/admin.js", array( 'jquery' ), $this->version, true );
}
/**
* Register styles used by this plugin for enqueuing elsewhere
*
* @uses wp_register_style()
*/
function wp_register_styles() {
// Admin Stylesheet
wp_register_style( "{$this->namespace}-admin", AUTHOR_RECOMMENDED_POSTS_URLPATH . "/css/admin.css", array(), $this->version, 'screen' );
// Public Stylesheet
wp_register_style( "{$this->namespace}-public", AUTHOR_RECOMMENDED_POSTS_URLPATH . "/css/public.css", array(), $this->version, 'screen' );
}
/**
* Enqueue public styles used by this plugin
*
* @uses wp_enqueue_style()
*/
function enqueue_custom_styles(){
wp_enqueue_style( "{$this->namespace}-public" );
}
}
if( !isset( $AuthorRecommendedPosts ) ) {
AuthorRecommendedPosts::instance();
}
register_activation_hook( __FILE__, array( 'AuthorRecommendedPosts', 'activate' ) );
register_deactivation_hook( __FILE__, array( 'AuthorRecommendedPosts', 'deactivate' ) );