Gutenberg: type: 'array' not possible to save?

Created on 9 Jun 2018  Â·  11Comments  Â·  Source: WordPress/gutenberg

Attributes that are arrays are not saved.

If JSON.stringify() is required then how to make it a string only on save?

This is what I use as a workaround (is there some other correct/official way?):

items: { type: 'array', default: [] },
itemsStringified: { type: 'string' },
[Type] Help Request

Most helpful comment

Yes, I can save arrays now. This is a React issue it seems. I think this can be closed.

All 11 comments

Can you share more of your block implementation? It should be expected that 'array' is a valid attribute type.

See https://github.com/WordPress/gutenberg/issues/7238

I only have 1 attribute type: 'array' and I do a single props.setAttributes({ test: updatedArray }); in RichText onChange() and neither edit() is re-triggered after setAttribute() nor is this array saved on front-end, I only get <!-- wp:slug/naked-block-without-array-saved /-->.

But: everything works for type: 'string' as expected (both edit() is triggered and value is saved).

This is my save() function:

save: function(props){
    return null;
},

I tried recreating, but from my own testing, it appears to work exactly as expected. Here's the entire block code I'm using:

( function( blocks, element ) {
    var el = element.createElement;

    blocks.registerBlockType( 'my-demo/demo-block', {

            title: 'Demo Block',

            icon: 'format-aside',

            category: 'common',

            attributes: {
                test: { type: 'array', default: [1, 2, 3] },
            },

            edit: function ( props ) {
                return el( 'div', {
                    style: { height: '20px' },
                    onClick: function(){
                        var newTest = [4, 5, 6];
                        props.setAttributes({ test: newTest });
                    },
                }, props.attributes.test );
            },

            save: function () {
                return el( 'div' );
            }

    } );
} )(
    window.wp.blocks,
    window.wp.element
);

When I click the block, the edit is called again, with the new updated test attribute, and the block is serialized as:

<!-- wp:my-demo/demo-block {"test":[4,5,6]} -->
<div class="wp-block-my-demo-demo-block"></div>
<!-- /wp:my-demo/demo-block -->

Note the array attribute.

Can you check to see if your attribute types are defined in an attributes property like in my snippet above?

Can you also check https://github.com/WordPress/gutenberg/issues/7016#issuecomment-396094836 to see if your issue may be the same, i.e. modifying the block's default value using Array#push or similar?

Yes, I used push(). But also splice() I think?

So the only way to push something would be this:

( function( blocks, element ) {
    var el = element.createElement;

    blocks.registerBlockType( 'my-demo/demo-block', {
            title: 'Demo Block',
            icon: 'format-aside',
            category: 'common',
            attributes: {
                test: { type: 'array', default: [1, 2, 3] },
            },
            edit: function ( props ) {
                return el( 'div', {
                    style: { height: '20px' },
                    onClick: function(){

                        // #1 This doesn't work.
                        props.attributes.test.push(4);
                        props.setAttributes({ test: props.attributes.test });

                        // #2 This works.
                        props.attributes.test[props.attributes.test.length] = 4;
                        props.setAttributes({ test: props.attributes.test });

                        // #3 And splice() equivalent would be this?
                        var copy = $.extend(true, {}, props.attributes.test);
                        copy.splice(1, 1);
                        props.setAttributes({ test: copy });
                    },
                }, props.attributes.test );
            },
            save: function () {
                return el( 'div' );
            }
    } );
} )(
    window.wp.blocks,
    window.wp.element
);

Right?

I didn't test this yet but I will remove my itemsStringified: { type: 'string' },.

Also this documentation page needs update then: https://wordpress.org/gutenberg/handbook/block-api/attributes/ (this was misleading and led me to creating this question and itemsStringified as a workaround).

If you’d like to use an object or an array in an attribute, you can register a string attribute type and use JSON as the intermediary. Serialize the structured data to JSON prior to saving, and then deserialize the JSON string on the server. Keep in mind that you’re responsible for the integrity of the data; make sure to properly sanitize, accommodate missing data, etc.

Related: #6097

Based on the original issue in #6074, seems like the workaround was primarily aimed at usage with meta? Can you clarify, @danielbachhuber / @gziolo ?

It should otherwise be perfectly valid to save an attribute with array and object.

@danielbachhuber added the following section to the docs with https://github.com/WordPress/gutenberg/pull/6097:

If you'd like to use an object or an array in an attribute, you can register a string attribute type and use JSON as the intermediary. Serialize the structured data to JSON prior to saving, and then deserialize the JSON string on the server. Keep in mind that you're responsible for the integrity of the data; make sure to properly sanitize, accommodate missing data, etc.

@gziolo Related (but possibly best as a separate issue?) — that approach causes issues when rendering on the front-end, because attributes are json_decoded before being passed into $block_type->render():

https://github.com/WordPress/gutenberg/blob/7066905fe907bb8b160d1373a5c5ec3220b5eec0/lib/blocks.php#L174

So if you've serialised your attribute as a JSON string, it gets automatically unserialised before the attributes are passed to your render_callback, and your server-side code gets confused because it's expecting a string and gets an array instead.

@manake did the advice at https://github.com/WordPress/gutenberg/issues/7016#issuecomment-396094836 to use Array#concat and the comment at https://github.com/WordPress/gutenberg/issues/7016#issuecomment-396242353 saying not to modify directly values passed through as props to edit or save help you?

Yes, I can save arrays now. This is a React issue it seems. I think this can be closed.

Ace. Thank you for the follow-up! It is appreciated.

Was this page helpful?
0 / 5 - 0 ratings