New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add latest comments block #7941

Merged
merged 36 commits into from Jul 19, 2018

Conversation

@tofumatt
Copy link
Member

tofumatt commented Jul 12, 2018

Description

Fixes #1792. Note that this PR is based on #7369, which is based on #1931. I've made a few tweaks (mentioned in #7369).

Closes #7369.


@tofumatt here:

I've made some changes here from the original PR, mainly around:

  1. changing get_the_title to _draft_or_post_title as it's the only way to display posts with no title
  2. escaping the post title
  3. Markup changes
  4. CSS refactors/tweaks
  5. Added centre-alignment support

I was going to add tests but these tests require post comments, and making them means I need a mock/test database, as the current e2e tests run against the local development URL. I'll do those in a follow-up branch as I've tested this locally a fair bit.


Adds Latest Comments block v1 using ServerSideRender component.
Allows configuring the following:

  • Number of comments displayed;
  • Comment excerpt to be shown;
  • Permit avatar to be shown;
  • Permit timestamps to be shown.

Screenshots

Editor:

screenshot 2018-07-12 23 40 58

Frontend:

screenshot 2018-07-12 23 35 58

Checklist:

  • My code is tested functionally.
  • My code follows the WordPress code style.
  • My code has proper inline documentation.
}
$list_items_markup .= __( ' on ', 'gutenberg' );
$list_items_markup .= '<a class="wp-block-latest-comments__comment-link" href="' . esc_url( get_comment_link( $comment ) ) . '">' . get_the_title( $comment->comment_post_ID ) . '</a>';

This comment has been minimized.

@tofumatt

tofumatt Jul 12, 2018

Author Member

Just checked into this and it looks like get_the_title() doesn't do any escaping, so this is Dangerous™. I'll have it fixed in a branch and add tests for it.

@tofumatt tofumatt requested a review from gziolo Jul 12, 2018

@Soean Soean added the New Block label Jul 13, 2018

@tofumatt tofumatt requested a review from WordPress/gutenberg-core Jul 13, 2018

$attributes['commentsToShow'] = $DEFAULT_COMMENTS_TO_SHOW;
}
// This filter is documented in wp-includes/widgets/class-wp-widget-recent-comments.php

This comment has been minimized.

@Soean

Soean Jul 13, 2018

Member

Inline comments must end in full-stops, exclamation marks, or question marks

$author_markup .= '<span class="wp-block-latest-comments__comment-author">' . get_comment_author( $comment ) . '</span>';
}
$post_title = '<a class="wp-block-latest-comments__comment-link" href="' . esc_url( get_comment_link( $comment ) ) . '">' . esc_html ( _draft_or_post_title( $comment->comment_post_ID ) ) . '</a>';

This comment has been minimized.

@Soean

Soean Jul 13, 2018

Member

There is a space after esc_html

$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' ),

This comment has been minimized.

@Soean

Soean Jul 13, 2018

Member

Text domain ''gutenberg' is missing

onChange={ this.toggleAttribute( 'displayAvatar' ) }
/>
<ToggleControl
label={ __( 'Display date/time' ) }

This comment has been minimized.

@Soean

Soean Jul 13, 2018

Member

I only see the date, no time
bildschirmfoto 2018-07-13 um 14 33 29

This comment has been minimized.

@tofumatt

tofumatt Jul 13, 2018

Author Member

Huh, seems right. It used to say "timestamp" which is definitely wrong, but maybe it should be using a better date function. I'll check it out...

@tofumatt tofumatt added this to the 3.3 milestone Jul 13, 2018

// appearing with no title.
require_once( ABSPATH . 'wp-admin/includes/template.php' );
$DEFAULT_COMMENTS_TO_SHOW = 5;

