0

I managed to finally get the ServerSideRender to work. But how do I reload the ServerSideRender when the post is saved?

    save: props => {
        return null;
    },

I think here I need something like a trigger to load the data again from my plugin.php Can somebody please tell me where to look? The serversiderender lists the headings structure and needs to display new data when the post is updated. Here is the whole index.js for the block.

const { __, setLocaleData } = wp.i18n;
const { registerBlockType } = wp.blocks;
const listul  = wp.element.createElement('svg',
    {
        width: 20,
        height: 20
    },
    wp.element.createElement( 'path',
        {
            d: "M5.5 7C4.67 7 4 6.33 4 5.5 4 4.68 4.67 4 5.5 4 6.32 4 7 4.68 7 5.5 7 6.33 6.32 7 5.5 7zM8 5h9v1H8V5zm-2.5 7c-.83 0-1.5-.67-1.5-1.5C4 9.68 4.67 9 5.5 9c.82 0 1.5.68 1.5 1.5 0 .83-.68 1.5-1.5 1.5zM8 10h9v1H8v-1zm-2.5 7c-.83 0-1.5-.67-1.5-1.5 0-.82.67-1.5 1.5-1.5.82 0 1.5.68 1.5 1.5 0 .83-.68 1.5-1.5 1.5zM8 15h9v1H8v-1z"
        }
    )
);
import ServerSideRender from '@wordpress/server-side-render';

registerBlockType( 'simpletoc/toc', {
    title: __( 'SimpleTOC', 'simpletoc' ),
    icon: listul,
    category: 'layout',
    edit: function( props ) {
        return (
            <p className={ props.className }>
            <ServerSideRender
                block="simpletoc/toc"
                attributes={ props.attributes }
            />
            </p>
        );
    },
    save: props => {
        return null;
    },
} );
8
  • the serverside render component automatically refreshes when the attributes change, you don't need to trigger it to refresh. What's the issue you're having that's posed this question? Are you trying to change the block based on something other than its attributes server side that changes when the post is published? I would avoid doing that, that's not how blocks are supposed to work
    – Tom J Nowell
    Commented Apr 14, 2020 at 21:27
  • The block generates a table of contents. So every time a user changes the content it should generate a new Toc. Until now I did not use the attributes because they are not needed. I used them because they were part of a tutorial. So what is the best way to do that? Maybe a “refresh” button? I would prefer that the block is refreshed in the editor when the user saves the article. Seems the better choice.
    – Marc
    Commented Apr 15, 2020 at 6:53
  • I would thing is it something like this Look for save_post in my callback function and change the attribute to have the desired effect? Or can I do this in JavaScript only?
    – Marc
    Commented Apr 15, 2020 at 9:18
  • Ooooh, no you shouldn't change it on save, that would mean the TOC would be incorrect until you saved the post. tbh this would be better built as a fully JS block. That way instead of using the post content on save, you could subscribe to the data store and just look at the content directly, Then the block would update in realtime. On top of that, the TOC would be stored as HTML in the post content, so no PHP code would be needed to render it on the frontend
    – Tom J Nowell
    Commented Apr 15, 2020 at 15:07
  • Otherwise, the approach implies a misunderstanding about how the React UI works. The UI doesn't determine the data. The data determines the UI. You can throw the entire UI away and recreate it using the components given the same data. To change the UI, you change the data. As long as your component passes the same props, you'll get the same result.
    – Tom J Nowell
    Commented Apr 15, 2020 at 15:09

2 Answers 2

1

I solved it with an "update" button in the block. It is a bit weird because I need to send "fake" attributes to re-render it. But it works.

var el = wp.element.createElement;
var registerBlockType = wp.blocks.registerBlockType;
var BlockControls = wp.blockEditor.BlockControls;
var ServerSideRender = wp.serverSideRender;
var Toolbar = wp.components.Toolbar;
var IconButton = wp.components.Button;

function sendfakeAttribute(props) {
        // this actually triggers the ServerSideRender again ¯\_(ツ)_/¯
        props.setAttributes({ updated: Date.now() });
}

registerBlockType( 'simpletoc/toc', {
    title: __( 'SimpleTOC', 'simpletoc' ),
    icon: listul,
    category: 'layout',
    edit: function( props ) {

                    return [
                            el(
                                BlockControls,
                                { key: 'controls' },
                                el(
                                    Toolbar,
                                    null,
                                    el(
                                        IconButton,
                                        {
                                            className: 'components-icon-button components-toolbar__control',
                                            label: 'update',
                                            onClick: function() { sendfakeAttribute(props) },
                                            icon: 'update'
                                        }
                                    )
                                )
                            ),
                            el(
                                ServerSideRender,
                                {
                                    block: props.name,
                                    attributes: props.attributes
                                }
                            )
                        ];


    },
    save: props => {
        return null;
    },
} );
1
  • wp.components.IconButton is deprecated. Use wp.components.Button or wp.components.ToolbarButton isntead. Commented Apr 10, 2021 at 8:42
0

Another workaround I found, urlQueryArgs always triggers ServerSideRender:

ServerSideRender,
{
    block: props.name,
    attributes: props.attributes,
    urlQueryArgs: { foo: 1 }
}

even though foo never changes. But this workaround is undocumented, as far as I know, so not a good idea in case WP decides to code more change checks.

So your own answer is better, Marc.

I found out the hard way that you are very right to use

props.setAttributes({ updated: Date.now() });

instead of

props.updated = Date.now();

Two things were news to me:

  1. setAttributes() merges existing properties instead of setting all properties.
  2. setAttributes() flags wp.element (or wp) to run ServerSideRender.

By inspection, function ServerSideRender() in 'wp-includes/js/dist/server-side-render.js' checks if the properties have changed before fetching. But if you debug the script you see ServerSideRender does not even get called again unless setAttributes() is used.

Your Answer

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

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