Efficient client data management for WordPress Plugins

Manipulating Client Data in highly interactive screens in WordPress (essentially the editor page in WordPress pre 5.0.0) is not the easiest task to do for plugin authors. As much as WordPress provides a large number of functions to access and manipulate data server side, it fails at providing a consistent way to access and manipulate data on the client.

And by client side data, I refer to things like:

  • What’s the current post content in the editor? How can I update it programmatically?
  • What’s the currently selected tags/categories?
  • Is a given metabox visible or not?
  • How can I be notified if an image block is inserted into the editor of  if the user switches the post status?

Client-data is also about accessing the WordPress REST API Data client-side:

  • How do I retrieve the latest posts?
  • How do I retrieve the current user’s object?
  • How can I create a new Category?

And it can also encompass plugins data. For example:

  • How do I store/update and access my own plugins client-side data?
  • How do I access and update the content of the Yoast metabox?
  • How do I retrieve the content of ACF metaboxes in a custom ACF plugin?

Often, to address these use-cases, we had to manipulate the DOM directly: Retrieve input’s values directly from the DOM or subscribe to DOM events to ensure we’re notified properly. This often leads to hacky code and code that breaks on WordPress/plugin updates because DOM access is not an official extensibility API.

Gutenberg JavaScript-heavy World

With Gutenberg’s release coming and as we add more and more JavaScript-powered UI to WordPress pages, the need for a consistent solution to manage client-side data is urgent, we can’t rely on DOM access anymore. To address this, Gutenberg introduces the Data Module.

Retrieving Data

One of the first use-cases of the Data module is to retrieve data defined by WordPress. To do so, you need to specify the namespace of the data to call a selector on this namespace.

Here’s how we retrieve the content of the post being edited in a Gutenberg Page.

var content = wp.data.select( 'core/editor' ).getEditedPostAttribute( 'content' );

Notice that the data module API is available in the wp.data global variable. The namespace to access the editor’s data is core/editor. And in each namespace, you can use a list of selectors.

A selector is a simple JavaScript function used to retrieve client-side data. In the example above, the selector being called is getEditedPostAttribute. This selector accepts an argument corresponding to the post attribute to retrieve. If we need to retrieve the title of the post instead of its content, we can do:

var title = wp.data.select( 'core/editor' ).getEditedPostAttribute( 'title' );

Protip: The list of the available selectors/namespaces is not documented properly on WordPress/Gutenberg yet. To see the full list of the core/editor‘s selectors, you can check the selectors file here.

You can also type wp.data.select( 'core/editor' ) in your browser’s console in any Gutenberg page to inspect the full list of the selectors available in this namespace.

Updating Data

So, selectors allow us to retrieve data and similarly, each namespace can defined actions to manipulate data (create/update/remove). For example, to update the title of the post being edited in Gutenberg, you can do:

wp.data.dispatch( 'core/editor' ).editPost( { title: 'My New Title' } );

An action is a function called to update the client-data defined in a given namespace.

Protip: To see the full list of the actions defined by the core/editor namespace, you can check the actions file here.
You can also type wp.data.dispatch(  'core/editor' ) in your browser’s console in any Gutenberg page to inspect the full list of the actions available in this namespace.

Register a custom “namespace”

Plugins can also manage their client state using the data module. To achieve this, they need to register their selectors/actions in addition to a reducer to hold and update the state.

A reducer is a function describing the shape of the initial state and how the state value evolves in response to dispatched actions.

Protip: The Data module is built on-top of the redux library. Learning redux is not required to use it but taking a look at the Redux Docs and its glossary should help you master the data module.

As an example, Let’s register a custom store to keep track of a list of todo items:

// This is the reducer
function reducer( state = [], action ) {
  if ( action.type === 'ADD_TODO' ) {
    return state.concat( [ action.todo ] );
  }

  return state;
}

// These are some selectors
function getTodos( state ) {
  return state;
}

function countTodos( state ) {
  return state.length;
}

// These are the actions
function addTodo( text, done = false ) {
  return {
    type: 'ADD_TODO',
    todo: { text: text, done: done };
  };
}