This comment has been minimized.

}
register_block_type( 'core/latest-comments', array(
'attributes' => array(

This comment has been minimized.

@Soean

This comment has been minimized.

@tofumatt

tofumatt Jul 13, 2018

Author Member

Ah, cheers. They looked weird before with bizarre indentation but I guess that was the right way.

This comment has been minimized.

@Soean

Soean Jul 13, 2018

Member

Yes, it looks a little bit strange.
You can check it local: https://wordpress.org/gutenberg/handbook/reference/coding-guidelines/#php

@tofumatt

This comment has been minimized.

Copy link
Member Author

tofumatt commented Jul 16, 2018

(I think this is all set for another review.)

@mcsf
Copy link
Contributor

mcsf left a comment

Thanks for taking this on, @tofumatt.

We need to address the case in which there are no comments to show. This is what the user gets now:

screen shot 2018-07-17 at 18 06 34

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

setAttributes( { commentsToShow: parseInt( commentsToShow, 10 ) || 0 } );

This comment has been minimized.

@mcsf

mcsf Jul 17, 2018

Contributor

Type coercion already happens behind the block API (asType). We should drop the ad hoc validation here. See Gallery or Columns for examples of core blocks using RangeControl with no other type validation than the one built in.

This comment has been minimized.

@mcsf

mcsf Jul 17, 2018

Contributor

I'm not a big fan of setAlignment and setCommentsToShow, as they just duplicate setAttributes.

I also don't love toggleAttribute, but don't feel strongly enough to oppose.

This comment has been minimized.

@tofumatt

tofumatt Jul 17, 2018

Author Member

The Gallery block, for instance, has a lot of specific functions that just call setAttributes. I think the notion is explicitly setting one prop per control. It's usually the way I'd create functions for a component. 🤷‍♂️

The alternative is an inline function passed as a prop, right?

<RangeControl
	label={ __( 'Number of comments' ) }
	value={ commentsToShow }
	onChange={ this.setCommentsToShow }
	min={ MIN_COMMENTS }
	max={ MAX_COMMENTS }
/>

or

<RangeControl
	label={ __( 'Number of comments' ) }
	value={ commentsToShow }
	onChange={ ( value ) => ( this.setAttributes( 'commentsToShow', value ) ) }
	min={ MIN_COMMENTS }
	max={ MAX_COMMENTS }
/>

This comment has been minimized.

@mcsf

mcsf Jul 17, 2018

Contributor

Hm, in both I only see drawbacks. 😄 Pick your poison, I say.

a {
cursor: default;
pointer-events: none;
}

This comment has been minimized.

@mcsf

mcsf Jul 17, 2018

Contributor

This poses the same interaction problems as when the Archives block was being developed. We should use the more robust Disabled element. See 480338c

This comment has been minimized.

@tofumatt

tofumatt Jul 17, 2018

Author Member

Nice, I didn't code this bit but will do. 👍

}
},

edit: edit,

This comment has been minimized.

@mcsf

mcsf Jul 17, 2018

Contributor

(minor): edit,

This comment has been minimized.

@tofumatt

tofumatt Jul 17, 2018

Author Member

I think we should have an eslint rule for that if it's important, but I'll change this one. 😄

This comment has been minimized.

@mcsf

mcsf Jul 17, 2018

Contributor

Nop, totally minor. I prefer the shorthand. ¯_(ツ)_/¯

This comment has been minimized.

@tofumatt

tofumatt Jul 17, 2018

Author Member

I do too… but we should have rules over preferences 😉

I've filed #8009.

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

if ( DEFAULT_CONTROLS.includes( align ) ) {

This comment has been minimized.

@mcsf

mcsf Jul 17, 2018

Contributor

I realize that the way we need to wrangle alignment types and do the getEditWrapperProps dance is suboptimal, but I'd rather have that addressed separately. Can we keep getEditWrapperProps here in line with other core blocks and revert exposing the constants?

This comment has been minimized.

@tofumatt

tofumatt Jul 17, 2018

Author Member

Related is
#7908 (comment); before this the code copied what many other elements did and ignored centre-alignment, which caused the centre alignment option to do nothing.

I feel like it's better to do this as a starting point here and convert everything else over in #7908. This would be the way we'd want things to go, right?

This comment has been minimized.

@mcsf

mcsf Jul 17, 2018

Contributor

This would be the way we'd want things to go, right?

Maybe, maybe not. :) But it deserves its own PR. I'd undo here.

/**
* Internal dependencies.
*/
import { DEFAULT_CONTROLS } from 'editor/components/block-alignment-toolbar';

This comment has been minimized.

@mcsf

mcsf Jul 17, 2018

Contributor

Per my other comment, we should get rid of this, but worth noting that this would've been a disapproved import (importing private entities across packages).

This comment has been minimized.

@tofumatt

tofumatt Jul 17, 2018

Author Member

I think I'm lost–how is it a private entity?

This comment has been minimized.

@mcsf

mcsf Jul 17, 2018

Contributor

Because it's not a top-level export of editor, i.e. you wouldn't be able to get it via

import { DEFAULT_CONTROLS } from '@wordpress/editor';

and we avoid importing across blocks in any other fashion (i.e. a module in core-blocks importing from editor). There were some exceptions to this due to circular dependencies, but I think they're all but solved.

This comment has been minimized.

@tofumatt

tofumatt Jul 17, 2018

Author Member

Aha, gotcha.

Has there been discussion about a custom rule to catch that for us or has it been difficult to implement? Seems quite easy to miss in a review.

This comment has been minimized.

@mcsf

mcsf Jul 17, 2018

Contributor

There are rules against import { Bla } from 'editor'; (and any other package), but none for deep access. I'm assuming we don't yet forbit deep access because of those unresolved circular dependencies we had-and-may-still-have. Someone may correct me on this. :)

