• I have a plugin that registers a simple custom block server-side only using register_block_type(). It works fine, but I’m looking to add an array attribute to allow the editor to select multiple options. I could do it with multiple boolean attributes, but I thought I’d try with an array as it’d be neater in the GUI.

    So I added the following to the attributes array element:

            'show' => [
                'label'   => 'Information to show',
                'type'    => 'array',
                'items'   => [
                    'type' => 'string',
                ],
                'enum'    => ['Price', 'Location', 'Description', 'Status', 'Conditions', 'Contact'],
                'default' => ['Price'],
                'autoGenerateControl' => true,
            ],

    Note that I had to add autoGenerateControl to get the multi-select control to display on the settings bar, after I did that it displayed as expected with the default value correctly loaded.

    But if I try to add or remove options using the multi-select control, two things happen:

    1. The post/page isn’t marked as “dirty” so I can’t save it, and
    2. The block itself displays “Error loading block: [object Object]”

    Note that if I remove all options from the multi-select control, the block displays as expected, it only displays this message if I select one or more options. Even though the render function is not yet coded to use the array attribute at all.

    Is it possible to do this? I’d really prefer if it can be done with server-side hooks only, as I’d rather not have to refactor the whole plugin to use npm. Any help appreciated.

Viewing 5 replies - 1 through 5 (of 5 total)
  • Thread Starter ImageRoscoHead

    (@roscohead)

    Thanks for your help!

    I found the autoGenerateControl in some example code somewhere, I’ve also not found any mention in any documentation. It is definitely causing the error, but if I remove it the GUI control is not rendered. I tried adding supports => [ 'autoRegister' => true ] with and without the autoGenerateControl but it didn’t appear to change the behaviour. Also, the error only displays in the editor, on the front end it displays as expected, but using the default value.

    It seems strange that it renders the control and populates it with the specified default, but is unable to set the attribute. Do you know why that would be, and if there’s any way to change the behaviour of that control?

    Failing that I guess the next thing to try would be a custom control, but I have no idea how to go about that. Is there a good tutorial that you know of?

    Thread Starter ImageRoscoHead

    (@roscohead)

    Correction: it’s not the autoGenerateControl causing the error. It’s adding any string to the array – either in the default value, or trying to add it via the control. If I set the default to an empty array, or delete all the strings in the control, the error goes away, and the block renders as expected. But if I modify the attribute via the GUI, it will not save that attribute, the next time I edit the page it will revert to the default array values.

    Thread Starter ImageRoscoHead

    (@roscohead)

    The error was indeed because the enum had to be inside the items element, but after posting in the Gutenberg git, it turns out there were a couple of related issues there as well (which have now been resolved there), see: https://github.com/WordPress/gutenberg/issues/83308

    Just to add to the discussion on the second part of your question: the auto-generated inspector controls for server-registered blocks are still experimental, and the multi-select variant in particular has rough edges. The “Error loading block” on change plus the post not being marked dirty usually means the generated control isn’t updating the attribute through the normal setAttributes flow, so the value it writes fails attribute validation.The most reliable workaround right now is to add a tiny edit.js (register it via the editorScript field in block.json) that renders InspectorControls with a SelectControl (multiple) or FormTokenField and calls setAttributes on change, while keeping render.php for the front end. That gives you a working multi-select with proper dirty-state handling, and you can drop it once the auto-generated controls mature.

    The main issue is that for an array attribute, enum needs to be defined inside the items schema rather than directly on the array itself.

    For example:

    'attributes' => [
        'test' => [
            'type'  => 'array',
            'items' => [
                'type' => 'string',
                'enum' => [ 'Option1', 'Option2', 'Option3' ],
            ],
            'default' => [ 'Option1', 'Option2' ],
        ],
    ],

    That should correctly validate each array item against the allowed values.

    The separate [object Object] message appears to be a Gutenberg error-handling issue, so even when validation fails, the editor is not presenting the REST API error in a useful way.

    If your goal is a multi-select UI, I’d keep the schema like the above and handle the selection control in the editor separately, while letting the server validate the final array values.

Viewing 5 replies - 1 through 5 (of 5 total)

You must be logged in to reply to this topic.