Gutenberg: t.subscribe

Created on 23 Nov 2018  Â·  15Comments  Â·  Source: WordPress/gutenberg

Describe the bug
select("core/editor").getCurrentPost().title produces a "t.subscribe is not a function" error on post reload.

To Reproduce
I made a tiny higher order component called PostTitle:

const GetTitle = props => <div>{props.title}</div>;
const selectTitle = withSelect(select => ({
  title: select("core/editor").getCurrentPost().title
}));
const PostTitle = selectTitle(GetTitle); 

When I used the element , it displayed the current post title on initial load and after saving, but when l I reloaded the page I got "t.subscribe is not a function" from wp.data.

Expected behavior
select("core/editor").getCurrentPost().title always gets the current post title.

Needs Testing [Type] Help Request

Most helpful comment

@SL0TR I found my issue to be in the save method not using RichText correctly.

save({attributes}) {
    const {content, alignment} = attributes;

    return (
        <div className="container">
            <div className="row">
                <div className="col">
                                            {/* BAD */}
                    {/*<RichText
                        tagName="div"
                        value={content}
                        style={{textAlign: alignment}}
                    />*/}
                                              {/* GOOD */}
                                              <RichText.Content
                        tagName="div"
                        value={content}
                        style={{textAlign: alignment}}
                    />
                </div>
            </div>
        </div>
    );
}

All 15 comments

Do you have wp-editor as a dependency of your custom script ?

Thanks so much. Turns out I forgot to add the InnerBlocks dependency. That seems to solve the problem, although I haven't really tested further.

Nope that's not the problem. I'm still getting teh same error.

Here's the entire index.js for my block. All I really want to do is move the post title under an initial image block...

const { registerBlockType } = wp.blocks;
const { InnerBlocks, RichText } = wp.editor
const { withSelect } = wp.data;

const ALLOWED_BLOCKS = [ 'core/paragraph' ];
const TEMPLATE = [ 
    [ 'core/paragraph', {placeholder: 'Objektbeschrieb'} ],
];

const GetTitle = props => <div>{props.title}</div>;
const selectTitle = withSelect(select => ({
  title: select("core/editor").getCurrentPost().title
}));
const PostTitle = selectTitle(GetTitle);
/*creates an element <PostTitle />*/

registerBlockType( 'object/objektbeschrieb', {
    title: 'Objektbeschrieb',

    icon: 'align-center',

    category: 'layout',

    edit( { attributes, className, setAttributes } ) {
        return (
            <div className={ className }>
                <PostTitle />
                <InnerBlocks 
                    template={ TEMPLATE }
                    allowedBlocks={ ALLOWED_BLOCKS }
                />
            </div>
        );
    },

    save( { attributes, className } ) {
        const { title } = attributes;
        return (
            <div className={ className }>
                <PostTitle />
                <InnerBlocks.Content />
            </div>
        );
    },
} );

How are you registering and enqueuing your JavaScript? Please paste the PHP code here.

function objektbeschrieb_block_init() {
    // Skip block registration if Gutenberg is not enabled/merged.
    if ( ! function_exists( 'register_block_type' ) ) {
        return;
    }
    $dir = dirname( __FILE__ );

    $index_js = 'objektbeschrieb/index.build.js';
    wp_register_script(
        'objektbeschrieb-block-editor',
        plugins_url( $index_js, __FILE__ ),
        array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor', 'underscore' ),
        filemtime( "$dir/$index_js" )
    );

    $style_css = 'objektbeschrieb/style.css';
    wp_register_style(
        'objektbeschrieb-block',
        plugins_url( $style_css, __FILE__ ),
        array(),
        filemtime( "$dir/$style_css" )
    );

    register_block_type( 'object/objektbeschrieb', array(
        'editor_script' => 'objektbeschrieb-block-editor',
        'style'         => 'objektbeschrieb-block',
    ) );
}
add_action( 'init', 'objektbeschrieb_block_init' );

And this is the error I'm getting:
screen shot 2018-11-23 at 9 39 41 am

I don't get the error on saved posts (so far), only if I
1) make a new post.
2) Give it a title
3) Save it
4) Reload

@janeschindler I'm running into this issue as well, did you make any progress on this?
Here is my JSX file:

const {assign} = lodash;
const {__} = wp.i18n;
const {Fragment} = wp.element;
const {
    RichText,
    BlockControls,
    AlignmentToolbar
} = wp.editor;
import {layoutAttributes} from './settings/layoutSettings';