This comment has been minimized.

@tofumatt

tofumatt Jul 17, 2018

Author Member

That won't actually work (eslint throws an error), but I have a PR incoming.

This comment has been minimized.

@aduth

aduth Jul 17, 2018

Member

That won't actually work (eslint throws an error), but I have a PR incoming.

Yeah, might be the same thing I've encountered before, where it was solved by including the unicode equivalent character of the slash.

This comment has been minimized.

@aduth

aduth Jul 17, 2018

Member

Uncanny! Do you have a matcher for lint?

I actually have no idea how this notification came through to my inbox 😅

This comment has been minimized.

@tofumatt

tofumatt Jul 17, 2018

Author Member

Whoa, is that what that is? If it works I'll add a comment for it this time 😅

This comment has been minimized.

@tofumatt

tofumatt Jul 17, 2018

Author Member

zomg that worked, thanks. I'll add it and add a comment this time 😉

$author_markup .= '<span class="wp-block-latest-comments__comment-author">' . get_comment_author( $comment ) . '</span>';
}
$post_title = '<a class="wp-block-latest-comments__comment-link" href="' . esc_url( get_comment_link( $comment ) ) . '">' . esc_html( _draft_or_post_title( $comment->comment_post_ID ) ) . '</a>';

This comment has been minimized.

@mcsf

mcsf Jul 17, 2018

Contributor

_draft_or_post_title already calls esc_html, though I can accept if you'd rather also escape here for reviewers peace of mind.

This comment has been minimized.

@tofumatt

tofumatt Jul 17, 2018

Author Member

I think I originally added the esc_html (or it was here already?) because we weren't using _draft_or_post_title. I suppose now that it's being used we can omit the extra escape.

In general I like seeing it but in this case I'll leave a comment explaining that _draft_or_post_title does the escaping. No need to run it twice.

@tofumatt

This comment has been minimized.

Copy link
Member Author

tofumatt commented Jul 17, 2018

Yeah, I noticed that and I have something in the pipeline, should be pushed soon.

tofumatt added a commit that referenced this pull request Jul 17, 2018

@tofumatt tofumatt requested a review from mcsf Jul 17, 2018

@tofumatt

This comment has been minimized.

Copy link
Member Author

