Skip to content

Commit

Permalink
Gutenberg: Add a Related Posts block (#10132)
Browse files Browse the repository at this point in the history
* Add server rendering for Related Posts block

* Setting block attributes properly

* Use a custom block rendering markup

* Add some semicolons

* Remove headline from server side rendering

* Default to off for displayContext

Requires Calypso-side change:

Automattic/wp-calypso#27924

* Pass render callback to jetpack_register_block()

* Exclude previously visited post properly

* Do not load posts when they have loaded already

* Add excerpt to title attribute

* Prevent the customizer from modifying block output

* Remove legacy wrapper if we have a Related Posts block in the content

* Conditionally add jp-relatedposts-items-visual class

* Some phpcs fixes

* Simplify block attribute retrieval

* Add some spacing

* Disable customize controls when content has a related posts block

* Add disclaimer that blocks are not affected to Settings

* Add disclaimer that blocks are not affected to Jetpack Traffic settings

* Support for WP < 5.0

* Improve how we disable the legacy widget when block is present in content

* Introduce a parse_numeric_get_arg helper

* Fixup
  • Loading branch information
tyxla authored Dec 20, 2018
1 parent 7f67b8e commit aeb41ff
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 21 deletions.
3 changes: 3 additions & 0 deletions _inc/client/traffic/related-posts.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ class RelatedPostsComponent extends React.Component {
link: 'https://jetpack.com/support/related-posts/',
} }
>
<p className="jp-form-setting-explanation">
{ __( 'The following settings will impact all related posts on your site, except for those you created via the block editor:' ) }
</p>
<ModuleToggle
slug="related-posts"
disabled={ unavailableInDevMode }
Expand Down
33 changes: 32 additions & 1 deletion modules/related-posts/class.related-posts-customize.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function customize_register( $wp_customize ) {
// If selective refresh is available, implement it.
if ( isset( $wp_customize->selective_refresh ) ) {
$wp_customize->selective_refresh->add_partial( "$this->prefix", array(
'selector' => '.jp-relatedposts',
'selector' => '.jp-relatedposts:not(.jp-relatedposts-block)',
'settings' => $selective_options,
'render_callback' => __CLASS__ . '::render_callback',
'container_inclusive' => false,
Expand All @@ -113,25 +113,56 @@ public static function render_callback() {
echo Jetpack_RelatedPosts::init()->get_headline();
}

/**
* Check whether the current post contains a Related Posts block.
* If we're on WP < 5.0, this automatically means it doesn't,
* because block support is intrododuced in WP 5.0.
*
* @since 6.9.0
*
* @return bool
*/
public static function contains_related_posts_block() {
if ( ! function_exists( 'has_block' ) ) {
return false;
}

if ( has_block( 'jetpack/related-posts' ) ) {
return true;
}

return false;
}

/**
* Check that we're in a single post view.
* Will return `false` if the current post contains a Related Posts block,
* because in that case we want to hide the Customizer controls.
*
* @since 4.4.0
*
* @return bool
*/
public static function is_single() {
if ( self::contains_related_posts_block() ) {
return false;
}
return is_single();
}

/**
* Check that we're not in a single post view.
* Will return `false` if the current post contains a Related Posts block,
* because in that case we want to hide the Customizer controls.
*
* @since 4.4.0
*
* @return bool
*/
public static function is_not_single() {
if ( self::contains_related_posts_block() ) {
return false;
}
return ! is_single();
}

Expand Down
167 changes: 152 additions & 15 deletions modules/related-posts/jetpack-related-posts.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php
class Jetpack_RelatedPosts {
const VERSION = '20150408';
const VERSION = '20181213';
const SHORTCODE = 'jetpack-related-posts';
private static $instance = null;
private static $instance_raw = null;
Expand Down Expand Up @@ -77,10 +77,15 @@ public function __construct( $blog_id_local, $blog_id_wpcom ) {

// 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( 'related-posts' );
jetpack_register_block(
'related-posts',
array(
'render_callback' => array( $this, 'render_block' ),
)
);
}

/**
Expand Down Expand Up @@ -125,17 +130,7 @@ public function action_frontend_init() {
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'] ) ) {
Expand Down Expand Up @@ -172,13 +167,18 @@ public function get_headline() {

/**
* 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 ( function_exists( 'has_block' ) && has_block( 'jetpack/related-posts', $content ) ) {
return $content;
}

if ( ! $this->_found_shortcode ) {
$content .= "\n" . $this->get_target_html();
}

Expand Down Expand Up @@ -248,12 +248,147 @@ public function get_target_html_unsupported() {
return "\n\n<!-- Jetpack Related Posts is not supported in this context. -->\n\n";
}

/**
* ===============
* GUTENBERG BLOCK
* ===============
*/

/**
* 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,
)
);

if ( ! $related_posts ) {
return '';
}

ob_start();
?>
<div id="jp-relatedposts" class="jp-relatedposts jp-relatedposts-block" style="display: block;">
<div class="jp-relatedposts-items <?php echo $block_attributes['show_thumbnails'] ? 'jp-relatedposts-items-visual ' : ''; ?>jp-relatedposts-<?php echo esc_attr( $block_attributes['layout'] ); ?>">
<?php
foreach ( $related_posts as $index => $related_post ) :
$classes = array_filter(
array(
'jp-relatedposts-post',
'jp-relatedposts-post' . $index,
! empty( $block_attributes['show_thumbnails'] ) ? 'jp-relatedposts-post-thumbs' : '',
)
);
$title_attr = $related_post['title'];
if ( '' !== $related_post['excerpt'] ) {
$title_attr .= "\n\n" . $related_post['excerpt'];
}
?>
<div
class="<?php echo esc_attr( implode( ' ', $classes ) ); ?>"
data-post-id="<?php echo esc_attr( $related_post['id'] ); ?>"
data-post-format="<?php echo esc_attr( ! empty( $related_post['format'] ) ? $related_post['format'] : 'false' ); ?>"
>
<?php if ( ! empty( $block_attributes['show_thumbnails'] ) && ! empty( $related_post['img']['src'] ) ) : ?>
<a class="jp-relatedposts-post-a"
href="<?php echo esc_url( $related_post['url'] ); ?>"
title="<?php echo esc_attr( $title_attr ); ?>"
rel="<?php echo esc_attr( $related_post['rel'] ); ?>"
data-origin="<?php echo esc_attr( $related_post['url_meta']['origin'] ); ?>"
data-position="<?php echo esc_attr( $related_post['url_meta']['position'] ); ?>"
>
<img class="jp-relatedposts-post-img"
src="<?php echo esc_url( $related_post['img']['src'] ); ?>"
width="<?php echo esc_attr( $related_post['img']['width'] ); ?>"
alt="<?php echo esc_attr( $title_attr ); ?>"
/>
</a>
<?php endif; ?>

<h4 class="jp-relatedposts-post-title">
<a
class="jp-relatedposts-post-a"
href="<?php echo esc_url( $related_post['url'] ); ?>"
title="<?php echo esc_attr( $title_attr ); ?>"
rel="<?php echo esc_attr( $related_post['rel'] ); ?>"
data-origin="<?php echo esc_attr( $related_post['url_meta']['origin'] ); ?>"
data-position="<?php echo esc_attr( $related_post['url_meta']['position'] ); ?>"
>
<?php echo esc_html( $related_post['title'] ); ?>
</a>
</h4>

<p class="jp-relatedposts-post-excerpt"><?php echo esc_html( $related_post['excerpt'] ); ?></p>

<?php if ( $block_attributes['show_date'] ) : ?>
<p class="jp-relatedposts-post-date" style="display: block;">
<?php echo esc_html( $related_post['date'] ); ?>
</p>
<?php endif; ?>

<?php if ( $block_attributes['show_context'] ) : ?>
<p class="jp-relatedposts-post-context">
<?php echo esc_html( $related_post['context'] ); ?>
</p>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
</div>
<?php
$html = ob_get_clean();

return $html;
}

/**
* ========================
* 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.
*
Expand Down Expand Up @@ -364,6 +499,7 @@ public function print_setting_html() {
$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>
Expand All @@ -385,6 +521,7 @@ public function print_setting_html() {
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 ),
Expand Down
18 changes: 13 additions & 5 deletions modules/related-posts/related-posts.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,13 @@
}
};

function afterPostsHaveLoaded() {
jprp.setVisualExcerptHeights();
$( '#jp-relatedposts a.jp-relatedposts-post-a' ).click( function() {
this.href = jprp.getTrackedUrl( this );
} );
}

/**
* Initialize Related Posts.
*/
Expand All @@ -203,6 +210,11 @@
var endpointURL = jprp.getEndpointURL(),
$relatedPosts = $( '#jp-relatedposts' );

if ( $( '#jp-relatedposts .jp-relatedposts-post' ).length ) {
afterPostsHaveLoaded();
return;
}

$.getJSON( endpointURL, function( response ) {
if ( 0 === response.items.length || 0 === $relatedPosts.length ) {
return;
Expand All @@ -229,15 +241,11 @@
html = ! showThumbnails ? jprp.generateMinimalHtml( response.items, options ) : jprp.generateVisualHtml( response.items, options );

$relatedPosts.append( html );
jprp.setVisualExcerptHeights();
if ( options.showDate ) {
$relatedPosts.find( '.jp-relatedposts-post-date' ).show();
}
$relatedPosts.show();

$( '#jp-relatedposts a.jp-relatedposts-post-a' ).click(function() {
this.href = jprp.getTrackedUrl( this );
});
afterPostsHaveLoaded();
} );
}

Expand Down

0 comments on commit aeb41ff

Please sign in to comment.