diff --git a/core-blocks/index.js b/core-blocks/index.js index 6782e3c5b6ef6..25042fdd5c06b 100644 --- a/core-blocks/index.js +++ b/core-blocks/index.js @@ -27,6 +27,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'; @@ -69,6 +70,7 @@ export const registerCoreBlocks = () => { file, freeform, html, + latestComments, latestPosts, more, nextpage, diff --git a/core-blocks/latest-comments/edit.js b/core-blocks/latest-comments/edit.js new file mode 100644 index 0000000000000..4c76758c73f6f --- /dev/null +++ b/core-blocks/latest-comments/edit.js @@ -0,0 +1,100 @@ +/** + * WordPress dependencies + */ +import { Component, Fragment } from '@wordpress/element'; +import { + PanelBody, + RangeControl, + ToggleControl, + ServerSideRender, +} from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { + InspectorControls, + BlockAlignmentToolbar, + BlockControls, +} from '@wordpress/editor'; + +/** + * Internal dependencies. + */ +import './editor.scss'; + +const MIN_COMMENTS = 1; +const MAX_COMMENTS = 100; + +class LatestComments extends Component { + constructor() { + super( ...arguments ); + this.toggleHandler = this.toggleHandler.bind( this ); + this.changeCommentsToShow = this.changeCommentsToShow.bind( this ); + } + + toggleHandler( propName ) { + return () => { + const value = this.props.attributes[ propName ]; + const { setAttributes } = this.props; + + setAttributes( { [ propName ]: ! value } ); + }; + } + + changeCommentsToShow( commentsToShow ) { + const { setAttributes } = this.props; + + setAttributes( { commentsToShow: parseInt( commentsToShow, 10 ) || 0 } ); + } + + render() { + const { setAttributes } = this.props; + const { align, displayAvatar, displayTimestamp } = this.props.attributes; + + return ( + + + { + setAttributes( { align: nextAlign } ); + } } + controls={ [ 'left', 'center', 'right', 'wide', 'full' ] } + /> + + + + + + + + + + + this.changeCommentsToShow( value ) } + min={ MIN_COMMENTS } + max={ MAX_COMMENTS } + /> + + + + + + ); + } +} + +export default LatestComments; diff --git a/core-blocks/latest-comments/editor.scss b/core-blocks/latest-comments/editor.scss new file mode 100644 index 0000000000000..774166ddffa5e --- /dev/null +++ b/core-blocks/latest-comments/editor.scss @@ -0,0 +1,32 @@ +.wp-block-latest-comments.alignright { + margin: 0 7em 2em; +} +.wp-block-latest-comments.alignleft { + margin-right: 2em; +} + +.wp-block-latest-comments { + a { + pointer-events: none; + cursor: default; + } + + .has-avatars img { + margin-right: 10px; + } +} + +.edit-post-visual-editor { + .wp-block-latest-comments__comment-excerpt p { + font-size: 14px; + line-height: 1.8; + padding-top: 0; + margin: 5px 0 20px; + } + + .wp-block-latest-comments { + .has-avatars > li { + min-height: 36px; + } + } +} diff --git a/core-blocks/latest-comments/index.js b/core-blocks/latest-comments/index.js new file mode 100644 index 0000000000000..908621ab1927c --- /dev/null +++ b/core-blocks/latest-comments/index.js @@ -0,0 +1,41 @@ +/** + * 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: __( 'Shows 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; + if ( 'left' === align || 'right' === align || 'wide' === align || 'full' === align ) { + return { 'data-align': align }; + } + }, + + edit: edit, + + save() { + return null; + }, +}; diff --git a/core-blocks/latest-comments/index.php b/core-blocks/latest-comments/index.php new file mode 100644 index 0000000000000..1d702bfc0b18f --- /dev/null +++ b/core-blocks/latest-comments/index.php @@ -0,0 +1,131 @@ + 100 + ) { + $attributes['commentsToShow'] = 5; + } + + $align = 'center'; + if ( isset( $attributes['align'] ) && in_array( $attributes['align'], array( 'left', 'right', 'wide', 'full' ), true ) ) { + $align = $attributes['align']; + } + + /** 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 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 .= '
  • '; + 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 .= '
    user_id ) ) { + $author_url = get_author_posts_url( $comment->user_id ); + } + if ( $author_url ) { + $list_items_markup .= '' . get_comment_author( $comment ) . ''; + } else { + $list_items_markup .= '' . get_comment_author( $comment ) . ''; + } + + $list_items_markup .= __( ' on ', 'gutenberg' ); + $list_items_markup .= '' . get_the_title( $comment->comment_post_ID ) . ''; + + if ( $attributes['displayTimestamp'] ) { + $list_items_markup .= sprintf( + '', + esc_attr( get_comment_date( 'c', $comment ) ), + esc_html( get_comment_date( '', $comment ) ) + ); + } + if ( $attributes['displayExcerpt'] ) { + $list_items_markup .= '
    ' . wpautop( get_comment_excerpt( $comment ) ) . '
    '; + } + $list_items_markup .= '
  • '; + } + } + + $class = "wp-block-latest-comments align{$align}"; + if ( $attributes['displayAvatar'] ) { + $class .= ' has-avatars'; + } + if ( $attributes['displayTimestamp'] ) { + $class .= ' has-timestamps'; + } + if ( $attributes['displayExcerpt'] ) { + $class .= ' has-excerpts'; + } + + $block_content = sprintf( + '', + esc_attr( $class ), + $list_items_markup + ); + + return $block_content; +} + +register_block_type( 'core/latest-comments', array( + 'attributes' => array( + 'className' => array( + 'type' => 'string', + ), + 'commentsToShow' => array( + 'type' => 'number', + 'default' => 5, + ), + 'displayAvatar' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'displayExcerpt' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'displayTimestamp' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'align' => array( + 'type' => 'string', + 'default' => 'center', + ), + ), + 'render_callback' => 'gutenberg_render_block_core_latest_comments', +) ); diff --git a/core-blocks/latest-comments/style.scss b/core-blocks/latest-comments/style.scss new file mode 100644 index 0000000000000..950fa5576dd5a --- /dev/null +++ b/core-blocks/latest-comments/style.scss @@ -0,0 +1,52 @@ +.wp-block-latest-comments { + padding-left: 2.5em; + + li { + line-height: 1.1; + margin-bottom: 1em; + font-size: 15px; + } + + &.has-avatars > li { + min-height: 36px; + list-style: none; + + .comment-data { + margin-left: 52px; + } + } + + .latestcomments { + line-height: 2.2; + } + + &.has-timestamps, + &.has-excerpts { + .latestcomments { + 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-timestamp { + color: $dark-gray-100; + font-size: 12px; + padding: 8px 2px 0 0; + display: block; +} + +.wp-block-latest-comments .avatar, +.wp-block-latest-comments__comment-avatar { + display: block; + float: left; + height: 40px; + width: 40px; + border-radius: 24px; + margin-right: 12px; +} diff --git a/core-blocks/test/fixtures/core__latest-comments.html b/core-blocks/test/fixtures/core__latest-comments.html new file mode 100644 index 0000000000000..cc4a2523b9d41 --- /dev/null +++ b/core-blocks/test/fixtures/core__latest-comments.html @@ -0,0 +1 @@ + diff --git a/core-blocks/test/fixtures/core__latest-comments.json b/core-blocks/test/fixtures/core__latest-comments.json new file mode 100644 index 0000000000000..3a41fc27d3aa8 --- /dev/null +++ b/core-blocks/test/fixtures/core__latest-comments.json @@ -0,0 +1,10 @@ +[ + { + "uid": "_uid_0", + "name": "core/latest-comments", + "isValid": true, + "attributes": {}, + "innerBlocks": [], + "originalContent": "" + } +] diff --git a/core-blocks/test/fixtures/core__latest-comments.parsed.json b/core-blocks/test/fixtures/core__latest-comments.parsed.json new file mode 100644 index 0000000000000..a8806d27be5a4 --- /dev/null +++ b/core-blocks/test/fixtures/core__latest-comments.parsed.json @@ -0,0 +1,16 @@ +[ + { + "blockName": "core/latest-comments", + "attrs": { + "displayAvatar": true, + "displayExcerpt": true, + "displayTimestamp": true + }, + "innerBlocks": [], + "innerHTML": "" + }, + { + "attrs": {}, + "innerHTML": "\n" + } +] diff --git a/core-blocks/test/fixtures/core__latest-comments.serialized.html b/core-blocks/test/fixtures/core__latest-comments.serialized.html new file mode 100644 index 0000000000000..a50d5664a60a6 --- /dev/null +++ b/core-blocks/test/fixtures/core__latest-comments.serialized.html @@ -0,0 +1 @@ +