tofumatt commented Jul 17, 2018

Thanks for the review, all set for another look.

tofumatt added a commit that referenced this pull request Jul 17, 2018

@tofumatt tofumatt force-pushed the miina-add/latest-comments-block branch from aa2bed3 to 6604304 Jul 17, 2018

@tofumatt

This comment has been minimized.

Copy link
Member Author

tofumatt commented Jul 17, 2018

Wait, scratch that, I seem to be getting a weird CSS error locally. Investigating...

tofumatt added a commit that referenced this pull request Jul 17, 2018

chore: Improve eslint checks for deep imports (#8013)
* chore: Improve eslint checks for deep imports

See: #7941 (comment)

* chore: Use fetch not request
@tofumatt

This comment has been minimized.

Copy link
Member Author

tofumatt commented Jul 17, 2018

Wait, scratch that, I seem to be getting a weird CSS error locally. Investigating...

It was something weird locally. Reset my env and everything is good. Ready for another review!

@aduth aduth referenced this pull request Jul 18, 2018

Closed

Add Latest Comments block. #7369

3 of 3 tasks complete
@aduth

This comment has been minimized.

Copy link
Member

aduth commented Jul 18, 2018

Can #7369 be closed in favor of this one?

@aduth

This comment has been minimized.

Copy link
Member

aduth commented Jul 18, 2018

Got some test failures, might be a bad rebase with the fixtures. Should be regenerated with npm run fixtures:regenerate.

@tofumatt

This comment has been minimized.

Copy link
Member Author

tofumatt commented Jul 18, 2018

Indeed, I see those too. Just a moment and I'll push that 👍

miina added some commits Jun 11, 2018

@tofumatt

This comment has been minimized.

Copy link
Member Author

tofumatt commented Jul 18, 2018

Well, fixed things manually for now, but I'll need to see why the fixtures aren't regenerating properly later... Should be passing now.

@aduth

This comment has been minimized.

Copy link
Member

aduth commented Jul 19, 2018

There are PHPCS (code styling) errors now. Will review what's here currently in the meantime.

FILE: /app/core-blocks/latest-comments/index.php
----------------------------------------------------------------------
FOUND 2 ERRORS AFFECTING 1 LINE
----------------------------------------------------------------------
 114 | ERROR | [x] Expected 1 spaces after opening bracket; 0 found
     |       |     (PEAR.Functions.FunctionCallSignature.SpaceAfterOpenBracket)
 114 | ERROR | [x] Expected 1 spaces before closing bracket; 0 found
     |       |     (PEAR.Functions.FunctionCallSignature.SpaceBeforeCloseBracket)
@tofumatt

This comment has been minimized.

Copy link
Member Author

tofumatt commented Jul 19, 2018

Shoot, I thought I fixed them, sorry 'bout that. Will push the fix now.

@tofumatt

This comment has been minimized.

Copy link
Member Author

tofumatt commented Jul 19, 2018

(Fixed)

this.toggleAttribute = this.toggleAttribute.bind( this );
}

