diff options
Diffstat (limited to 'plugins/jetpack/modules/related-posts/jetpack-related-posts.php')
-rw-r--r-- | plugins/jetpack/modules/related-posts/jetpack-related-posts.php | 320 |
1 files changed, 255 insertions, 65 deletions
diff --git a/plugins/jetpack/modules/related-posts/jetpack-related-posts.php b/plugins/jetpack/modules/related-posts/jetpack-related-posts.php index fcbe23e7..ebd91cf1 100644 --- a/plugins/jetpack/modules/related-posts/jetpack-related-posts.php +++ b/plugins/jetpack/modules/related-posts/jetpack-related-posts.php @@ -1,8 +1,9 @@ <?php class Jetpack_RelatedPosts { - const VERSION = '20150408'; + const VERSION = '20190204'; const SHORTCODE = 'jetpack-related-posts'; - private static $instance = null; + + private static $instance = null; private static $instance_raw = null; /** @@ -15,10 +16,7 @@ class Jetpack_RelatedPosts { if ( class_exists('WPCOM_RelatedPosts') && method_exists( 'WPCOM_RelatedPosts', 'init' ) ) { self::$instance = WPCOM_RelatedPosts::init(); } else { - self::$instance = new Jetpack_RelatedPosts( - get_current_blog_id(), - Jetpack_Options::get_option( 'id' ) - ); + self::$instance = new Jetpack_RelatedPosts(); } } @@ -35,18 +33,13 @@ class Jetpack_RelatedPosts { if ( class_exists('WPCOM_RelatedPosts') && method_exists( 'WPCOM_RelatedPosts', 'init_raw' ) ) { self::$instance_raw = WPCOM_RelatedPosts::init_raw(); } else { - self::$instance_raw = new Jetpack_RelatedPosts_Raw( - get_current_blog_id(), - Jetpack_Options::get_option( 'id' ) - ); + self::$instance_raw = new Jetpack_RelatedPosts_Raw(); } } return self::$instance_raw; } - protected $_blog_id_local; - protected $_blog_id_wpcom; protected $_options; protected $_allow_feature_toggle; protected $_blog_charset; @@ -57,14 +50,10 @@ class Jetpack_RelatedPosts { /** * 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; + public function __construct() { $this->_blog_charset = get_option( 'blog_charset' ); $this->_convert_charset = ( function_exists( 'iconv' ) && ! preg_match( '/^utf\-?8$/i', $this->_blog_charset ) ); @@ -76,11 +65,18 @@ class Jetpack_RelatedPosts { } // Add Related Posts to the REST API Post response. - if ( function_exists( 'register_rest_field' ) ) { - add_action( 'rest_api_init', array( $this, 'rest_register_related_posts' ) ); - } + add_action( 'rest_api_init', array( $this, 'rest_register_related_posts' ) ); + + jetpack_register_block( + 'jetpack/related-posts', + array( + 'render_callback' => array( $this, 'render_block' ), + ) + ); + } - jetpack_register_block( 'related-posts' ); + protected function get_blog_id() { + return Jetpack_Options::get_option( 'id' ); } /** @@ -125,17 +121,7 @@ class Jetpack_RelatedPosts { return; if ( isset( $_GET['relatedposts'] ) ) { - $excludes = array(); - if ( isset( $_GET['relatedposts_exclude'] ) ) { - if ( is_string( $_GET['relatedposts_exclude'] ) ) { - $excludes = explode( ',', $_GET['relatedposts_exclude'] ); - } elseif ( is_array( $_GET['relatedposts_exclude'] ) ) { - $excludes = array_values( $_GET['relatedposts_exclude'] ); - } - - $excludes = array_unique( array_filter( array_map( 'absint', $excludes ) ) ); - } - + $excludes = $this->parse_numeric_get_arg( 'relatedposts_exclude' ); $this->_action_frontend_init_ajax( $excludes ); } else { if ( isset( $_GET['relatedposts_hit'], $_GET['relatedposts_origin'], $_GET['relatedposts_position'] ) ) { @@ -172,13 +158,18 @@ class Jetpack_RelatedPosts { /** * Adds a target to the post content to load related posts into if a shortcode for it did not already exist. + * Will skip adding the target if the post content contains a Related Posts block. * * @filter the_content * @param string $content * @returns string */ public function filter_add_target_to_dom( $content ) { - if ( !$this->_found_shortcode ) { + if ( has_block( 'jetpack/related-posts', $content ) ) { + return $content; + } + + if ( ! $this->_found_shortcode ) { $content .= "\n" . $this->get_target_html(); } @@ -249,12 +240,203 @@ EOT; } /** + * =============== + * GUTENBERG BLOCK + * =============== + */ + + /** + * Echoes out items for the Gutenberg block + * + * @param array $related_post The post oject. + * @param array $block_attributes The block attributes. + */ + public function render_block_item( $related_post, $block_attributes ) { + $instance_id = 'related-posts-item-' . uniqid(); + $label_id = $instance_id . '-label'; + + $item_markup = sprintf( + '<ul id="%1$s" aria-labelledby="%2$s" class="jp-related-posts-i2__post" role="menuitem">', + esc_attr( $instance_id ), + esc_attr( $label_id ) + ); + + $item_markup .= sprintf( + '<li class="jp-related-posts-i2__post-link"><a id="%1$s" href="%2$s" rel="%4$s">%3$s</a></li>', + esc_attr( $label_id ), + esc_url( $related_post['url'] ), + esc_attr( $related_post['title'] ), + esc_attr( $related_post['rel'] ) + ); + + if ( ! empty( $block_attributes['show_thumbnails'] ) && ! empty( $related_post['img']['src'] ) ) { + $img_link = sprintf( + '<li class="jp-related-posts-i2__post-img-link"><a href="%1$s" rel="%2$s"><img src="%3$s" width="%4$s" alt="%5$s" /></a></li>', + esc_url( $related_post['url'] ), + esc_attr( $related_post['rel'] ), + esc_url( $related_post['img']['src'] ), + esc_attr( $related_post['img']['width'] ), + esc_attr( $related_post['img']['alt_text'] ) + ); + + $item_markup .= $img_link; + } + + if ( $block_attributes['show_date'] ) { + $date_tag = sprintf( + '<li class="jp-related-posts-i2__post-date">%1$s</li>', + esc_html( $related_post['date'] ) + ); + + $item_markup .= $date_tag; + } + + if ( ( $block_attributes['show_context'] ) && ! empty( $related_post['context'] ) ) { + $context_tag = sprintf( + '<li class="jp-related-posts-i2__post-context">%1$s</li>', + esc_html( $related_post['context'] ) + ); + + $item_markup .= $context_tag; + } + + $item_markup .= '</ul>'; + + return $item_markup; + } + + /** + * Render a related posts row. + * + * @param array $posts The posts to render into the row. + * @param array $block_attributes Block attributes. + */ + public function render_block_row( $posts, $block_attributes ) { + $rows_markup = ''; + foreach ( $posts as $post ) { + $rows_markup .= $this->render_block_item( $post, $block_attributes ); + } + return sprintf( + '<div class="jp-related-posts-i2__row" data-post-count="%1$s">%2$s</div>', + count( $posts ), + $rows_markup + ); + } + + /** + * Render the related posts markup. + * + * @param array $attributes Block attributes. + * @return string + */ + public function render_block( $attributes ) { + $block_attributes = array( + 'show_thumbnails' => isset( $attributes['displayThumbnails'] ) && $attributes['displayThumbnails'], + 'show_date' => isset( $attributes['displayDate'] ) ? (bool) $attributes['displayDate'] : true, + 'show_context' => isset( $attributes['displayContext'] ) && $attributes['displayContext'], + 'layout' => isset( $attributes['postLayout'] ) && 'list' === $attributes['postLayout'] ? $attributes['postLayout'] : 'grid', + 'size' => ! empty( $attributes['postsToShow'] ) ? absint( $attributes['postsToShow'] ) : 3, + ); + + $excludes = $this->parse_numeric_get_arg( 'relatedposts_origin' ); + $related_posts = $this->get_for_post_id( + get_the_ID(), + array( + 'size' => $block_attributes['size'], + 'exclude_post_ids' => $excludes, + ) + ); + + $display_lower_row = $block_attributes['size'] > 3; + + if ( empty( $related_posts ) ) { + return ''; + } + + switch ( count( $related_posts ) ) { + case 2: + case 4: + case 5: + $top_row_end = 2; + break; + + default: + $top_row_end = 3; + break; + } + + $upper_row_posts = array_slice( $related_posts, 0, $top_row_end ); + $lower_row_posts = array_slice( $related_posts, $top_row_end ); + + $rows_markup = $this->render_block_row( $upper_row_posts, $block_attributes ); + if ( $display_lower_row ) { + $rows_markup .= $this->render_block_row( $lower_row_posts, $block_attributes ); + } + + $target_to_dom_priority = has_filter( + 'the_content', + array( $this, 'filter_add_target_to_dom' ) + ); + remove_filter( + 'the_content', + array( $this, 'filter_add_target_to_dom' ), + $target_to_dom_priority + ); + + /* + Below is a hack to get the block content to render correctly. + + This functionality should be covered in /inc/blocks.php but due to an error, + this has not been fixed as of this writing. + + Alda has submitted a patch to Core in order to have this issue fixed at + https://core.trac.wordpress.org/attachment/ticket/45495/do_blocks.diff and + hopefully it makes to to the final RC of WP 5.1. + */ + $priority = has_filter( 'the_content', 'wpautop' ); + remove_filter( 'the_content', 'wpautop', $priority ); + add_filter( 'the_content', '_restore_wpautop_hook', $priority + 1 ); + + return sprintf( + '<nav class="jp-relatedposts-i2" data-layout="%1$s">%2$s</nav>', + esc_attr( $block_attributes['layout'] ), + $rows_markup + ); + } + + /** * ======================== * PUBLIC UTILITY FUNCTIONS * ======================== */ /** + * Parse a numeric GET variable to an array of values. + * + * @since 6.9.0 + * + * @uses absint + * + * @param string $arg Name of the GET variable + * @return array $result Parsed value(s) + */ + public function parse_numeric_get_arg( $arg ) { + $result = array(); + + if ( isset( $_GET[ $arg ] ) ) { + if ( is_string( $_GET[ $arg ] ) ) { + $result = explode( ',', $_GET[ $arg ] ); + } elseif ( is_array( $_GET[ $arg ] ) ) { + $result = array_values( $_GET[ $arg ] ); + } + + $result = array_unique( array_filter( array_map( 'absint', $result ) ) ); + } + + return $result; + } + + /** * Gets options set for Jetpack_RelatedPosts and merge with defaults. * * @uses Jetpack_Options::get_option, apply_filters @@ -364,6 +546,7 @@ EOT; $options = $this->get_options(); $ui_settings_template = <<<EOT +<p class="description">%s</p> <ul id="settings-reading-relatedposts-customize"> <li> <label><input name="jetpack_relatedposts[show_headline]" type="checkbox" value="1" %s /> %s</label> @@ -385,6 +568,7 @@ EOT; EOT; $ui_settings = sprintf( $ui_settings_template, + esc_html__( 'The following settings will impact all related posts on your site, except for those you created via the block editor:', 'jetpack' ), checked( $options['show_headline'], true, false ), esc_html__( 'Highlight related content with a heading', 'jetpack' ), checked( $options['show_thumbnails'], true, false ), @@ -456,7 +640,7 @@ EOT; <div class="jp-relatedposts-items jp-relatedposts-items-visual"> <div class="jp-relatedposts-post jp-relatedposts-post0 jp-relatedposts-post-thumbs" data-post-id="0" data-post-format="image"> <a $href_params> - <img class="jp-relatedposts-post-img" src="https://jetpackme.files.wordpress.com/2014/08/1-wpios-ipad-3-1-viewsite.png?w=350&h=200&crop=1" width="350" alt="Big iPhone/iPad Update Now Available" scale="0"> + <img class="jp-relatedposts-post-img" src="https://jetpackme.files.wordpress.com/2019/03/cat-blog.png" width="350" alt="Big iPhone/iPad Update Now Available" scale="0"> </a> <h4 class="jp-relatedposts-post-title"> <a $href_params>Big iPhone/iPad Update Now Available</a> @@ -466,7 +650,7 @@ EOT; </div> <div class="jp-relatedposts-post jp-relatedposts-post1 jp-relatedposts-post-thumbs" data-post-id="0" data-post-format="image"> <a $href_params> - <img class="jp-relatedposts-post-img" src="https://jetpackme.files.wordpress.com/2014/08/wordpress-com-news-wordpress-for-android-ui-update2.jpg?w=350&h=200&crop=1" width="350" alt="The WordPress for Android App Gets a Big Facelift" scale="0"> + <img class="jp-relatedposts-post-img" src="https://jetpackme.files.wordpress.com/2019/03/devices.jpg" width="350" alt="The WordPress for Android App Gets a Big Facelift" scale="0"> </a> <h4 class="jp-relatedposts-post-title"> <a $href_params>The WordPress for Android App Gets a Big Facelift</a> @@ -476,7 +660,7 @@ EOT; </div> <div class="jp-relatedposts-post jp-relatedposts-post2 jp-relatedposts-post-thumbs" data-post-id="0" data-post-format="image"> <a $href_params> - <img class="jp-relatedposts-post-img" src="https://jetpackme.files.wordpress.com/2014/08/videopresswedding.jpg?w=350&h=200&crop=1" width="350" alt="Upgrade Focus: VideoPress For Weddings" scale="0"> + <img class="jp-relatedposts-post-img" src="https://jetpackme.files.wordpress.com/2019/03/mobile-wedding.jpg" width="350" alt="Upgrade Focus: VideoPress For Weddings" scale="0"> </a> <h4 class="jp-relatedposts-post-title"> <a $href_params>Upgrade Focus: VideoPress For Weddings</a> @@ -585,7 +769,7 @@ EOT; /** * Gets an array of related posts that match the given post_id. * - * @param int $post_id + * @param int $post_id Post which we want to find related posts for. * @param array $args - params to use when building Elasticsearch filters to narrow down the search domain. * @uses self::get_options, get_post_type, wp_parse_args, apply_filters * @return array @@ -597,19 +781,23 @@ EOT; $options['size'] = $args['size']; } - if ( ! $options['enabled'] || 0 == (int)$post_id || empty( $options['size'] ) || get_post_status( $post_id) !== 'publish' ) { + if ( + ! $options['enabled'] + || 0 === (int) $post_id + || empty( $options['size'] ) + ) { return array(); } $defaults = array( - 'size' => (int)$options['size'], - 'post_type' => get_post_type( $post_id ), - 'post_formats' => array(), - 'has_terms' => array(), - 'date_range' => array(), + 'size' => (int) $options['size'], + 'post_type' => get_post_type( $post_id ), + 'post_formats' => array(), + 'has_terms' => array(), + 'date_range' => array(), 'exclude_post_ids' => array(), ); - $args = wp_parse_args( $args, $defaults ); + $args = wp_parse_args( $args, $defaults ); /** * Filter the arguments used to retrieve a list of Related Posts. * @@ -796,7 +984,7 @@ EOT; */ protected function _get_coalesced_range( array $date_range ) { $now = time(); - $coalesce_time = $this->_blog_id_wpcom % 86400; + $coalesce_time = $this->get_blog_id() % 86400; $current_time = $now - strtotime( 'today', $now ); if ( $current_time < $coalesce_time && '01' == date( 'd', $now ) ) { @@ -837,7 +1025,7 @@ EOT; $related_posts = array( array( 'id' => - 1, - 'url' => 'https://jetpackme.files.wordpress.com/2014/08/1-wpios-ipad-3-1-viewsite.png?w=350&h=200&crop=1', + 'url' => 'https://jetpackme.files.wordpress.com/2019/03/cat-blog.png', 'url_meta' => array( 'origin' => 0, 'position' => 0 @@ -849,7 +1037,7 @@ EOT; 'rel' => 'nofollow', 'context' => esc_html__( 'In "Mobile"', 'jetpack' ), 'img' => array( - 'src' => 'https://jetpackme.files.wordpress.com/2014/08/1-wpios-ipad-3-1-viewsite.png?w=350&h=200&crop=1', + 'src' => 'https://jetpackme.files.wordpress.com/2019/03/cat-blog.png', 'width' => 350, 'height' => 200 ), @@ -857,7 +1045,7 @@ EOT; ), array( 'id' => - 1, - 'url' => 'https://jetpackme.files.wordpress.com/2014/08/wordpress-com-news-wordpress-for-android-ui-update2.jpg?w=350&h=200&crop=1', + 'url' => 'https://jetpackme.files.wordpress.com/2019/03/devices.jpg', 'url_meta' => array( 'origin' => 0, 'position' => 0 @@ -869,7 +1057,7 @@ EOT; 'rel' => 'nofollow', 'context' => esc_html__( 'In "Mobile"', 'jetpack' ), 'img' => array( - 'src' => 'https://jetpackme.files.wordpress.com/2014/08/wordpress-com-news-wordpress-for-android-ui-update2.jpg?w=350&h=200&crop=1', + 'src' => 'https://jetpackme.files.wordpress.com/2019/03/devices.jpg', 'width' => 350, 'height' => 200 ), @@ -877,7 +1065,7 @@ EOT; ), array( 'id' => - 1, - 'url' => 'https://jetpackme.files.wordpress.com/2014/08/videopresswedding.jpg?w=350&h=200&crop=1', + 'url' => 'https://jetpackme.files.wordpress.com/2019/03/mobile-wedding.jpg', 'url_meta' => array( 'origin' => 0, 'position' => 0 @@ -889,7 +1077,7 @@ EOT; 'rel' => 'nofollow', 'context' => esc_html__( 'In "Mobile"', 'jetpack' ), 'img' => array( - 'src' => 'https://jetpackme.files.wordpress.com/2014/08/videopresswedding.jpg?w=350&h=200&crop=1', + 'src' => 'https://jetpackme.files.wordpress.com/2019/03/mobile-wedding.jpg', 'width' => 350, 'height' => 200 ), @@ -1087,15 +1275,12 @@ EOT; protected function _generate_related_post_image_params( $post_id ) { $options = $this->get_options(); $image_params = array( - 'src' => '', - 'width' => 0, - 'height' => 0, + 'alt_text' => '', + 'src' => '', + 'width' => 0, + 'height' => 0, ); - if ( ! $options['show_thumbnails'] ) { - return $image_params; - } - /** * Filter the size of the Related Posts images. * @@ -1118,7 +1303,7 @@ EOT; // Try to get post image if ( class_exists( 'Jetpack_PostImages' ) ) { - $img_url = ''; + $img_url = ''; $post_image = Jetpack_PostImages::get_image( $post_id, $thumbnail_size @@ -1134,10 +1319,15 @@ EOT; } } - if ( !empty( $img_url ) ) { - $image_params['width'] = $thumbnail_size['width']; + if ( ! empty( $img_url ) ) { + if ( ! empty( $post_image['alt_text'] ) ) { + $image_params['alt_text'] = $post_image['alt_text']; + } else { + $image_params['alt_text'] = ''; + } + $image_params['width'] = $thumbnail_size['width']; $image_params['height'] = $thumbnail_size['height']; - $image_params['src'] = Jetpack_PostImages::fit_image_url( + $image_params['src'] = Jetpack_PostImages::fit_image_url( $img_url, $thumbnail_size['width'], $thumbnail_size['height'] @@ -1249,7 +1439,7 @@ EOT; } $response = wp_remote_post( - "https://public-api.wordpress.com/rest/v1/sites/{$this->_blog_id_wpcom}/posts/$post_id/related/", + "https://public-api.wordpress.com/rest/v1/sites/{$this->get_blog_id()}/posts/$post_id/related/", array( 'timeout' => 10, 'user-agent' => 'jetpack_related_posts', @@ -1345,7 +1535,7 @@ EOT; foreach ( $categories as $category ) { if ( 'uncategorized' != $category->slug && '' != trim( $category->name ) ) { $post_cat_context = sprintf( - _x( 'In "%s"', 'in {category/tag name}', 'jetpack' ), + esc_html_x( 'In “%s”', 'in {category/tag name}', 'jetpack' ), $category->name ); /** @@ -1551,7 +1741,7 @@ EOT; * @return array */ public function rest_get_related_posts( $object, $field_name, $request ) { - return $this->get_for_post_id( $object['id'], array() ); + return $this->get_for_post_id( $object['id'], array( 'size' => 6 ) ); } } |