Contents
Introduction
This tutorial explains, in exhaustive detail, how to consume wp.datas select and dispatch APIs inside WordPress blocks using modern patterns (React hooks: useSelect, useDispatch), classic programmatic access (wp.data.select / wp.data.dispatch), and HOCs (withSelect, withDispatch). It covers common store names, frequently used selectors and actions, best practices, performance tips, examples for reading/writing post data and block attributes, and how to coordinate asynchronous entity fetching when building editor UI.
Concepts and terminology
- wp.data — central data store mechanism in Gutenberg. Exposes runtime-selectors and -actions.
- select — synchronous read-only accessors into a registered store (select(storeName).selectorName(…)). Use to read editor state.
- dispatch — invoke actions exposed by a store (dispatch(storeName).actionName(…)). Use to update state, insert blocks, edit post meta, etc.
- useSelect / useDispatch — React hooks provided by @wordpress/data for consuming select/dispatch inside functional components and blocks. They provide automatic subscription/unsubscription and integrate with component re-render lifecycle.
- withSelect / withDispatch — higher-order components (HOCs) for class components or legacy code to map selectors/actions to props.
- Resolvers — some selectors (getEntityRecords, for example) automatically trigger network requests when used inside useSelect or withSelect, allowing components to request entities on demand.
Common stores, selectors and actions
These are the most commonly used stores when writing blocks that interact with the editor or manage content:
store | typical selectors | typical actions |
core/editor | getCurrentPostId, getCurrentPostType, getEditedPostAttribute(titlemetacontent), getEditedPost | editPost, savePost (depends on WP version) |
core/block-editor | getBlocks, getBlock, getSelectedBlockClientId, getBlockOrder, getBlockIndex | insertBlocks, updateBlockAttributes, removeBlocks, selectBlock, clearSelectedBlock |
core | getEntityRecords (postType), getEntityRecord (single), getAuthors, getSettings | Some entity actions (resolvers for fetching) — use dispatch(core) utilities |
Note: API names may vary slightly across WordPress versions. The examples below use the stable, widely-supported selectors/actions such as getEditedPostAttribute, getEntityRecords, updateBlockAttributes, insertBlocks, and editPost.
Using useSelect and useDispatch (recommended for blocks)
When building block edit components (functional components), prefer useSelect/useDispatch. They provide clear separation of reads and writes and automatically subscribe the component to data changes.
Import examples (ESNext)
import { useSelect, useDispatch } from @wordpress/data import { createBlock } from @wordpress/blocks
Example: reading the current post title and edited content
import { useSelect } from @wordpress/data import { PlainText } from @wordpress/block-editor function MyBlockEdit() { const title = useSelect( (select) => { return select(core/editor).getEditedPostAttribute(title) }, [] ) // empty deps array: run once on mount and subscribe to changes const content = useSelect( (select) => { return select(core/editor).getEditedPostAttribute(content) }, [] ) return () }Post title: { title }
{} } />
Example: updating a block attribute using useDispatch
import { useDispatch } from @wordpress/data import { Button } from @wordpress/components function UpdateBlockAttributesButton( { clientId } ) { const { updateBlockAttributes, selectBlock } = useDispatch( core/block-editor ) const onClick = () => { // set an attribute on the block updateBlockAttributes( clientId, { myCustomAttribute: value } ) // optionally select it after update selectBlock( clientId ) } return }
Example: inserting a new core/paragraph block programmatically
import { useDispatch } from @wordpress/data import { createBlock } from @wordpress/blocks function InsertParagraphButton() { const { insertBlocks } = useDispatch( core/block-editor ) const addParagraph = () => { const paragraph = createBlock( core/paragraph, { content: Inserted by code } ) insertBlocks( paragraph ) // appends by default } return }
Using the global wp.data.select and wp.data.dispatch (legacy or non-React code)
If youre writing plain JavaScript (no React), or you need to read/write from a script outside a block edit React component, use the global APIs wp.data.select and wp.data.dispatch directly. Remember to manage subscriptions manually when needed.
Read some editor state
// read current post id const postId = wp.data.select( core/editor ).getCurrentPostId() // read edited post attribute (meta, title, content) const editedTitle = wp.data.select( core/editor ).getEditedPostAttribute( title ) const editedMeta = wp.data.select( core/editor ).getEditedPostAttribute( meta )
Dispatch an action
// update post meta using core/editors editPost action wp.data.dispatch( core/editor ).editPost({ meta: { my_plugin_meta_key: new-value } })
Subscribe to store changes
// subscribe returns an unsubscribe function const unsubscribe = wp.data.subscribe( () => { const title = wp.data.select( core/editor ).getEditedPostAttribute( title ) console.log( Title changed:, title ) }) // Later when you dont need it: unsubscribe()
Using withSelect and withDispatch HOCs
For class components or older code that prefers HOCs, withSelect and withDispatch map selectors and actions to props. Use compose to combine them cleanly.
import { compose } from @wordpress/compose import { withSelect, withDispatch } from @wordpress/data class MyLegacyComponent extends React.Component { render() { const { currentPostId, blocks, updateBlockAttributes } = this.props // render UI... returnPost ID: { currentPostId }, Blocks: { blocks.length }} } export default compose( withSelect( (select) => { return { currentPostId: select(core/editor).getCurrentPostId(), blocks: select(core/block-editor).getBlocks() } }), withDispatch( (dispatch) => { return { updateBlockAttributes: (clientId, attrs) => { dispatch(core/block-editor).updateBlockAttributes(clientId, attrs) } } }) )( MyLegacyComponent )
Working with entities (posts, terms, users)
Use the core stores entity selectors to read lists or single records. When used inside useSelect or withSelect, resolvers run automatically to fetch entities from the REST API if they are not loaded yet.
Example: fetch latest 5 posts
import { useSelect } from @wordpress/data function LatestPosts() { const posts = useSelect( (select) => { return select(core).getEntityRecords( postType, post, { per_page: 5 } ) }, [] ) if ( posts === undefined ) { returnLoading…
} if ( posts.length === 0 ) { returnNo posts found.
} return (
-
{ posts.map( p =>
- { p.title p.title.rendered } ) }
Note: getEntityRecords returns undefined when still resolving check for undefined to show a loading state. The resolver will dispatch the network request automatically when used within useSelect/withSelect.
Common integration patterns and examples
1) Read show selected block details
import { useSelect } from @wordpress/data function SelectedBlockInfo() { const selectedClientId = useSelect( (select) => { return select(core/block-editor).getSelectedBlockClientId() }, [] ) const block = useSelect( (select) => { return selectedClientId ? select(core/block-editor).getBlock( selectedClientId ) : null }, [ selectedClientId ] ) if ( ! block ) { returnNo block selected} return (Selected block: { block.name }
{ JSON.stringify(block.attributes, null, 2) })
}2) Update selected block attribute
import { useSelect, useDispatch } from @wordpress/data function ToggleBlockFlag() { const selectedClientId = useSelect( (select) => select(core/block-editor).getSelectedBlockClientId(), [] ) const { updateBlockAttributes } = useDispatch( core/block-editor ) const toggle = () => { if ( ! selectedClientId ) return const block = wp.data.select(core/block-editor).getBlock( selectedClientId ) const current = block.attributes.myFlag false updateBlockAttributes( selectedClientId, { myFlag: ! current } ) } return }3) Insert blocks at a particular index
import { useDispatch } from @wordpress/data import { createBlock } from @wordpress/blocks function InsertAtTopButton() { const { insertBlocks } = useDispatch( core/block-editor ) const insertAtTop = () => { const block = createBlock( core/paragraph, { content: Top inserted paragraph } ) insertBlocks( block, 0 ) // insert at index 0 } return }Edge cases, debugging and common pitfalls
- Undefined selectors: Some selectors return undefined while their resolvers run. Check for undefined before rendering lists.
- Store names: Use the exact store name (e.g., core/block-editor, not editor). If in doubt, inspect wp.data.stores in the console to see registered stores.
- Action names: Some actions and selectors differ by WP version. When an action isnt found, check console errors and WordPress developer docs or inspect store.selectors/ store.actions in the console.
- Component re-renders: useSelect subscribes to changes and re-runs when dependencies or store state change. Keep selectors minimal to avoid unnecessary re-renders.
- Mutable objects: Do not mutate objects returned by select treat them as read-only. Use dispatch actions to update state.
Performance tips
- Keep useSelect selectors as narrow as possible. Selecting a large part of the state will cause more frequent re-renders.
- Use the dependency array (second argument) for useSelect to control when the selector callback should change identity.
- Memoize derived values (useMemo inside components) if required, but prefer selecting only the raw data you need.
- Avoid repeatedly calling createBlock/insertBlocks inside renders — trigger actions in event handlers.
- Use withSelect/withDispatch if you must: it helps keep pure presentational components and separate data logic, but hooks are generally simpler.
Advanced topics
Checking if entity records are loaded
Some apps want to show a loader until an entity is available. A typical pattern:
import { useSelect } from @wordpress/data function PostsList() { const posts = useSelect( (select) => select(core).getEntityRecords(postType, post, { per_page: 5 }), [] ) if ( posts === undefined ) { returnLoading posts…} return (
- { posts.map( p =>
- { p.title.rendered } ) }
Resolving race conditions
Because selectors may cause network requests, avoid calling the dispatch action that triggers a resolver repeatedly in quick succession. Use debouncing if you trigger edits on each keystroke and rely on a resolver to fetch. For example, if your code calls an action that triggers an entity fetch, debounce the trigger to avoid flooding the REST API.
Using wp.data.select inside event callbacks
Remember the returned object from select may be stale if stored in an outer closure. Re-call wp.data.select(…) inside the callback for up-to-date values.
document.getElementById(my-button).addEventListener(click, () => { const currentTitle = wp.data.select(core/editor).getEditedPostAttribute(title) console.log(Title at click time:, currentTitle) })
Practical full example: a block that toggles a post meta boolean
This example demonstrates a block edit component which:
- Reads a post meta key via core/editor
- Shows its current state
- Updates meta using dispatch(core/editor).editPost
import { useSelect, useDispatch } from @wordpress/data import { ToggleControl } from @wordpress/components function PostMetaToggle() { const metaKey = my_plugin_toggle // Read the meta (meta object or undefined) const meta = useSelect( (select) => { return select(core/editor).getEditedPostAttribute(meta) }, [] ) const toggleValue = meta ? !! meta[ metaKey ] : false const { editPost } = useDispatch( core/editor ) const onChange = (value) => { editPost({ meta: { [ metaKey ]: value } }) } return () }
How to debug selectors and actions
- Open browser console and inspect wp.data.stores to find stores and their selectors/actions.
- Call wp.data.select(storeName).someSelector in the console to see available selectors and return values.
- Call Object.keys(wp.data.select(storeName)) to list selectors. Likewise Object.keys(wp.data.dispatch(storeName)) for actions.
- Use console.log within useSelect to inspect values avoid logging in renders that cause clutter — use effect hooks if needed.
Quick reference cheat sheet
Read | const value = select(storeName).selectorName(…) |
Dispatch | dispatch(storeName).actionName(…) |
Hook read | const v = useSelect( select => select(storeName).selector(), [deps] ) |
Hook write | const { action } = useDispatch(storeName) action(…) |
Global | wp.data.select(…) and wp.data.dispatch(…) |
Further reading
Final notes
This article provided comprehensive, practical guidance and many ready-to-use examples for consuming wp.data select and dispatch inside blocks using both modern hooks and legacy patterns. Use hooks for new block development, check return values for undefined when selectors resolve asynchronously, and keep selectors focused to avoid performance overhead. When debugging, inspect wp.data.stores in the console to see what selectors and actions are available in your WordPress version.
|
Acepto donaciones de BAT's mediante el navegador Brave 🙂 |