toggleAttribute( propName ) {

This comment has been minimized.

@aduth

aduth Jul 19, 2018

Member

This function doesn't toggle anything on its own, it creates a function which performs the toggle. More accurately, it might be named createToggleAttribute.

<ToggleControl
label={ __( 'Display avatar' ) }
checked={ displayAvatar }
onChange={ this.toggleAttribute( 'displayAvatar' ) }

This comment has been minimized.

@aduth

aduth Jul 19, 2018

Member

toggleAttribute returns a new function every invocation, causing React to do render reconciliation more often than we need it to. I wonder if we should pre-bind these functions in the constructor:

constructor() {
	// ...

	this.toggleDisplayAvatar = this.createToggleAttribute( 'displayAvatar' );
}

This comment has been minimized.

@tofumatt

tofumatt Jul 19, 2018

Author Member

Yeah, this has been pointed out elsewhere that this pattern is bad for unneeded re-renders, though obviously the code is nice.

Pre-binding them in the constructor is a good pattern actually 👍

*/
import './editor.scss';

const MIN_COMMENTS = 1;

This comment has been minimized.

@aduth

aduth Jul 19, 2018

Member

IMO we should JSDoc any constant, even just to establish the convention in encouraging the practice for less-obvious constants.

This comment has been minimized.

@tofumatt

tofumatt Jul 19, 2018

Author Member

I'm cool with that 👍

/>
</PanelBody>
</InspectorControls>
<Disabled>

This comment has been minimized.

@aduth

aduth Jul 19, 2018

Member

Makes me wonder: Is there any case where we want ServerSideRender to not be disabled? Should this be built-in to the render logic of that component?

This comment has been minimized.

@tofumatt

tofumatt Jul 19, 2018

Author Member

I wondered that too, we should probably open an issue for it. I suppose building it in and then having some escape hatch prop that doesn't disable it would be good.

margin-right: 10px;
}

.edit-post-visual-editor {

This comment has been minimized.

@aduth

aduth Jul 19, 2018

Member

Why do we need this context?

This comment has been minimized.

@tofumatt

tofumatt Jul 19, 2018

Author Member

I bet we don't; I inherited this CSS and I guess I didn't refactor enough. It can go. 👍

// appearing with no title.
require_once( ABSPATH . 'wp-admin/includes/template.php' );
$default_comments_to_show = 5;

This comment has been minimized.

@aduth

aduth Jul 19, 2018

Member

As I understand it, scoping in PHP won't work as expected with what we have here. This would need to be accessed by global, which we're not doing.

Simpler demonstration:

Before:

<?php

$extra = 'bar';

function do_foo() {
	echo 'foo' . $extra;
}

do_foo();
⇒ php test.php
foo%        

After:

<?php

$extra = 'bar';

function do_foo() {
	global $extra;
	echo 'foo' . $extra;
}

do_foo();
⇒ php test.php
foobar%     

Though, as written, it's more of a constant, which is exemplified in define.

Though, above all, does this really need to be in the global scope? I think we're over-optimizing at the risk of outside breakage (anything else in the running WordPress page could access this variable, intentionally or not).

This comment has been minimized.

@tofumatt

tofumatt Jul 19, 2018

Author Member

Yeah I didn't think using define was right because I wanted a constant scoped to this file–and the constants created by define are global... right?

I'll admit that my PHP is wildly rusty and I'm totally unclear what the best practice is for this.

I just want a file-scoped constant. I can remove it if that's a pain to make.

This comment has been minimized.

@aduth

aduth Jul 19, 2018

Member

and the constants created by define are global... right?

Yes, and so is the previous variable assignment, as can be demonstrated:

diff --git a/core-blocks/latest-comments/index.php b/core-blocks/latest-comments/index.php
index 33c21e41f..092fe08eb 100644
--- a/core-blocks/latest-comments/index.php
+++ b/core-blocks/latest-comments/index.php
@@ -9,6 +9,7 @@
 // appearing with no title.
 require_once( ABSPATH . 'wp-admin/includes/template.php' );
 
+$default_comments_to_show = 5;
 define( 'GUTENBERG_LATEST_COMMENTS_BLOCK_DEFAULT_TO_SHOW', 5 );
 
 /**
diff --git a/lib/load.php b/lib/load.php
index f1a8b09c6..f8a4b7985 100644
--- a/lib/load.php
+++ b/lib/load.php
@@ -34,3 +34,5 @@ require dirname( __FILE__ ) . '/register.php';
 foreach ( glob( dirname( __FILE__ ) . '/../core-blocks/*/index.php' ) as $block_logic ) {
 	require $block_logic;
 }
+
+var_export( $default_comments_to_show ); exit;

This comment has been minimized.

This comment has been minimized.

@tofumatt

tofumatt Jul 19, 2018

Author Member

Yeah, I didn't realise that 😢

