the issue I’m having is that the image data object (imgDataObj in the
js), which is saved as an attribute in the JS side, is getting passed
to the PHP side even though I’m not passing it in the serversiderender
component and I’m not listening for it in the PHP render callback
That issue could happen if you’re using WordPress 5.8 which uses Gutenberg 10.7 which has a function named __experimentalSanitizeBlockAttributes
that’s defined in the @wordpress/blocks
or wp.blocks
package. See lines 1255-1293 in wp-includes/js/dist/blocks.js
or the source at https://github.com/WordPress/gutenberg/blob/v10.7.0/packages/blocks/src/api/utils.js#L236-L277 for Gutenberg 10.7.0 release.
And what the function does is:
/**
* Ensure attributes contains only values defined by block type, and merge
* default values for missing attributes.
*
* @param {string} name The block's name.
* @param {Object} attributes The block's attributes.
* @return {Object} The sanitized attributes.
*/
export function __experimentalSanitizeBlockAttributes( name, attributes ) {
And in wp-includes/js/dist/server-side-render.js
(on line 220) or the source at https://github.com/WordPress/gutenberg/blob/v10.7.0/packages/server-side-render/src/server-side-render.js#L75-L77 (for Gutenberg 10.7.0), you can see that ServerSideRender
applies __experimentalSanitizeBlockAttributes()
on the attributes:
const sanitizedAttributes =
attributes &&
__experimentalSanitizeBlockAttributes( block, attributes );
Which means that the attributes will be merged with the ones set when registering the block type, so that’s exactly why in your case, the imgDataObj
was passed to your render callback (in PHP) even if you didn’t set the attribute in the attributes
property passed to ServerSideRender
.
How to fix the issue
Because you said, “We don’t need the entire image object“, then just remove imgDataObj
from the attributes when you register the block type.
And then, add a local variable/constant in your edit
function like so:
// At the top in the file, add:
const { useSelect } = wp.data;
// Then in the edit function, add this:
const imgDataObj = useSelect( select => {
const { getEntityRecord } = select( 'core' );
return attributes.imgID && getEntityRecord( 'root', 'media', attributes.imgID );
}, [ attributes.imgID ] );
And note that there are other changes you need to make, but see my code on GitHub for more details. (see link at the bottom)
But before that, please read the following notes..
Additional Issues/Notes
-
InspectorControls
andMediaUpload
should be imported from the@wordpress/block-editor
orwp.blockEditor
package. -
text
is not a valid attribute type and yet in your JS and PHP, thepos
attribute usedtext
as the type. So ensure your attributes are using the correct type. -
Media/post IDs are numbers, so I’d change the type of the
imgID
attribute tonumber
. -
You should use the dot notation when accessing properties in objects, unless if the property name contains characters like spaces or hypens (
-
). So instead ofimgDataObj['id']
, I’d useimgDataObj.id
. -
Your
edit
function is returning an array of elements, so each top-level element should have a uniquekey
property, e.g.<InspectorControls key="my-key">
. -
When you register your script in PHP (using
wp_register_script()
), you should specify all the WordPress/Gutenberg packages that you use in your script. So instead ofarray( 'wp-blocks', 'wp' )
, I’d usearray( 'wp-element', 'wp-editor', 'wp-blocks', 'wp-block-editor', 'wp-components', 'wp-server-side-render' )
. -
And actually, to allow bigger attributes object, you can set
httpMethod
toPOST
like so:<ServerSideRender httpMethod="POST" .../>
.
Try/Check My Code
You can find the source (ESNext + JSX) on GitHub, and check this diff to see what I changed.