// Now let's register our custom namespace
var myNamespace = 'my-todos-plugin';
wp.data.registerStore( myNamespace, { 
  reducer: reducer,
  selectors: { getTodos: getTodos, countTodos: countTodos },
  actions: { addTodo: addTodo }
} );

Now that the custom namespace is registered, we can consume this in our code, the same way we did for the core/editor’s store.

// Add a new todo item
wp.data.dispatch( 'my-todos-plugin' ).addTodo( 'Finish writing a blog post about the data module', false );

// Retrieve the list of todos
var countTodos = wp.data.select( 'my-todos-plugin' ).countTodos();

React to changes in the state

Another important use-case for WordPress Plugins often is to react to changes happening in Core Data or other plugins. To address this, the Data Module provides a subscribe function. This function allows registering listeners that get called each time the state is changed.

In the following example, we trigger some random behavior each time a new block is added to the editor:

var currentCount = wp.data.select( 'core/editor' ).getBlockCount();
wp.data.subscribe( function() {
  var newCount = wp.data.select( 'core/editor' ).getBlockCount();
  var hasNewBlocks = newCount > currentCount;
  currentCount = newCount;

  if ( hasNewBlocks ) {
    // A new block has been added, do something
    console.log( 'The new block count is :' + newCount );
  }
} );

Declarative data needs

In addition to a new way to handle data client-side, as WordPress and plugins move towards more JavaScript UIs, the use of React and its wordpress abstraction wp.element is growing.

The WordPress element module allow you to describe UI using functions (or components) taking props and returning an HTML representation of the component.

A simple component displaying an h1 can be written like so:

// You can use JSX instead of wp.element.createElement
var el = wp.element.createElement;

function Title( props ) {
  return el( 'h1', {}, props.title );
}

Very often, these UI components need data to work properly. In the example above, the Title component expects a title prop to display its content in an h1.

Let’s say we’d like to display title component using the title of the post being edited in Gutenberg, we can use the select function explained previously and do something like that:

el( Title, { title: wp.data.select( 'core/editor' ).getEditedPostAttribute( 'title' ) } );

But this approach has some downsides. The value of the title prop can change over time and we’d like to refresh our component once that happens. This means we need to use wp.data.subscribe and rerender each time the title changes.

Fortunately, to avoid having to write this logic for ourselves, The data module provides what in the React community is referred to as a Higher-order component. A Higher-order component is a function that wraps another component and feeds it with props.

Here’s how you provide the title as a prop using the data module:

var EditorPostTitle = wp.data.withSelect( function( select ) {
  return {
    title: select( 'core/editor' ).getEditedPostAttribute( 'title' )
  };
} )( Title );

Now when we render the EditorPostTitle component, it will be automatically refreshed each time the title value changes.

el( EditorPostTitle );

Similarly to how the withSelect Higher-order component provides props to components using selectors, the data module also provides a withDispatch Higher-order component to feed components with actions.

Let’s write an input that can be used to change the value of the Gutenberg’s post title.

var el = wp.element.createElement;
var compose = wp.element.compose;

function TitleInput( props ) {
  return el( 'input', { 
    value: props.title,
    onChange: function( event ) {
      props.onChangeTitle( event.target.value );
    },
  } );
}

var PostTitleInput = compose( [
  wp.data.withSelect( function( select ) {
    return {
      title: select( 'core/editor' ).getEditedPostAttribute( 'title' )
    };
  } ),
  wp.data.withDispatch( function( dispatch ) {
    return {
      onChangeTitle: function( title ) {
        dispatch( 'core/editor' ).editPost( { title: title } );
      }
    };
  } )
] )( TitleInput );

Notice in this example how we’re composing both withSelect to retrieve the current title and withDispatch to provide a onChangeTitle callback the input Component can call to perform the updates.

Protip: Notice the compose function being used in the example, it’s an utility function that allow combining several Higher-order components together. 

Learn more about this functional programming pattern here

 Fetching WordPress Data

Until now, we were mostly dealing with synchronous selectors and actions but WordPress Data offers a way to handle asynchronous data as well.