/**
 * Register: a Gutenberg Block.
 *
 * Registers a new block provided a unique name and an object defining its
 * behavior. Once registered, the block is made editor as an option to any
 * editor interface where blocks are implemented.
 *
 * @link https://wordpress.org/gutenberg/handbook/block-api/
 * @param  {string}   name     Block name.
 * @param  {Object}   settings Block settings.
 * @return {?WPBlock}          The block, if it has been successfully
 *                             registered; otherwise `undefined`.
 */
wp.blocks.registerBlockType('wisnet/paragraph', {
    // Block name. Block names must be string that contains a namespace prefix. Example: my-plugin/my-custom-block.
    title: __('Content'), // Block title.
    icon: 'shield', // Block icon from Dashicons → https://developer.wordpress.org/resource/dashicons/.
    attributes: assign(
        {
            content: {
                type: 'string',
                source: 'html'
            },
            alignment: {
                type: 'string'
            }
        }, layoutAttributes),
    category: 'common', // Block category — Group blocks together based on common traits E.g. common, formatting, layout widgets, embed.
    keywords: [
        __('paragraph'),
        __('text'),
        __('content')
    ],

    /**
     * The edit function describes the structure of your block in the context of the editor.
     * This represents what the editor will render when the block is used.
     *
     * The "edit" property must be a valid function.
     *
     * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/
     */
    edit({attributes, className, setAttributes}) {
        const {alignment, content} = attributes;

        function onChangeContent(newContent) {
            setAttributes({content: newContent});
        }

        function onChangeAlignment(newAlignment) {
            setAttributes({alignment: newAlignment});
        }

        return (
            <Fragment>
                <BlockControls>
                    <AlignmentToolbar
                        value={alignment}
                        onChange={onChangeAlignment}
                    />
                </BlockControls>

                <RichText
                    key="editable"
                    tagName="div"
                    className={className}
                    onChange={onChangeContent}
                    style={{textAlign: alignment}}
                    value={content}
                />

            </Fragment>
        );

    },

    /**
     * The save function defines the way in which the different attributes should be combined
     * into the final markup, which is then serialized by Gutenberg into post_content.
     *
     * The "save" property must be specified and must be a valid function.
     *
     * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/
     */
    save({attributes}) {
        const {content, alignment} = attributes;

        return (
            <div className="container">
                <div className="row">
                    <div className="col">
                        <RichText
                            tagName="div"
                            value={content}
                            style={{textAlign: alignment}}
                        />
                    </div>
                </div>
            </div>
        );
    }
});

I never figured this out, sorry!

I'm having the same issue when exporting:

export default compose(
    withSelect(select => ({
        isEditorSidebarOpened: select('core/edit-post').isEditorSidebarOpened(),
    })),
)(Component);

Has anyone found a solution? Getting the same error!

@SL0TR I found my issue to be in the save method not using RichText correctly.

save({attributes}) {
    const {content, alignment} = attributes;

    return (
        <div className="container">
            <div className="row">
                <div className="col">
                                            {/* BAD */}
                    {/*<RichText
                        tagName="div"
                        value={content}
                        style={{textAlign: alignment}}
                    />*/}
                                              {/* GOOD */}
                                              <RichText.Content
                        tagName="div"
                        value={content}
                        style={{textAlign: alignment}}
                    />
                </div>
            </div>
        </div>
    );
}

From this comment:

https://github.com/WordPress/gutenberg/issues/12240#issuecomment-441180384

Note that for every reference to a top-level wp global, e.g. wp.data or wp.blocks, you must define the corresponding script handle as a dependency of your script.

From your code example, you appear to be missing wp-data:

const { registerBlockType } = wp.blocks;
const { InnerBlocks, RichText } = wp.editor
const { withSelect } = wp.data;
wp_register_script(
    'objektbeschrieb-block-editor',
    plugins_url( $index_js, __FILE__ ),
    // You *must* include `wp-data` here in order for `wp.data` to be available
    array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor', 'underscore'  ),
    filemtime( "$dir/$index_js" )
);

See also: https://make.wordpress.org/core/2018/12/06/javascript-packages-and-interoperability-in-5-0-and-beyond/

I'll preemptively close the issue, but if the problem persists, let me know and we can reopen and continue the discussion.

I made a similar component, but it allows me to have the title live ... I have no problem

import React from "react";
const { withSelect } = wp.data;

const Title = props => (
  <h1 className={props.className} style={props.style}>
    {props.title}
  </h1>
);

var selectTitle = withSelect(function(select) {
  var postData;
  if (typeof select("core/editor").getPostEdits().title !== "undefined") {
    postData = select("core/editor").getPostEdits();
  } else {
    postData = select("core/editor").getCurrentPost();
  }
  return {
    title: postData.title
  };
});
const LiveTitle = selectTitle(Title);

export default LiveTitle;

Was this page helpful?
0 / 5 - 0 ratings