Integrating with Gutenberg Blocks: Dynamic Data Fetching
Learn to build dynamic Gutenberg blocks that fetch live Knowledge Base data via the REST API. Master the @wordpress/data store integration for your blocks.
Previously in this course, we built a robust custom hook for API logic to streamline our React admin dashboard. Now, we're taking that knowledge into the content editor. In this lesson, we will build a dynamic block that fetches and displays our Knowledge Base entries directly inside the Gutenberg editor, allowing users to select and embed content without leaving the post-editing screen.
Understanding Dynamic Blocks
A dynamic block is a block that renders its output on the server side using PHP, rather than just saving static HTML to the post_content. This is crucial for our Knowledge Base plugin because if we update a KB entry in our admin dashboard, we want that change to reflect immediately across all posts where the block is used.
Instead of saving the rendered HTML, we save a "placeholder" (the block attributes) and let the render_callback handle the database query and output generation.
Integrating with Gutenberg Blocks via the REST API
To make this work, we need to bridge our existing API infrastructure with the Block Editor's data store. We will use the @wordpress/data package, which we explored when registering a custom data store, to fetch our KB entries.
1. Registering the Dynamic Block
First, we define our block in PHP. We need to register the block type and provide a render_callback function.
PHP#6A9955">// kb-plugin/blocks/kb-display/index.php register_block_type( 'kb-plugin/kb-display', array( 'attributes' => array( 'kbId' => array( 'type' => 'integer', ), ), 'render_callback' => 'render_kb_display_block', ) ); function render_kb_display_block( $attributes ) { if ( empty( $attributes['kbId'] ) ) { return '<p>Please select a Knowledge Base entry.</p>'; } #6A9955">// Fetch the specific KB entry using our established service layer $post = get_post( $attributes['kbId'] ); return sprintf( '<div class="kb-entry"><h2>%s</h2>%s</div>', esc_html( $post->post_title ), apply_filters( 'the_content', $post->post_content ) ); }
2. Fetching Data in the Editor
In our JavaScript block code, we need to display a dropdown or list of available KB entries. We'll use useSelect to query our custom data store.
JAVASCRIPT// kb-plugin/src/blocks/kb-display/edit.js import { useSelect } from CE9178">'@wordpress/data'; import { SelectControl } from CE9178">'@wordpress/components'; export default function Edit( { attributes, setAttributes } ) { const { kbId } = attributes; const { kbEntries, isResolving } = useSelect( ( select ) => { const store = select( CE9178">'kb-plugin/data' ); return { kbEntries: store.getEntries(), isResolving: store.isResolving( CE9178">'getEntries' ), }; }, [] ); if ( isResolving ) return <p>Loading entries...</p>; return ( <SelectControl label="Select KB Entry" value={ kbId } options={ [ { label: CE9178">'Select one...', value: 0 }, ...kbEntries.map( ( e ) => ( { label: e.title.rendered, value: e.id } ) ), ] } onChange={ ( val ) => setAttributes( { kbId: parseInt( val ) } ) } /> ); }
Hands-on Exercise
- Create a new directory
blocks/kb-displayin your plugin. - Register the block in your main plugin file using
register_block_type. - Implement the
edit.jsfile provided above. - Ensure your
package.jsonis configured to build the new block assets using@wordpress/scripts. - Run
npm run buildand verify that the block appears in the editor and successfully populates theSelectControlwith your KB entries.
Common Pitfalls
- Forgetting to define attributes: If you don't define your
kbIdattribute in the PHP registration, the editor won't know how to save the block state to the database. - Mixing up client/server logic: Remember that the
edit.jsruns in the browser, while therender_callbackruns on the server. Do not try to callget_posts()inside youredit.jsfile; always use the REST API via your store. - Stale Data: Since we are using our custom data store, ensure your resolvers are correctly handling the cache. If you've been optimizing API response times, ensure that invalidating the cache doesn't break the block's ability to fetch the initial list.
Recap
We've successfully bridged the gap between our React admin dashboard and the Gutenberg editor. By creating a dynamic block, we keep our content presentation decoupled from the block's storage. We've utilized our existing REST API and data store to power the block's UI, ensuring a consistent developer experience across the entire plugin.
Up next: We will address potential data conflicts by implementing optimistic locking to ensure that multiple editors don't overwrite each other's changes.
Work with me

Headless WordPress + Next.js Frontend Development
Keep WordPress for content, get a lightning-fast Next.js frontend. The best of both worlds — familiar editing, modern speed.

Custom WordPress Plugin Development
Custom WordPress & WooCommerce plugins built to standard — by the developer behind a plugin with 5,000+ active installs and a SaaS with 10,000+ users.