To do so, we can attach a side-effect to each selector: A function that gets executed the first time a selector is called with a given set of arguments. This function can be responsible of performing an async API request and updating the state once the request succeeds. These side-effect functions are called resolvers.

For instance, we might be interested to fetch posts list to display them in a PostList component.

var el = wp.element.createElement;

// This a UI component showing a list of post titles given a posts prop.
function PostList( props ) {
  return props.posts.map( function( post ) {
    return el( 'div', { key: post.id }, post.title.rendered );
  } );
}

var RecentPostList = wp.data.withSelect( function( select ) {
  posts: select( 'core' ).getEntityRecords( 'postType', 'post' )
} );

Notice that in this example, the APIs being used are the same we were using before, but behind the scenes, a REST API is being executed the first time the getEntityRecords selector is called, to fetch the post list.

Here’s the exact flow:

  • The first time the getEntityRecords selector is called, the post list is empty. So the PostList component is rendered with an empty list of posts.
  • But behind the scenes the core data module also calls the resolver called getEntityRecords to perform the API Request for you. 
  • When the API Request resolves, the state is updated with the received posts. This will automatically retrigger a rerender, thanks to the way withSelect works.
  • The PostList gets rerendered with the update list of posts.  

Protip: If you’re interested in implementing this kind of side effects in your own plugins, make sure to take a look at the resolvers in the Data module docs.

WordPress Headless / Agnostic?

The Data Module is a generic JavaScript package to handle data, if you want to use in a WordPress client, or if you want to use any applications not related with WordPress, that’s also possible. Instead of using the wp.data global, you can just fetch the package from npm:

npm install @wordpress/data --save

Going further

The Data Module is still being enhanced, if you’re Interested in learning more about the Data Module or any other modules, make sure to join the #core-js channel of the WordPress Core slack and the weekly meetings happening each Tuesday at 13:00 UTC.

Thanks Andrew Duthie for the feedback.


This post is brought to you by the new Gutenberg Editor 


50 responses to “Efficient client data management for WordPress Plugins”

  1. Nice work Riad
    I’ve seen a video which talk about sending data between wordpress and block that could be useful to somebody
    https://www.youtube.com/watch?v=g-y3SXeooyo
    I’ve have a question to ask you about columns
    you use InnerBlocks layouts={ getColumnLayouts( columns ) }
    Is it possible to wrap each of this columns in a component ?
    Something that could be used like this
    InnerBlocks layouts={ [
    { name: ‘column-1’, label: ‘Column 1’, icon: ‘columns’ , wrapper:’Mycomponent’},
    { name: ‘column-2’, label: ‘Column 2’, icon: ‘columns’, wrapper:’Mycomponent’ },
    ] }

    • I know the columns block is being worked on to add wrappers, so yeah, keep an eye on the next releases.

  2. Hi, is there a way to get the attributes of a parent block within the edit function of an inner block?

    • You can probably traverse the block hierarchy using the data module’s selectors in the `core/editor` namespace. I don’t have the selectors in mind but you should be able to grab the current’s uid from the props and access its parent block instance.

  3. Hi Riad
    Great article as usual
    I have one question about withstate internal state. If we had three richtext in a component which can change. How concatanate the three in an internal state ?
    I had a use case which may be more explicit
    I found this in a card gutenberg addons : edit: withState( { editable: ‘content’, } )( edit ).
    https://gist.github.com/sylvaincordiere/3642a97146e0f07538138f639eefebe6#file-gistfile1-txt-L423
    I suppose that editable: ‘content’ is the internal state but is the ugb-card-heading content, ugb-tagline content or ugb-card-des content. There are three richtext and I can’t understand which one is the internal state.

  4. Thanks for this post Riad.
    I’ve take a look at latest post block in gutenberg.
    Is there a way to add load more button or pagination to it ?

    • It’s certainly possible but I don’t think that’ss going to be added to the core blocks because it mirrors the current widget. But it’s totally achievable in a custom block.

  5. Riad
    As usual you learn me a lot with few paragraph.
    Few month ago you talk about the possibility of including graphql in wordpress’s future core.
    Is there any news about that ?
    Because I struggle a lot with wp rest api and I think I’m not alone.
    A simple example :
    In WordPress 4.7 the filter argument for any post endpoint was removed so if I want to filter posts to show only post with featured image it become impossible without adding another plugin which add the filter.

    • Hi, Glad you’re learning stuff with my posts.

      So, yeah GraphQL is something we definitely keep an eye on, but at the moment Core is focused on Gutenberg. No real news in this area so but hopefully some exploration could start in the next months.

  6. Hi everybody
    Just a question to ask :
    Is there any asynchronous actions managed by gutenberg ?

  7. Hello, Riad
    Thank you for the great article, you saved my day and I mean it :).
    Note: At “React to changes in the state” example at the condition “if ( newCount > currentCount )” it must be “if ( hasNewBlocks ) {“

  8. Hi riad
    I’ve seen withAPIData is being deprecated : https://github.com/WordPress/gutenberg/issues/7390
    I’ve try to replace it in the latest post block without success:
    edit: withSelect( ( select ) => {
    return {
    posts: `/wp/v2/posts?per_page=3`
    };
    } )( ( { posts, className, isSelected, attributes, setAttributes } ) => {
    if ( ! posts.data ) {
    return (

    { __( ‘Loading Posts’ ) }

    );
    }
    if ( 0 === posts.data.length ) {
    return (
    { __( ‘No posts’ ) }
    );
    }
    return (

    setAttributes({ content })}
    placeholder={__(‘placeholder’)}
    />

    {posts.data.map(post => {
    return (


    {post.title.rendered}

    );
    })}

    );
    } ),
    Could you give an indication about using withSelect ?

    • you can use the `select( ‘core’ ).getPosts()` to retrieve the list of posts, but there’s no support for filtering/pagination yet, it will come soon enough.

  9. Thanks for your answer but I get TypeError: “e(…).getPosts is not a function”. I’ve search getPosts function in gutenberg doc without success. I’ve imported withSelect and select from wp.data though this was enough

    • Oh you’re right, the function is missing for some reason. You can do this as an alternative for now `wp.data.select(‘core’).getEntityRecords( ‘postType’, ‘post’ )`

  10. Hi Riad I ‘ve notice that you recently change withAPIData by withSelect in gutenberg code. With withAPIData we can use the rest api to filter post like posts: `/wp/v2/posts?per_page=3`. How could we do that with withSelect ?

  11. Hi Riad
    Thanks for your work here.
    I have a general question for gutenberg.
    Is it possible to extract data with it ?
    I mean upload a csv file from a block and use its data to populate a table.

    • Hi, this is not possible by default, but nothing stops you from building a CSV Table block, it seems easily doable and a great idea.

    • Gutenberg works on the frontend which means you can access WordPress Data through REST APIs. All the core REST APIs are available but if you want to do something not available in the Core’s REST API, you’d have to build your own endpoint.

  12. Hi Pal,

    I used your the function {wp.data.subscribe} to listen on changes of post format select, it’s working very well BUT it listen to any changes happened in the content so it triggered while writing the post content.

    I need to avoid listen on any other element except post format element, This is my code…

    wp.data.subscribe( function() {

    console.log( wp.data.select(‘core/editor’).getEditedPostAttribute(‘format’) );

    });

    Thanks for the great article.

  13. Hi, Riad! This is the best (and probably the only) article I’ve seen on the subject. Thank you very much! This was really helpful to get a better grasp of this new data module.

    I’ve got a question for you: is there a way to imitate the search feature that was available in withAPIData? Here’s an example of what was used before:

    `wp/v2/post/?search=test&per_page=20`

    • Hey Thanks Rodrigo.

      You can probably use the `getEntityRecords` selector to do that: `getEntityRecords( ‘postType’, ‘post’, { search: ‘test’, ‘per_page’: 20 } )`.

      • Thanks a lot, Riad! That’s exactly what I did 🙂 There is comment up there that gave me that idea. I saw that you could insert something like “{ per_page: 3 }” so I thought it was maybe possible to add the search part as a parameter in there too. And yes, it did work. I appreciate your help, my friend 🙂

        Extra questions: is there any way to retrieve the data of a single post using the WP Data Core if I’ve got it’s post ID at hand? What’s the difference between “getEntityRecords” and “getEntityRecords”?

      • Great. and yes, you can use `getEntityRecord` and pass the `id` directly as the last argument (instead of an object)

      • I started digging right after I wrote that last reply, and found I was able to do it just like you said, Riad 🙂

        getEntityRecord( ‘postType’, ‘post’, [id] )

        I was also able to retrieve a category name using something similar that I found by looking into the structure of the Gutenberg files (I should have done that days ago xP):

        getEntityRecord( ‘taxonomy’, ‘category’, [id] )

        But I haven’t been able to retrieve an image’s data. I’ve got the featured image id thanks to the ”featured_image” property retrieved by the post data, so I could use that.

        Any ideas? Is it possible at the moment?

      • Thank you so much, Riad! That did the trick 🙂 A post containing all this instructions and their parameters would be a good idea and really helpful too. It’s pretty weird I haven’t run into any regarding this particular subject.

      • Oh, yes! I’ve checked that info a million times, but you won’t be able to find things like that in those documentation. I’d love to help with something like that, but as you can see, my knowledge is not as good as it should be to be able to do that 🙁

  14. Yes, me again >.< I've been working in a way to retrieve a category name using it's ID with the method we've been discussing about. The problem is that it returns “undefined”, so I can't get information I need out of the “withSelect” call. If I console.log the results, I get two respondes (the second one shows moments after the first one): the first one is “undefined” and the second one is the info that I'm actually looking for. The problem is that it only seems to work when console.loging the results, if I return them, the second answer never shows.

    Any ideas why this is happening?

  15. Hi, Riad. Is there a way to create custom query? I has created custom table in Database for post rating, and now I need to get rating values in my custom block, how can I do this?

  16. Hello Riad,

    Your post evokes the getter/setter for core fields, eg the title, content.
    But how to update the terms of taxonomies associated with post ?

    I see how to recover them:
    var tagsTaxonomy = wp.data.select (‘core’). getTaxonomy (‘post_tag’);
    var tags = tagsTaxonomy && wp.data.select (‘core / editor’). getEditedPostAttribute (tagsTaxonomy.rest_base);

    But I do not see how to update them?
    This does not seem to work?

    wp.data.dispatch (‘core / editor’). editPost (tagsTaxonomy.rest_base, tags);

    An idea ?

      • Hello Riad,

        Thanks for your reply. Thats works fine.

        The problems continue (I’m trying to make my open-source plugin “Simple Tags” compatible with Gutenberg … a bit late)
        I have a tag with the name value : “Test”

        When i try to get it with :

        var results = wp.data.select(‘core’).getEntityRecords(‘taxonomy’, ‘tags’, {search: ‘Test’, hide_empty: false})
        console.log(results)

        I have no result, only a empty array.
        My browser console show nothing, no request to the rest API :/

      • The first time you call an async selector, you won’t have the results right away, you can subscribe to the store `.subscribe` or use `withSelect` that takes care of all these reactiveness for you.

  17. Hi Riad,

    Thanks for the great info

    I’m struggling to set the post content like the title

    wp.data.dispatch( ‘core/editor’ ).editPost( { content: ‘The new content’ } );

    It changes it in the code editor but the blocks stays intact. Is there any way to update the blocks according to the HTML in JS?

  18. Just wanted to say that this has been the most helpful post for Gutenberg development that I’ve seen to date. I keep coming back to it because of the great examples and detailed descriptions. Thanks a ton for sharing.

  19. One challenge at this point is determining how to run JavaScript you want to run only once when the block editor has loaded. Using jQuery( document ).ready() doesn’t always work and I can’t seem to find any actions to hook into for when the block editor has finished loading. Any suggestions?

Leave a Reply to Riad BenguellaCancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Discover more from Riad Benguella

Subscribe now to keep reading and get access to the full archive.

Continue reading