-
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
Add "Latest Posts" Block #870
Conversation
969a0ed
to
ffcd2a1
Compare
Thanks for doing this. For now, this block will show the latest post at the moment where we save the block, if we create a new post after that. This new post is not included in the frontend. I think this post is a good opportunity to leverage the Server Side Rendering to address this. |
Yeah, I've seen your PR but haven't looked into it more. I also agree since it's an expected behavior to always display the latest posts, especially when using REST API (ie it's 'dynamic'). |
Thanks for giving this a try!
Definitely, this is a great example of a purely dynamic block in my book. |
*/ | ||
import { registerBlock } from '../../api'; | ||
|
||
function getLatestPosts( postsToShow = 5 ) { |
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.
Thinking... this could be a good example for breaking some logic into a separate file. Perhaps rest-api-latest-posts/data.js
? Or maybe too much abstraction at this stage.
@@ -0,0 +1,71 @@ | |||
/** |
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.
Let's call this block just latest-posts
.
There's good overlap here with the Recent Posts widget. |
Sweet deal, and awesome work! I was so inspired I took a stab at the design of this, as suggested in your ToDo. Note: the following is very mockuppy and conceptual, and I expect some pushback here. The implementation is also probably something that can happen best in a separate PR, but nonetheless to keep the discussion grouped for now, here it is. Neutral: Selected: This leverages both the "block-first" UI of putting the most basic stuff right on the block, and the more advanced stuff in the Inspector on the right. For this concept, I arbitrarily decided to put the post date and number of posts in the inspector, but this was also done in order to grease the discussion on what we put there (see #672 ). |
@jasmussen I like this, but I think we could also avoid it looking like a form if we just made the title an optional editable field like caption/quote-source with placeholder text instead of a label and an input. |
This was my first instinct as well. I do think we'll want some further iteration here, as to what feels right. But I specifically like the gray background which is a callback to placeholders. Not only does this help the block feel distinct from the others, in that it's dynamic, but it also literally "grays" the content, implying you can't edit it directly. |
Question: can However, it seems like Gutenberg doesn't like if attribute is |
@lamosty |
3330a77
to
9ab5f7c
Compare
In 497cee8, I added simple server-side rendering. However, I had to rename the component to Now, I have some more questions :):
|
Yes, @notnownikki proposed a SSR endpoint see (#780) and implemented it in the WIP pr #816
For now, the frontend is just a raw HTML, saved from the editor (the |
blocks/library/latest-posts/index.js
Outdated
|
||
this.props.setAttributes( { | ||
poststoshow | ||
} ); |
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 have mixed feelings here, we're calling setAttributes
in the constructor which could change the markup directly. I think it's better to use defaultAttributes
property for this (see usage in the table
block I think).
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.
Ah, I didn't know we have defaultAttributes
. Thanks!
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'm happy to put the SSR endpoint into its own PR, can start on it now if it's wanted :)
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'm happy to put the SSR endpoint into its own PR, can start on it now if it's wanted :)
No rush, I think I'll leave the SSR part as it is now and we can improve it in a future PR. :)
Wow, that's quite a list! I think I'll try to keep this simple though and try to implement @jasmussen's design for now. We can always improve. :) |
Yeah a lot of options in there. That list is good to have as some of the options might be good to add at a later date. |
blocks/library/latest-posts/data.js
Outdated
* Returns a Promise with the latest posts or an error on failure. | ||
* | ||
* @param {Number} postsToShow | ||
* @returns {Object} |
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.
Instead of {Object}
this can be {wp.api.collections.Posts}
foreach( $recent_posts as $post ) { | ||
$post_permalink = get_permalink( $post['ID'] ); | ||
|
||
$posts_content .= "<li><a href='{$post_permalink}'>{$post['post_title']}</a></li>\n"; |
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.
Instead of $post['post_title']
this should use get_the_title( $post['ID'] )
so that filters apply.
index.php
Outdated
@@ -473,3 +476,8 @@ function the_gutenberg_project() { | |||
</div> | |||
<?php | |||
} | |||
|
|||
function gutenberg_load_blocks_server_side_redering() { |
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.
Typo s/redering/rendering/
<?php | ||
|
||
function gutenberg_block_core_latest_posts( $attributes ) { | ||
$postsToShow = 5; |
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.
Shouldn't this be $posts_to_show
?
497cee8
to
ce45015
Compare
After #849 which added a bunch of tests for block parsing and serialization, this PR should probably be rebased against |
In c9c7146, I added a basically blank full post content fixtures. since latest posts block returns
But that doesn't test anything (except the |
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.
Aside avoiding to store the request in the state, this looks solid to me 👍
Nice work! 🎉 |
$posts_to_show = 5; | ||
|
||
if ( array_key_exists( 'poststoshow', $attributes ) ) { | ||
$posts_to_show = $attributes['poststoshow']; |
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 there is no sanitization or validation of block attributes (yet), it should probably be done here, ensuring it is a number and that it is greater than 0, but less than (maybe) 100.
See also #886 (comment)
Thank you very much for all the great tips and reviews! @youknowriad @notnownikki @aduth @mtias @westonruter @jasmussen I've learned quite a lot here and refreshed my JS skills. :) |
Thank you @lamosty for working on this one. |
@@ -9,6 +9,8 @@ | |||
* @package gutenberg | |||
*/ | |||
|
|||
define( 'GUTENBERG__PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); |
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.
These define
s are duplicating code already in place elsewhere:
gutenberg/lib/client-assets.php
Lines 13 to 22 in 3f727da
/** | |
* Retrieves the root plugin path. | |
* | |
* @return string Root path to the gutenberg plugin. | |
* | |
* @since 0.1.0 | |
*/ | |
function gutenberg_dir_path() { | |
return plugin_dir_path( dirname( __FILE__ ) ); | |
} |
The GUTENBERG__
(double underscore) convention is unique to the constants introduced here; others in the codebase do not use this convention. It seems unnecessary to me.
I don't have a preference on whether this is done as a function or constants (the function is pretty fast), but it needs to be consistent in approach and naming.
Also, gutenberg.php
should contain the bare minimum necessary to initialize the plugin, because it is going to be rewritten during the build process. These defines should probably happen in a new lib/constants.php
or similar.
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.
Ah, I didn't notice that, my bad.
In a new PR, I'll fix those things.
Thanks!
function gutenberg_load_blocks_server_side_rendering() { | ||
require_once GUTENBERG__BLOCKS_LIBRARY_DIR . '/latest-posts/index.php'; | ||
} | ||
add_action( 'init', 'gutenberg_load_blocks_server_side_rendering' ); |
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 think there are a few other issues here, not least that npm run package-plugin
is currently broken because this file was not added to the plugin zip package. I'll open a PR to try to fix.
@mtias suggested to me to create a simple block to get latest posts with the WP REST API. It should also serve as an example for other developers so they can start experimenting with the API and create some cool blocks.
I've been studying Gutenberg (pretty good editor!) and come up with something really simple. It's still a work in progress since I want to fix a few things and maybe make it a bit better.
I'd like to also open a discussion about some of the things here:
rest-api-
since we could have another 'latest posts' block without using rest apirest-api
: are we planning to have more such components using rest api? If yes, I think it would be nice to give them their own categoryAsking for help: after saving a post with this latest posts block and then reloading the saved post, instead of having the block parsed and displayed as other blocks, it shows with the Gutenberg tags and HTML code. Can you spot what I'm doing wrong, please? It works fine when seeing the post on the front-end though.
Am I using the
attributes
ofregisterBlock
properly? I use them to store the latest posts retrieved from DB but don't define them inregisterBlock
.Thanks!
Nice to have/TODO