Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use page Title in Gutenberg custom banner block

I have created a custom banner image block for Gutenberg, which works great, but I want to know if it is possible to use the page title as the current banner text placeholder until it has been edited?

enter image description here

My Edit function is

 return [
            el('div', {className:'header-banner'},
                el(
                    element.Fragment,
                    null,
                    controls,
                    el( "div",{
                        className: 'banner-image',
                        style: { backgroundImage: 'url('+attributes.mediaURL+')' }
                    },
                    attributes.title || isSelected ?  el(RichText, {
                            key: 'editable',
                            tagName: "h1",
                            className: "banner-title",
                            //Can i add the page title in here if it is avaiable??
                            //placeholder: i18n.__('Write title…'),
                            value: attributes.title,
                            onChange: function onChange(value) {
                                return props.setAttributes({ title: value });
                            },
                            inlineToolbar: true
                        }) : null 

                    )
                )
            )//header-banner
        ];    

Thanks :)

like image 471
Jim-miraidev Avatar asked Aug 03 '18 13:08

Jim-miraidev


2 Answers

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.

like image 180
joemaller Avatar answered Sep 28 '22 02:09

joemaller


@joemaller thanks for the helpful response.

Here's an example that demonstrates using withSelect() to wrap a component defined via the edit property of the block configuration object passed to registerBlockType().

The component is passed the title via props.

If the user edits the post/page title, the component is re-rendered with the new title because its props will have changed. This enables it to update in "real time".

import { withSelect } from '@wordpress/data'

...

edit: withSelect(
  ( select ) => {
    return {
      title: select( 'core/editor' ).getEditedPostAttribute( 'title' ),
    }
  } )( props => {
    return (
      <div>{ props.title }</div>
    )
} ),
like image 27
firxworx Avatar answered Sep 28 '22 00:09

firxworx