class Jetpack_RelatedPosts { const VERSION = '20150408'; const SHORTCODE = 'jetpack-related-posts'; /** * Creates and returns a static instance of Jetpack_RelatedPosts. * * @return Jetpack_RelatedPosts */ public static function init() { static $instance = NULL; if ( ! $instance ) { if ( class_exists('WPCOM_RelatedPosts') && method_exists( 'WPCOM_RelatedPosts', 'init' ) ) { $instance = WPCOM_RelatedPosts::init(); } else { $instance = new Jetpack_RelatedPosts( get_current_blog_id(), Jetpack_Options::get_option( 'id' ) ); } } return $instance; } /** * Creates and returns a static instance of Jetpack_RelatedPosts_Raw. * * @return Jetpack_RelatedPosts */ public static function init_raw() { static $instance = NULL; if ( ! $instance ) { if ( class_exists('WPCOM_RelatedPosts') && method_exists( 'WPCOM_RelatedPosts', 'init_raw' ) ) { $instance = WPCOM_RelatedPosts::init_raw(); } else { $instance = new Jetpack_RelatedPosts_Raw( get_current_blog_id(), Jetpack_Options::get_option( 'id' ) ); } } return $instance; } protected $_blog_id_local; protected $_blog_id_wpcom; protected $_options; protected $_allow_feature_toggle; protected $_blog_charset; protected $_convert_charset; protected $_previous_post_id; protected $_found_shortcode = false; /** * Constructor for Jetpack_RelatedPosts. * * @param int $blog_id_local * @param int $blog_id_wpcom * @uses get_option, add_action, apply_filters * @return null */ public function __construct( $blog_id_local, $blog_id_wpcom ) { $this->_blog_id_local = $blog_id_local; $this->_blog_id_wpcom = $blog_id_wpcom; $this->_blog_charset = get_option( 'blog_charset' ); $this->_convert_charset = ( function_exists( 'iconv' ) && ! preg_match( '/^utf\-?8$/i', $this->_blog_charset ) ); add_action( 'admin_init', array( $this, 'action_admin_init' ) ); add_action( 'wp', array( $this, 'action_frontend_init' ) ); } /** * ================= * ACTIONS & FILTERS * ================= */ /** * Add a checkbox field to Settings > Reading for enabling related posts. * * @action admin_init * @uses add_settings_field, __, register_setting, add_action * @return null */ public function action_admin_init() { // Add the setting field [jetpack_relatedposts] and place it in Settings > Reading add_settings_field( 'jetpack_relatedposts', '' . __( 'Related posts', 'jetpack' ) . '', array( $this, 'print_setting_html' ), 'reading' ); register_setting( 'reading', 'jetpack_relatedposts', array( $this, 'parse_options' ) ); add_action('admin_head', array( $this, 'print_setting_head' ) ); if( 'options-reading.php' == $GLOBALS['pagenow'] ) { // Enqueue style for live preview on the reading settings page $this->_enqueue_assets( false, true ); } } /** * Load related posts assets if it's a elegiable frontend page or execute search and return JSON if it's an endpoint request. * * @global $_GET * @action wp * @uses add_shortcode, get_the_ID * @returns null */ public function action_frontend_init() { // Add a shortcode handler that outputs nothing, this gets overridden later if we can display related content add_shortcode( self::SHORTCODE, array( $this, 'get_target_html_unsupported' ) ); if ( ! $this->_enabled_for_request() ) return; if ( isset( $_GET['relatedposts'] ) ) { $excludes = array(); if ( isset( $_GET['relatedposts_exclude'] ) ) { $excludes = explode( ',', $_GET['relatedposts_exclude'] ); } $this->_action_frontend_init_ajax( $excludes ); } else { if ( isset( $_GET['relatedposts_hit'], $_GET['relatedposts_origin'], $_GET['relatedposts_position'] ) ) { $this->_log_click( $_GET['relatedposts_origin'], get_the_ID(), $_GET['relatedposts_position'] ); $this->_previous_post_id = (int) $_GET['relatedposts_origin']; } $this->_action_frontend_init_page(); } } /** * Adds a target to the post content to load related posts into if a shortcode for it did not already exist. * * @filter the_content * @param string $content * @returns string */ public function filter_add_target_to_dom( $content ) { if ( !$this->_found_shortcode ) { $content .= "\n" . $this->get_target_html(); } return $content; } /** * Looks for our shortcode on the unfiltered content, this has to execute early. * * @filter the_content * @param string $content * @uses has_shortcode * @returns string */ public function test_for_shortcode( $content ) { $this->_found_shortcode = has_shortcode( $content, self::SHORTCODE ); return $content; } /** * Returns the HTML for the related posts section. * * @uses esc_html__, apply_filters * @returns string */ public function get_target_html() { $options = $this->get_options(); if ( $options['show_headline'] ) { $headline = sprintf( '', esc_html__( 'Related', 'jetpack' ) ); } else { $headline = ''; } /** * Filter the Related Posts headline. * * @module related-posts * * @since 3.0.0 * * @param string $headline Related Posts heading. */ $headline = apply_filters( 'jetpack_relatedposts_filter_headline', $headline ); if ( $this->_previous_post_id ) { $exclude = "data-exclude='{$this->_previous_post_id}'"; } else { $exclude = ""; } return << $headline EOT; } /** * Returns the HTML for the related posts section if it's running in the loop or other instances where we don't support related posts. * * @returns string */ public function get_target_html_unsupported() { return "\n\n\n\n"; } /** * ======================== * PUBLIC UTILITY FUNCTIONS * ======================== */ /** * Gets options set for Jetpack_RelatedPosts and merge with defaults. * * @uses Jetpack_Options::get_option, apply_filters * @return array */ public function get_options() { if ( null === $this->_options ) { $this->_options = Jetpack_Options::get_option( 'relatedposts' ); if ( ! is_array( $this->_options ) ) $this->_options = array(); if ( ! isset( $this->_options['enabled'] ) ) $this->_options['enabled'] = true; if ( ! isset( $this->_options['show_headline'] ) ) $this->_options['show_headline'] = true; if ( ! isset( $this->_options['show_thumbnails'] ) ) $this->_options['show_thumbnails'] = false; if ( empty( $this->_options['size'] ) || (int)$this->_options['size'] < 1 ) $this->_options['size'] = 3; /** * Filter Related Posts basic options. * * @module related-posts * * @since 2.8.0 * * @param array $this->_options Array of basic Related Posts options. */ $this->_options = apply_filters( 'jetpack_relatedposts_filter_options', $this->_options ); } return $this->_options; } /** * Parses input and returnes normalized options array. * * @param array $input * @uses self::get_options * @return array */ public function parse_options( $input ) { $current = $this->get_options(); if ( !is_array( $input ) ) $input = array(); if ( isset( $input['enabled'] ) && '1' == $input['enabled'] ) { $current['enabled'] = true; $current['show_headline'] = ( isset( $input['show_headline'] ) && '1' == $input['show_headline'] ); $current['show_thumbnails'] = ( isset( $input['show_thumbnails'] ) && '1' == $input['show_thumbnails'] ); } else { $current['enabled'] = false; } if ( isset( $input['size'] ) && (int)$input['size'] > 0 ) $current['size'] = (int)$input['size']; else $current['size'] = null; return $current; } /** * HTML for admin settings page. * * @uses self::get_options, checked, esc_html__ * @returns null */ public function print_setting_html() { $options = $this->get_options(); $ui_settings_template = <<
  • EOT; $ui_settings = sprintf( $ui_settings_template, checked( $options['show_headline'], true, false ), esc_html__( 'Show a "Related" header to more clearly separate the related section from posts', 'jetpack' ), checked( $options['show_thumbnails'], true, false ), esc_html__( 'Use a large and visually striking layout', 'jetpack' ), esc_html__( 'Preview:', 'jetpack' ) ); if ( !$this->_allow_feature_toggle() ) { $template = << %s EOT; printf( $template, $ui_settings ); } else { $template = <<
  • %s
  • EOT; printf( $template, checked( $options['enabled'], false, false ), esc_html__( 'Hide related content after posts', 'jetpack' ), checked( $options['enabled'], true, false ), esc_html__( 'Show related content after posts', 'jetpack' ), $ui_settings ); } } /** * Head JS/CSS for admin settings page. * * @uses esc_html__ * @returns null */ public function print_setting_head() { // only dislay the Related Posts JavaScript on the Reading Settings Admin Page $current_screen = get_current_screen(); if( 'options-reading' != $current_screen->id ) return; $related_headline = sprintf( '', esc_html__( 'Related', 'jetpack' ) ); $href_params = 'class="jp-relatedposts-post-a" href="#jetpack_relatedposts" rel="nofollow" data-origin="0" data-position="0"'; $related_with_images = <<