-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Implemented query panel in latest posts block. #3198
Conversation
1ccd40e
to
fc9e2da
Compare
d6618c4
to
f11d90e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I'd have preferred to see the Latest Posts block updated to use withAPIData
before enhancing it to handle additional data attributes.
'default' => 'date', | ||
), | ||
'categories' => array( | ||
'type' => 'string', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: Alignment on the arrow (for consistency at least)
blocks/query-panel/index.js
Outdated
value: 'title/asc', | ||
}, | ||
{ | ||
label: __( 'Z → A' ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trying to think through localization impact here; would this be translated differently by language? We might consider at least including a translator comment to explain the intent here:
https://codex.wordpress.org/I18n_for_WordPress_Developers#Descriptions
blocks/query-panel/index.js
Outdated
onOrderChange, | ||
onOrderByChange, | ||
} ) { | ||
return ( <div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For styling consistency I'd recommend not ending lines with the opening tag of an element and rather having these on their own line. Especially in the case of the line below with <SelectControl
it helps readability to associate props with the opening tag and not losing context with the condition in which it renders.
return (
<div>
{ ( onOrderChange || onOrderByChange ) && (
<SelectControl
label={ __( 'Order by' ) }
blocks/query-panel/index.js
Outdated
onChange={ ( value ) => { | ||
const [ newOrderBy, newOrder ] = value.split( '/' ); | ||
if ( newOrder !== order ) { | ||
( onOrderChange || noop )( newOrder ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could probably test truthiness of the callback in the condition on the line above and avoid the dependency on noop
. This also reads a little "clever".
blocks/term-tree-select/index.js
Outdated
import SelectControl from '../inspector-controls/select-control'; | ||
|
||
function getSelectOptions( terms, level = 0 ) { | ||
return reduce( terms, ( options, term ) => ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might consider Lodash's flatMap
which I recently found in #3185 to perform much better than Array#reduce
+ Array#concat
.
Further, we can use array spread syntax to simplify this a bit:
function getSelectOptions( terms, level = 0 ) {
return flatMap( terms, ( term ) => [
{
value: term.id,
label: repeat( '\u00A0', level * 3 ) + unescapeString( term.name ),
},
...getSelectOptions( term.children, level + 1 ),
] );
}
blocks/term-tree-select/index.js
Outdated
} | ||
|
||
export default function TermTreeSelect( { termsTree, label, noOptionLabel, selectedTerm, onChange } ) { | ||
const options = ( noOptionLabel ? [ { value: '', label: noOptionLabel } ] : [] ).concat( getSelectOptions( termsTree ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a long line and difficult to read, I would suggest breaking it down a bit.
const options = (
noOptionLabel ?
[ { value: '', label: noOptionLabel } ] :
[]
).concat( getSelectOptions( termsTree ) );
You could also use Lodash's compact
to drop falsey values:
const options = compact( [
noOptionLabel && { value: '', label: noOptionLabel },
...getSelectOptions( termsTree ),
] );
editor/utils/terms.js
Outdated
@@ -0,0 +1,27 @@ | |||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we get some unit tests for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added :) they were missing at the time because I was not certain if a utils function was right for this case.
2290356
to
dcb3e7a
Compare
Thank you for your suggestions @aduth. I think I addressed all of them excluding an alignment in a php file. I made some changes to make things look better, but type item in categories is still not aligned with other types of other attributes, as the other type elements are not siblings (they are "cousins") if we add more spaces we break a phpcs rule. Regarding the refactoring to withAPIData in latest posts, as postsCollection.fetch supported exactly the parameters we needed, I would prefer to do this change in a separate PR. |
blocks/library/latest-posts/index.js
Outdated
const { setAttributes } = this.props; | ||
|
||
if ( postToShowCurrent === postToShowNext ) { | ||
if ( this.props.attributes === nextProps.attributes ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we want to rely on a strict equality check here; these two objects may in fact be different references while containing the same values for postsToShow
, order
, orderBy
, categories
. If we need to, we can use Lodash's _.isEqual
for a deep equality comparison.
categories: '/wp/v2/categories', | ||
} ) ); | ||
|
||
export default flowRight( [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The flowRight
here is unnecessary at this point (with a single higher-order component) and could be written as:
export default applyWithAPIData( CategorySelect );
blocks/query-panel/index.js
Outdated
onOrderByChange, | ||
} ) { | ||
return ( | ||
<div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the div
is not serving a purpose on its own, wondering if we ought to just return as an array, with the only gotcha being we'd have to add keys to each rendered element, but this would reduce the total number of DOM nodes on the screen and reduce indentation in the component:
return [
<SelectControl
key="..."
// ...
];
dcb3e7a
to
521f28b
Compare
Hi @aduth, thank you for your feedback 👍 , I rebased and addressed all the points. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Requests incurred from unrelated attribute changes should be addressed.
'render_callback' => 'gutenberg_render_block_core_latest_posts', | ||
) ); | ||
'attributes' => | ||
array( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was this changed to put array opening on a line of its own? This isn't a style I've seen common to WordPress, and adds quite a bit of excessive indentation and awkward arrow spacing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was a try to make things look more aligned while respecting phpcs rules. I reverted this change but unfortunately, I'm not seeing a way to make things more aligned and respect phpcs.
blocks/library/latest-posts/index.js
Outdated
const { setAttributes } = this.props; | ||
|
||
if ( postToShowCurrent === postToShowNext ) { | ||
if ( isEqual( this.props.attributes, nextProps.attributes ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noting that we really want to check that a change in the attributes specific to the fetching of posts are the only ones we want to trigger a new request for; as implemented, a change to the block's alignment, columns, layout will trigger a new request.
blocks/query-panel/index.js
Outdated
}, | ||
{ | ||
|
||
/* translators: label for ordering posts by title in ascending order, translation may be required for languages using non latin alphabet */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kinda feel we can drop the rest of the comment after the first comma, that's really up to the translator to judge for themselves, and the first bit should be sufficient for understanding the intent of the string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personal preference would be to drop the newline prior to this comment, feels in line with this ESLint rule we have enabled:
blocks/query-panel/index.js
Outdated
onChange={ onCategoryChange } | ||
/> ), | ||
onNumberOfItemsChange && | ||
( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistency here with the previous condition, and also tabbed at least once more than necessary. Would suggest:
onNumberOfItemsChange && (
<RangeControl
key="query-panel-range-control"
label={ __( 'Number of items' ) }
value={ numberOfItems }
onChange={ onNumberOfItemsChange }
min={ minItems }
max={ maxItems }
/>
),
448d807
to
3109a67
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Design wise approving. I did find a bug though in changing the number of items. It got stuck after going to higher number then 1.
3109a67
to
8aacd1a
Compare
Codecov Report
@@ Coverage Diff @@
## master #3198 +/- ##
==========================================
- Coverage 37.85% 37.65% -0.21%
==========================================
Files 279 283 +4
Lines 6778 6748 -30
Branches 1240 1227 -13
==========================================
- Hits 2566 2541 -25
+ Misses 3547 3545 -2
+ Partials 665 662 -3
Continue to review full report at Codecov.
|
Hi @karmatosed, I was able to replicate something similar to what you described. When increasing number of posts to show the posts were not refreshing, leaving the user to be stuck in one post if a value of one was set before. It was introduced by a typo I made while addressing the last reviews and was fixed. Thank you for reporting the problem and for reviewing the design :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to run, so here's a more drive-by review.
blocks/library/latest-posts/index.js
Outdated
if ( isEqual( | ||
pick( this.props.attributes, attrsTriggerRefresh ), | ||
pick( nextProps.attributes, attrsTriggerRefresh ) | ||
) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally not a fan of the name attrsTriggerRefresh
vs. e.g. queryKeys
/queryProps
. Though the name could be skipped altogether:
const shouldRefetch = [ 'a', 'b' ].some( ( queryKey ) =>
this.props.attributes[ queryKey ] !== nextProps.attributes[ queryKey ] );
(or the converse with shouldSkip
and Array#every
)
editor/utils/terms.js
Outdated
}; | ||
|
||
const ret = fillWithChildren( termsByParent[ 0 ] || [] ); | ||
return ret; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftover assignment of ret
?
return ( | ||
<TermTreeSelect | ||
{ ...{ label, noOptionLabel } } | ||
termsTree={ buildTermsTree( categories.data ) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens while we're waiting for the data request? Should we do an early null
return?
blocks/term-tree-select/index.js
Outdated
*/ | ||
import { unescape as unescapeString, repeat, flatMap, compact } from 'lodash'; | ||
|
||
import SelectControl from '../inspector-controls/select-control'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing Internal dependencies
comment (also, if you want to be really consistent, the External
one should use lowercase d 😅 ).
function CategorySelect( { label, noOptionLabel, categories, selectedCategory, onChange } ) { | ||
return ( | ||
<TermTreeSelect | ||
{ ...{ label, noOptionLabel } } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you have this spread, you can throw in onChange
.
@@ -62,8 +65,12 @@ function gutenberg_render_block_core_latest_posts( $attributes ) { | |||
return $block_content; | |||
} | |||
|
|||
register_block_type( 'core/latest-posts', array( | |||
register_block_type('core/latest-posts', array( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should restore that space before the string 'core/latest-posts'
.
blocks/query-panel/index.js
Outdated
if ( newOrder !== order && 'function' === typeof onOrderChange ) { | ||
onOrderChange( newOrder ); | ||
} | ||
if ( newOrderBy !== orderBy && 'function' === typeof onOrderByChange ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If onOrderChange
and onOrderByChange
default to Lodash's noop
, the function checks here can be dropped.
editor/utils/terms.js
Outdated
} ); | ||
}; | ||
|
||
const ret = fillWithChildren( termsByParent[ 0 ] || [] ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would termsByParent[ '0' ]
be more correct? Since it's dict key.
5f30b3e
to
b4e7465
Compare
Hi @mcsf, thank you a lot for your review, your feedback was applied. |
editor/utils/test/terms.js
Outdated
import { buildTermsTree } from '../terms'; | ||
|
||
describe( 'buildTermsTree()', () => { | ||
describe( 'isHorizontalEdge', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some copy-paste that went wrong? 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes @mcsf I missed it, it was solved :D
eebf4c0
to
dfe86f8
Compare
blocks/library/latest-posts/data.js
Outdated
@@ -2,15 +2,22 @@ | |||
* Returns a Promise with the latest posts or an error on failure. | |||
* | |||
* @param {Number} postsToShow Number of posts to display. | |||
* @param {String} order Sort attribute ascending or descending. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recommend enumerating the two options: desc
, asc
and rephrasing to something like: Whether to sort in ascending or descending order: 'asc'|'desc'
.
blocks/library/latest-posts/data.js
Outdated
@@ -2,15 +2,22 @@ | |||
* Returns a Promise with the latest posts or an error on failure. | |||
* | |||
* @param {Number} postsToShow Number of posts to display. | |||
* @param {String} order Sort attribute ascending or descending. | |||
* @param {String} orderBy Attribute specifying how to sort the posts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Post parameter by which to sort posts.
/** | ||
* Internal dependencies | ||
*/ | ||
import { buildTermsTree } from '../../editor/utils/terms'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
buildTermsTree
is in @wordpress/editor
, this should be a WordPress dependency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to @wordpress/utils :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch @mcsf, blocks library shouldn't depend on the editor. 👍
988ae68
to
81189ae
Compare
81189ae
to
e17bef4
Compare
e17bef4
to
ee07318
Compare
Description
Ths PR aims to implement the query panel specified in issue #2662.
The panel is added to latest posts block. But this leaves a discussion point, it allows, for example, to show 8 oldest posts by setting sorting from oldest to newest.
To solve this we need to make a decision :
We rename this block to "Posts" allowing to show the most recent ones or oldest or other option the user chooses.
Or we maintain the most recent posts concept, we always retrieve from the database the N most recent posts and then we sort this recent posts in accordance with the sorting criteria the user selected.
Feel free to share your options.
How Has This Been Tested?
Try to change the values of the 3 different options in the query panel. Verify that the posts in the editor update in accordance with the option selected. Save the post on each option change, and open the post, verify the server side render also shows the selected option correctly.
Screenshots (jpeg or gifs if applicable):
Notes
There is a bug where component looks like loading forever if there are no posts that become more visible with this changes (because we can more easily select options without posts). A fix is being issued in #3180.
The function buildTermsTree in utils was extracted from HierarchicalTermSelector component. As a future PR, this component will be refactored to make use of the utils function (removing the duplicate version) and will also be simplified/refactored to make use of the new component TermTreeSelect created in this PR.