Creating a Server‑Side Gutenberg Block with @wordpress/create‑block
Build a Gutenberg block that renders on the server with @wordpress/create‑block. Follow this step‑by‑step guide to scaffold, configure, and validate a dynamic, PHP‑based block while keeping assets optimized.
11 Oct 2025, 13:35 UTC

Desired Outcome
Create a Gutenberg block that renders its output on the server using a PHP render_callback. This allows dynamic content, PHP logic, and caching while keeping the editor lightweight.
Prerequisites
- WordPress 5.0+ (PHP 7.4+ required for server‑side rendering)
- Node.js 12+ and npm installed to run the scaffolding tool
- Basic knowledge of Gutenberg block structure (
block.json,index.js,server.php) - File‑system access to a child theme or a custom plugin directory
Development Steps
- Scaffold the block
npx @wordpress/create-block my-server-blockThis creates a folder
my-server-blockwithblock.json,index.js,style.css, and aserver.phpplaceholder. - Configure block.json
{ "apiVersion": 2, "name": "my-plugin/server-block", "title": "Server Block", "category": "widgets", "icon": "smiley", "supports": { "html": false }, "editorScript": "file:./index.js", "editorStyle": "file:./style.css", "style": "file:./style.css", "renderCallback": "my_plugin_render_server_block" }Notice the
renderCallbackkey that points to a PHP function. Thesupports.html: falsesetting forces the block to render only in the editor canvas. - Add the PHP render callback
function my_plugin_render_server_block( $attributes ) { // Example: query latest posts $query = new WP_Query( [ 'posts_per_page' => 5, 'post_status' => 'publish', ] ); if ( ! $query->have_posts() ) { return 'No posts found.
'; } ob_start(); echo '- ';
while ( $query->have_posts() ) : $query->the_post();
printf( '
- %s ', esc_url( get_permalink() ), esc_html( get_the_title() ) ); endwhile; echo '
All output is escaped with
esc_urlandesc_htmlto avoid XSS. The function is hooked intoinitto register the block with WordPress. - Enqueue assets only where needed
function my_plugin_enqueue_block_assets() { wp_register_script( 'my-server-block-editor', plugins_url( 'index.js', __FILE__ ), [ 'wp-blocks', 'wp-element' ], filemtime( plugin_dir_path( __FILE__ ) . 'index.js' ) ); wp_register_style( 'my-server-block-editor', plugins_url( 'style.css', __FILE__ ), [ 'wp-edit-blocks' ], filemtime( plugin_dir_path( __FILE__ ) . 'style.css' ) ); wp_register_style( 'my-server-block', plugins_url( 'style.css', __FILE__ ), [], filemtime( plugin_dir_path( __FILE__ ) . 'style.css' ) ); } add_action( 'init', 'my_plugin_enqueue_block_assets' );Using
wp_register_*keeps handles unique and avoids conflicts with other plugins or themes.
Validation & Checks
- Editor preview: Open the block picker, insert the block, and confirm it renders a list of links in the editor canvas.
- Front‑end rendering: Publish a page containing the block and view the source. The
ul.server-block-listshould be present and populated. - Asset loading: In the browser console, verify that
index.jsloads only in the editor context and that no 404 errors appear forstyle.css. - Security audit: Inspect the output for raw PHP tags or unescaped content. The example uses
esc_urlandesc_htmlfor safety.
Recovery & Troubleshooting
- If the block does not appear, check that
block.jsonis syntactically correct. A malformed JSON will cause the editor to throw an error. - Missing
render_callbackwill result in an empty block on the front‑end. Ensure the PHP function is defined beforeregister_block_typeruns. - Asset 404s: confirm the
plugins_url()paths match the actual file locations. Usefilemtime()to bust cache during development. - Security warnings: if the block contains user‑supplied attributes, always sanitize them with the appropriate
sanitize_*functions before using them in the query or output. - Compatibility: if the site still uses the Classic Editor, the block will not be available. Switch to Gutenberg or install the Classic Editor compatibility plugin.
Conclusion
By following this guide you can build a robust, server‑side Gutenberg block that leverages PHP for dynamic content, keeps the editor lightweight, and benefits from WordPress caching mechanisms. Remember to test on a staging environment before deploying to production.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.