动态区块是在前端渲染时动态构建结构和内容的区块,适用于内容需实时更新或代码变更需立即生效的场景。通过服务器端渲染回调函数,开发者可以灵活控制区块的显示逻辑,避免编辑器验证问题。
import { registerBlockType } from '@wordpress/blocks';
import { useSelect } from '@wordpress/data';
import { useBlockProps } from '@wordpress/block-editor';
registerBlockType( 'gutenberg-examples/example-dynamic', {
apiVersion: 3,
title: 'Example: last post',
icon: 'megaphone',
category: 'widgets',
edit: () => {
const blockProps = useBlockProps();
const posts = useSelect( ( select ) => {
return select( 'core' ).getEntityRecords( 'postType', 'post' );
}, [] );
return (
<div { ...blockProps }>
{ ! posts && 'Loading' }
{ posts && posts.length === 0 && 'No Posts' }
{ posts && posts.length > 0 && (
<a href={ posts[ 0 ].link }>
{ posts[ 0 ].title.rendered }
</a>
) }
</div>
);
},
} );Dynamic blocks are blocks that build their structure and content on the fly when the block is rendered on the front end.
There are two primary uses for dynamic blocks:
For many dynamic blocks, the save callback function should be returned as null, which tells the editor to save only the block attributes to the database. These attributes are then passed into the server-side rendering callback, so you can decide how to display the block on the front end of your site. When you return null, the editor will skip the block markup validation process, avoiding issues with frequently-changing markup.
If you are using InnerBlocks in a dynamic block you will need to save the InnerBlocks in the save callback function using <InnerBlocks.Content/>
You can also save an HTML representation of the block. If you provide a server-side rendering callback, this HTML will be replaced with the output of your callback, but will be rendered if your block is deactivated or your render callback is removed.
Block attributes can be used for any content or setting you want to save for that block. In the first example above, with the latest posts block, the number of latest posts you want to show could be saved as an attribute. Or in the second example, attributes can be used for each piece of content you want to show in the front end – such as heading text, paragraph text, an image, a URL, etc.
The following code example shows how to create a dynamic block that shows only the last post as a link.
import { registerBlockType } from '@wordpress/blocks';
import { useSelect } from '@wordpress/data';
import { useBlockProps } from '@wordpress/block-editor';
registerBlockType( 'gutenberg-examples/example-dynamic', {
apiVersion: 3,
title: 'Example: last post',
icon: 'megaphone',
category: 'widgets',
edit: () => {
const blockProps = useBlockProps();
const posts = useSelect( ( select ) => {
return select( 'core' ).getEntityRecords( 'postType', 'post' );
}, [] );
return (
<div { ...blockProps }>
{ ! posts && 'Loading' }
{ posts && posts.length === 0 && 'No Posts' }
{ posts && posts.length > 0 && (
<a href={ posts[ 0 ].link }>
{ posts[ 0 ].title.rendered }
</a>
) }
</div>
);
},
} );
Because it is a dynamic block it doesn’t need to override the default save implementation on the client. Instead, it needs a server component. The contents in the front of your site depend on the function called by the render_callback property of register_block_type.
<?php
/**
* Plugin Name: Gutenberg examples dynamic
*/
function gutenberg_examples_dynamic_render_callback( $block_attributes, $content ) {
$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 ) )
);
}
function gutenberg_examples_dynamic() {
// automatically load dependencies and version
$asset_file = include( plugin_dir_path( __FILE__ ) . 'build/index.asset.php');
wp_register_script(
'gutenberg-examples-dynamic',
plugins_url( 'build/block.js', __FILE__ ),
$asset_file['dependencies'],
$asset_file['version']
);
register_block_type( 'gutenberg-examples/example-dynamic', array(
'api_version' => 3,
'editor_script' => 'gutenberg-examples-dynamic',
'render_callback' => 'gutenberg_examples_dynamic_render_callback'
) );
}
add_action( 'init', 'gutenberg_examples_dynamic' );
There are a few things to notice:
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)save function just returns null because the rendering is performed server-side.Note : For common customization settings including color, border, spacing customization and more, we will see on the next chapter how you can rely on block supports to provide such functionality in an efficient way.
Gutenberg 2.8 added the <ServerSideRender> block which enables rendering to take place on the server using PHP rather than in JavaScript.
Server-side render is meant as a fallback; client-side rendering in JavaScript is always preferred (client rendering is faster and allows better editor manipulation).
import { registerBlockType } from '@wordpress/blocks';
import ServerSideRender from '@wordpress/server-side-render';
import { useBlockProps } from '@wordpress/block-editor';
registerBlockType( 'gutenberg-examples/example-dynamic', {
apiVersion: 3,
title: 'Example: last post',
icon: 'megaphone',
category: 'widgets',
edit: function ( props ) {
const blockProps = useBlockProps();
return (
<div { ...blockProps }>
<ServerSideRender
block="gutenberg-examples/example-dynamic"
attributes={ props.attributes }
/>
</div>
);
},
} );
Note that this code uses the wp-server-side-render package but not wp-data. Make sure to update the dependencies in the PHP code. You can use wp-scripts to automatically build dependencies (see the block-development-examples repo for PHP code setup).