3

I tried to write a very simple block plugin for Gutenberg: A simple TOC generator. I can now place a block in a post and the table of contents is being generated as an unordered list. Great! But in the backend (Gutenberg Editor) there is still my ugly block that just say "SimpleTOC" and is not dynamic.

How can I display the output of my php function "render_callback" in the plugin.php https://github.com/mtoensing/simpletoc/blob/0.5/plugin.php in the "edit" function in the JS code? I read my tutorials and looked at core blocks but I just don't get the server side functions.

This is all of my index.js https://github.com/mtoensing/simpletoc/blob/0.5/src/index.js block code:

const { __, setLocaleData } = wp.i18n;
const { registerBlockType } = wp.blocks;

registerBlockType( 'simpletoc/toc', {
    title: __( 'Table of Contents', 'simpletoc' ),
    icon: 'list-view',
    category: 'layout',
    edit( { className } ) {
    return <p className={ className }>
        <ul>
            <li>SimpleTOC</li>
            <li>SimpleTOC</li>
            <li>SimpleTOC</li>
        </ul>
        </p>;
  },
    save: props => {
        return null;
    },
} );

My render_callback function looks like this in plugin.php https://github.com/mtoensing/simpletoc/blob/0.5/plugin.php:

function render_callback( $attributes, $content ) {

    $blocks = parse_blocks( get_the_content( get_the_ID()));

    if ( empty( $blocks ) ) {
        return 'No contents.';
    }

  //add only if block is used in this post.
  add_filter( 'render_block', __NAMESPACE__ . '\\filter_block', 10, 2 );

    $headings = array_values( array_filter( $blocks, function( $block ){
        return $block['blockName'] === 'core/heading';
    }) );
    if ( empty( $headings ) ) {
        return 'No headings.';
    }

    $heading_contents = array_column( $headings, 'innerHTML');

    $output .= '<ul class="toc">';
    foreach ( $heading_contents as $heading_content ) {
        preg_match( '|<h[^>]+>(.*)</h[^>]+>|iU', $heading_content , $matches );

        $link = sanitize_title_with_dashes( $matches[1]);
        $output .= '<li><a href="#' . $link . '">' . $matches[1] . '</a></li>';
    }
    $output .= '</ul>';

    return $output;
}

2 Answers 2

2

I think that you are missing the PHP registration of the block.

The JS definition is all right, but you need to tell PHP that the block exists.

Can you try to register your block in your plugin or function.php file?

Here is an example https://developer.wordpress.org/block-editor/tutorials/block-tutorial/creating-dynamic-blocks/

<?php

function simpletoc_toc_render_callback( $attributes, $content ) {
    return 'This is my block content'.
}

function simpletoc_toc_register_block() {
    register_block_type( 'simpletoc/toc', array(
        'render_callback' => 'simpletoc_toc_render_callback'
    ) );

}
add_action( 'init', 'simpletoc_toc_register_block' );

Note that the code above is shortened to the essential.

EDIT Sorry, didn't realized that all the magic for the backend rendering was coming from ACF Plugin.

You might want to have a look at this. https://developer.wordpress.org/block-editor/packages/packages-server-side-render/ Though I have no idea on how to use it.

2

I had to add serversiderender as a component in php (in init), package.js and the js code.

init in php

  wp_register_script(
    'simpletoc',
    plugins_url('build/index.js', __FILE__),
    [ 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-server-side-render' ],
    filemtime(plugin_dir_path(__FILE__) . 'build/index.js')
    );

block js:

const { __, setLocaleData } = wp.i18n;
const { registerBlockType } = wp.blocks;
import ServerSideRender from '@wordpress/server-side-render';

registerBlockType( 'simpletoc/toc', {
    title: __( 'SimpleTOC', 'simpletoc' ),
    icon: 'list-view',
    category: 'layout',
    edit: function( props ) {
        return (
                    <p className={ props.className }>
            <ServerSideRender
                block="simpletoc/toc"
                attributes={ props.attributes }
            />
                    </p>
        );
    },
    save: props => {
        return null;
    },
} );

and install it in the environment:

npm install @wordpress/server-side-render --save

I forgot the very first step and then it just worked. Complete working script here: https://github.com/mtoensing/simpletoc/tree/0.6

1
  • Awesome, thanks for sharing your solution.
    – Tim
    Apr 29, 2020 at 8:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.