If the define call is too global I'm fine with just hard-coding it in. 🤷‍♂️

This comment has been minimized.

@aduth

aduth Jul 19, 2018

Member

Since it's prefixed enough it shouldn't be a huge concern.

This comment has been minimized.

@aduth

aduth Jul 19, 2018

Member

Alternatively, we could consider enhancing our JSON schema support to handle minimum and maximum, rely on the validation behavior, and assign the default only once in the block registration.

https://spacetelescope.github.io/understanding-json-schema/reference/numeric.html#range

In fact, since we use REST validation under the hood, I wonder if this is already possible.

This comment has been minimized.

@aduth

aduth Jul 19, 2018

Member

It's already supported:

https://github.com/WordPress/wordpress-develop/blob/8f95800d52c1736d651ae6e259f90ad4a0db2c3f/src/wp-includes/rest-api.php#L1169-L1209

Our usage will trigger the default to take its place when outside bounds:

if ( isset( $attributes[ $attribute_name ] ) ) {
$is_valid = rest_validate_value_from_schema( $attributes[ $attribute_name ], $schema );
if ( ! is_wp_error( $is_valid ) ) {
$value = rest_sanitize_value_from_schema( $attributes[ $attribute_name ], $schema );
}
}
if ( is_null( $value ) && isset( $schema['default'] ) ) {
$value = $schema['default'];
}

This comment has been minimized.

@tofumatt

tofumatt Jul 19, 2018

Author Member

Huh, nice! Okay, I'll look at that.

@tofumatt tofumatt requested review from aduth and WordPress/gutenberg-core Jul 19, 2018

@tofumatt

This comment has been minimized.

Copy link
Member Author

tofumatt commented Jul 19, 2018

Thanks! Ready for another review.


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

This comment has been minimized.

@aduth

aduth Jul 19, 2018

Member

We should double check that our new ES2015 prototype member polyfills with Babel 7 useBuiltIns: 'usage' allows this to work as expected in IE11.

This is an ES2015+ method which until recently was not expected to be polyfilled and would therefore error in IE11.

This comment has been minimized.

@tofumatt

tofumatt Jul 19, 2018

Author Member

I tested it in IE11 and it worked; I could change the align values and nothing errored on me (it touches this code path).

// appearing with no title.
require_once( ABSPATH . 'wp-admin/includes/template.php' );
$default_comments_to_show = 5;

This comment has been minimized.

@aduth

aduth Jul 19, 2018

Member

This $default_comments_to_show variable is unused. I suspect it wasn't intentional to keep.

This comment has been minimized.

@tofumatt

tofumatt Jul 19, 2018

Author Member

Entirely not, sorry. Fixed.

@tofumatt

This comment has been minimized.

Copy link
Member Author

tofumatt commented Jul 19, 2018

Side note: I have e2e tests written and ready for this, but they depend on #8041 because I need to ensure there are no existing posts/comments in the test database.

@tofumatt tofumatt requested a review from aduth Jul 19, 2018

@aduth

aduth approved these changes Jul 19, 2018

Copy link
Member

aduth left a comment

Looks good 👍

Stale review.

@tofumatt tofumatt merged commit 1feed2c into master Jul 19, 2018

2 checks passed

codecov/project 49.31% (+0.13%) compared to b06a335
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details

@tofumatt tofumatt deleted the miina-add/latest-comments-block branch Jul 19, 2018

@StaggerLeee

This comment has been minimized.

Copy link

StaggerLeee commented Jul 20, 2018

One question. Who will use it ?
It is not anything for the Post. Latest comments is thing for Widget, sidebar.

I am bit confuse with your plans to make blocks for all old WP native widgets.

@tofumatt

This comment has been minimized.

Copy link
Member Author

tofumatt commented Jul 20, 2018

@pento pento referenced this pull request Jul 23, 2018

Closed

Fix the Server Fixtures generator #8126

4 of 4 tasks complete

@afercia afercia added the Widgets label Jan 30, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment