Use page Title in Gutenberg custom banner block
Gutenberg stores the current editor state using wp.data, which is an abstraction over Redux. To get the title (or 100+ other values), we need to query the core/editor
data store. Gutenberg makes it simple to retrieve post attributes with getEditedPostAttribute.
Once we know where to look, getting the title is simple:
const { select } = wp.data;
const title = select("core/editor").getEditedPostAttribute( 'title' );
That works, but it's not responsive. When the post title changes, title
won't reflect the new value. That's kind of a let down.
To reflect changes to the editor title, we need to listen for changes to the core/editor
data store. There are a few ways to do this.
One solution is to define a simple change handler function and subscribe it to data store updates:
const { select } = wp.data;
function logTitle() {
const title = select("core/editor").getEditedPostAttribute( 'title' );
console.log("Editor Title:", title);
}
subscribe(logTitle);
That will fire when any wp.data
store value is updated -- which happens a lot.
What seems to be the Gutenberg-sanctioned way of including data-store values is to use a higher-order component to include the value directly:
const GetTitle = props => <div>{props.title}</div>;
const selectTitle = withSelect(select => ({
title: select("core/editor").getEditedPostAttribute( 'title' )
}));
const PostTitle = selectTitle(GetTitle);
Then in the block's output, include a <PostTitle />
jsx tag. That's a lot cleaner than nested callbacks or another change handler.
Higher-order components can be difficult to follow. The short explanation is that they wrap a existing component, generate some data, then return a copy of the component with the new data passed as props. This separates logic from presentation and helps with maintainability.
GetTitle
is simple enough, it's just a small component that takes in a props
object with a title key and spits out some html.
withSelect
is a function constructor or decorator. It accepts a function argument, and returns a new function which expects a component. Normally the returned function is invoked immediately (sort of an IIFE) but I stored it in the selectTitle
variable for clarity. The new function generates an object containing the title, this object will be passed as props to any components passed to withSelect
. Through some magic this will be called whenever the data store is updated.
In the end, PostTitle
contains the function result of selectTitle
which is a component pre-populated with the the generated props. This component can then be placed into our markup using a <PostTitle />
tag. Whenever the editor data-store is updated, the higher-level component will reflect the new data.