Skip to content

Commit

Permalink
Add latest comments block (#7941)
Browse files Browse the repository at this point in the history
Add a block that shows a range of the latest comments.

Fixes #1792
See: #7369, #1931
  • Loading branch information
tofumatt committed Jul 19, 2018
1 parent 348e463 commit 1feed2c
Show file tree
Hide file tree
Showing 10 changed files with 397 additions and 0 deletions.
2 changes: 2 additions & 0 deletions core-blocks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import * as embed from './embed';
import * as file from './file';
import * as freeform from './freeform';
import * as html from './html';
import * as latestComments from './latest-comments';
import * as latestPosts from './latest-posts';
import * as list from './list';
import * as more from './more';
Expand Down Expand Up @@ -71,6 +72,7 @@ export const registerCoreBlocks = () => {
file,
freeform,
html,
latestComments,
latestPosts,
more,
nextpage,
Expand Down
123 changes: 123 additions & 0 deletions core-blocks/latest-comments/edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* WordPress dependencies
*/
import { Component, Fragment } from '@wordpress/element';
import {
Disabled,
PanelBody,
RangeControl,
ToggleControl,
ServerSideRender,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import {
InspectorControls,
BlockAlignmentToolbar,
BlockControls,
} from '@wordpress/editor';

/**
* Internal dependencies.
*/
import './editor.scss';

/**
* Minimum number of comments a user can show using this block.
*
* @type {number}
*/
const MIN_COMMENTS = 1;
/**
* Maximum number of comments a user can show using this block.
*
* @type {number}
*/
const MAX_COMMENTS = 100;

class LatestComments extends Component {
constructor() {
super( ...arguments );

this.setAlignment = this.setAlignment.bind( this );
this.setCommentsToShow = this.setCommentsToShow.bind( this );

// Create toggles for each attribute; we create them here rather than
// passing `this.createToggleAttribute( 'displayAvatar' )` directly to
// `onChange` to avoid re-renders.
this.toggleDisplayAvatar = this.createToggleAttribute( 'displayAvatar' );
this.toggleDisplayDate = this.createToggleAttribute( 'displayDate' );
this.toggleDisplayExcerpt = this.createToggleAttribute( 'displayExcerpt' );
}

createToggleAttribute( propName ) {
return () => {
const value = this.props.attributes[ propName ];
const { setAttributes } = this.props;

setAttributes( { [ propName ]: ! value } );
};
}

setAlignment( align ) {
this.props.setAttributes( { align } );
}

setCommentsToShow( commentsToShow ) {
this.props.setAttributes( { commentsToShow } );
}

render() {
const {
align,
commentsToShow,
displayAvatar,
displayDate,
displayExcerpt,
} = this.props.attributes;

return (
<Fragment>
<BlockControls>
<BlockAlignmentToolbar
value={ align }
onChange={ this.setAlignment }
/>
</BlockControls>
<InspectorControls>
<PanelBody title={ __( 'Latest Comments Settings' ) }>
<ToggleControl
label={ __( 'Display avatar' ) }
checked={ displayAvatar }
onChange={ this.toggleDisplayAvatar }
/>
<ToggleControl
label={ __( 'Display date' ) }
checked={ displayDate }
onChange={ this.toggleDisplayDate }
/>
<ToggleControl
label={ __( 'Display excerpt' ) }
checked={ displayExcerpt }
onChange={ this.toggleDisplayExcerpt }
/>
<RangeControl
label={ __( 'Number of comments' ) }
value={ commentsToShow }
onChange={ this.setCommentsToShow }
min={ MIN_COMMENTS }
max={ MAX_COMMENTS }
/>
</PanelBody>
</InspectorControls>
<Disabled>
<ServerSideRender
block="core/latest-comments"
attributes={ this.props.attributes }
/>
</Disabled>
</Fragment>
);
}
}

export default LatestComments;
14 changes: 14 additions & 0 deletions core-blocks/latest-comments/editor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.wp-block-latest-comments.has-avatars .avatar {
margin-right: 10px;
}

.wp-block-latest-comments__comment-excerpt p {
font-size: 14px;
line-height: $editor-line-height;
margin: 5px 0 20px;
padding-top: 0;
}

.wp-block-latest-comments.has-avatars .wp-block-latest-comments__comment {
min-height: 36px;
}
44 changes: 44 additions & 0 deletions core-blocks/latest-comments/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* WordPress dependencies.
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies.
*/
import './style.scss';
import edit from './edit';

export const name = 'core/latest-comments';

export const settings = {
title: __( 'Latest Comments' ),

description: __( 'Show a list of your site’s most recent comments.' ),

icon: 'list-view',

category: 'widgets',

keywords: [ __( 'recent comments' ) ],

supports: {
html: false,
},

getEditWrapperProps( attributes ) {
const { align } = attributes;

// TODO: Use consistent values across the app;
// see: https://github.com/WordPress/gutenberg/issues/7908.
if ( [ 'left', 'center', 'right', 'wide', 'full' ].includes( align ) ) {
return { 'data-align': align };
}
},

edit,

save() {
return null;
},
};
143 changes: 143 additions & 0 deletions core-blocks/latest-comments/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<?php
/**
* Server-side rendering of the `core/latest-comments` block.
*
* @package gutenberg
*/

// Used to get `_draft_or_post_title`, which prevents empty-title posts from
// appearing with no title.
require_once( ABSPATH . 'wp-admin/includes/template.php' );

/**
* Renders the `core/latest-comments` block on server.
*
* @param array $attributes The block attributes.
*
* @return string Returns the post content with latest comments added.
*/
function gutenberg_render_block_core_latest_comments( $attributes = array() ) {
// This filter is documented in wp-includes/widgets/class-wp-widget-recent-comments.php.
$comments = get_comments( apply_filters( 'widget_comments_args', array(
'number' => $attributes['commentsToShow'],
'status' => 'approve',
'post_status' => 'publish',
) ) );

$list_items_markup = '';
if ( ! empty( $comments ) ) {
// Prime the cache for associated posts. This is copied from \WP_Widget_Recent_Comments::widget().
$post_ids = array_unique( wp_list_pluck( $comments, 'comment_post_ID' ) );
_prime_post_caches( $post_ids, strpos( get_option( 'permalink_structure' ), '%category%' ), false );

foreach ( $comments as $comment ) {
$list_items_markup .= '<li class="wp-block-latest-comments__comment">';
if ( $attributes['displayAvatar'] ) {
$avatar = get_avatar( $comment, 48, '', '', array(
'class' => 'wp-block-latest-comments__comment-avatar',
) );
if ( $avatar ) {
$list_items_markup .= $avatar;
}
}

$list_items_markup .= '<article>';
$list_items_markup .= '<footer class="wp-block-latest-comments__comment-meta">';
$author_url = get_comment_author_url( $comment );
if ( empty( $author_url ) && ! empty( $comment->user_id ) ) {
$author_url = get_author_posts_url( $comment->user_id );
}

$author_markup = '';
if ( $author_url ) {
$author_markup .= '<a class="wp-block-latest-comments__comment-author" href="' . esc_url( $author_url ) . '">' . get_comment_author( $comment ) . '</a>';
} else {
$author_markup .= '<span class="wp-block-latest-comments__comment-author">' . get_comment_author( $comment ) . '</span>';
}

// `_draft_or_post_title` calls `esc_html()` so we don't need to wrap that call in
// `esc_html`.
$post_title = '<a class="wp-block-latest-comments__comment-link" href="' . esc_url( get_comment_link( $comment ) ) . '">' . _draft_or_post_title( $comment->comment_post_ID ) . '</a>';

$list_items_markup .= sprintf(
/* translators: 1: author name (inside <a> or <span> tag, based on if they have a URL), 2: post title related to this comment */
__( '%1$s on %2$s', 'gutenberg' ),
$author_markup,
$post_title
);

if ( $attributes['displayDate'] ) {
$list_items_markup .= sprintf(
'<time datetime="%1$s" class="wp-block-latest-comments__comment-date">%2$s</time>',
esc_attr( get_comment_date( 'c', $comment ) ),
date_i18n( get_option( 'date_format' ), get_comment_date( 'U', $comment ) )
);
}
$list_items_markup .= '</footer>';
if ( $attributes['displayExcerpt'] ) {
$list_items_markup .= '<div class="wp-block-latest-comments__comment-excerpt">' . wpautop( get_comment_excerpt( $comment ) ) . '</div>';
}
$list_items_markup .= '</article></li>';
}
}

$class = 'wp-block-latest-comments';
if ( $attributes['align'] ) {
$class .= " align{$attributes['align']}";
}
if ( $attributes['displayAvatar'] ) {
$class .= ' has-avatars';
}
if ( $attributes['displayDate'] ) {
$class .= ' has-dates';
}
if ( $attributes['displayExcerpt'] ) {
$class .= ' has-excerpts';
}
if ( empty( $comments ) ) {
$class .= ' no-comments';
}
$classnames = esc_attr( $class );

$block_content = ! empty( $comments ) ? sprintf(
'<ol class="%1$s">%2$s</ol>',
$classnames,
$list_items_markup
) : sprintf( '<div class="%1$s">%2$s</div>',
$classnames,
__( 'No comments to show.', 'gutenberg' )
);

return $block_content;
}

register_block_type( 'core/latest-comments', array(
'attributes' => array(
'className' => array(
'type' => 'string',
),
'commentsToShow' => array(
'type' => 'number',
'default' => 5,
'minimum' => 1,
'maximum' => 100,
),
'displayAvatar' => array(
'type' => 'boolean',
'default' => true,
),
'displayDate' => array(
'type' => 'boolean',
'default' => true,
),
'displayExcerpt' => array(
'type' => 'boolean',
'default' => true,
),
'align' => array(
'type' => 'string',
'enum' => array( 'center', 'left', 'right', 'wide', 'full', '' ),
),
),
'render_callback' => 'gutenberg_render_block_core_latest_comments',
) );
43 changes: 43 additions & 0 deletions core-blocks/latest-comments/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
.wp-block-latest-comments__comment {
font-size: 15px;
line-height: 1.1;
list-style: none;
margin-bottom: 1em;

.has-avatars & {
min-height: 36px;
list-style: none;

.wp-block-latest-comments__comment-meta,
.wp-block-latest-comments__comment-excerpt {
margin-left: 52px;
}
}

.has-dates &,
.has-excerpts & {
line-height: 1.5;
}
}

.wp-block-latest-comments__comment-excerpt p {
font-size: 14px;
line-height: 1.8;
margin: 5px 0 20px;
}

.wp-block-latest-comments__comment-date {
color: $dark-gray-100;
display: block;
font-size: 12px;
}

.wp-block-latest-comments .avatar,
.wp-block-latest-comments__comment-avatar {
border-radius: 24px;
display: block;
float: left;
height: 40px;
margin-right: 12px;
width: 40px;
}
1 change: 1 addition & 0 deletions core-blocks/test/fixtures/core__latest-comments.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!-- wp:latest-comments {"displayAvatar":true,"displayExcerpt":true,"displayTimestamp":true} /-->
Loading

0 comments on commit 1feed2c

Please sign in to comment.