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 dynamic block documentation #4067
Changes from 5 commits
78ed19f
b7c7890
9be22a8
e1707a4
a5749c1
9af5e8e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
# Creating dynamic blocks | ||
|
||
It is possible to create dynamic blocks. These are blocks that can change their content even if the post is not saved. One example from WordPress itself is the latest posts block. This block will update everywhere it is used when a new post is published. | ||
|
||
The following code example shows how to create the latest post block dynamic block. | ||
|
||
{% codetabs %} | ||
{% ES5 %} | ||
```js | ||
// myblock.js | ||
|
||
var el = wp.element.createElement, | ||
registerBlockType = wp.blocks.registerBlockType, | ||
withAPIData = wp.components.withAPIData; | ||
|
||
registerBlockType( 'my-plugin/latest-post', { | ||
title: 'Latest Post', | ||
icon: 'megaphone', | ||
category: 'widgets', | ||
|
||
edit: withAPIData( function() { | ||
return { | ||
posts: '/wp/v2/posts?per_page=1' | ||
}; | ||
} )( function( props ) { | ||
if ( ! props.posts.data ) { | ||
return "loading !"; | ||
} | ||
if ( props.posts.data.length === 0 ) { | ||
return "No posts"; | ||
} | ||
var className = props.className; | ||
var post = props.posts.data[ 0 ]; | ||
|
||
return el( | ||
'a', | ||
{ className: className, href: post.link }, | ||
post.title.rendered | ||
); | ||
} ), | ||
|
||
save: function() { | ||
// Rendering in PHP | ||
return null; | ||
}, | ||
} ); | ||
``` | ||
{% ESNext %} | ||
```js | ||
// myblock.js | ||
|
||
const { el } = wp.element; | ||
const { registerBlockType } = wp.blocks; | ||
const { withAPIData } = wp.components; | ||
|
||
registerBlockType( 'my-plugin/latest-post', { | ||
title: 'Latest Post', | ||
icon: 'megaphone', | ||
category: 'widgets', | ||
|
||
edit: withAPIData( () => { | ||
return { | ||
posts: '/wp/v2/posts?per_page=1' | ||
}; | ||
} )( ( { posts, className } ) => { | ||
if ( ! posts.data ) { | ||
return "loading !"; | ||
} | ||
if ( posts.data.length === 0 ) { | ||
return "No posts"; | ||
} | ||
var post = posts.data[ 0 ]; | ||
|
||
return <a className={ className } href={ post.link }> | ||
{ post.title.rendered } | ||
</a>; | ||
} ), | ||
|
||
save() { | ||
// Rendering in PHP | ||
return null; | ||
}, | ||
} ); | ||
``` | ||
{% end %} | ||
|
||
Because it is a dynamic block it also needs a server component. The rendering can be added using the `render_callback` property when using the `register_block_type` function. | ||
|
||
```php | ||
<?php | ||
// block.php | ||
|
||
function my_plugin_render_block_latest_post( $attribites ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo: Should we omit this if it's an unused variable? |
||
$recent_posts = wp_get_recent_posts( array( | ||
'numberposts' => 1, | ||
'post_status' => 'publish', | ||
) ); | ||
if ( count( $recent_posts ) === 0 ) { | ||
return 'No posts'; | ||
} | ||
$post = $recent_posts[ 0 ]; | ||
$post_id = $post['ID']; | ||
return sprintf( | ||
'<a class="wp-block-my-plugin-latest-post" href="%1$s">%2$s</a>', | ||
esc_url( get_permalink( $post_id ) ), | ||
esc_html( get_the_title( $post_id ) ) | ||
); | ||
} | ||
|
||
register_block_type( 'my-plugin/latest-post', array( | ||
'render_callback' => 'my_plugin_render_block_latest_post', | ||
) ); | ||
``` | ||
|
||
There are a few things to notice: | ||
|
||
* The edit function still shows a representation of the block in the editor's context (this could be very different from the rendered version, it's up to the block's author) | ||
* The save function just returns null because the rendering is performed server-side. | ||
* The server-side rendering is a function taking the block attributes as an argument and returning the markup (quite similar to shortcodes) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to be clearer about how attributes are also defined on the server for this to work correctly? Though in this case there are no attributes for this block. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know, I've copied these points from Riad's post. Could we merge this and iterate on it further? |
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.
Per consistency with other docs, should we include ES5 and ESNext varieties here?