Site icon Hip-Hop Website Design and Development

ServerSideRender and Media Object: attributes passing image data object to php renderer even though it’s not set

EDIT: Simply put, 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.

I have a custom script that creates image srcset with custom sizes. I’m trying to put this into a block. ServerSideRender seems to be the way to go. I’ve made a handful of blocks using it but never one with an image. So the idea is, the user uploads/picks an image from the media library and sets their custom sizes for each breakpoint. The block sends the sizes and just the ID number of the image to the PHP side of things. We don’t need the entire image object. For one it creates an error say the URL is too long. All my script needs is the ID. However, even though I’m not passing the image object in the attributes, it shows up in the PHP side.

I got this working in a non-serversiderender block but it was kinda clunky. Serversiderender seems more elegant but I’m just missing something.

Here is my js:

import React from 'react';
if (wp.element && wp.editor) {
const { __ } = wp.i18n; // Import __() from wp.i18n
const {
registerBlockType,
getBlockDefaultClassName
} = wp.blocks;
const {
useBlockProps,
MediaUploadCheck,
} = wp.blockEditor;
const {
Button,
PanelBody,
PanelRow,
SelectControl,
TextControl,
ToggleControl,
} = wp.components;
const {
InspectorControls,
MediaUpload
} = wp.editor;
const { serverSideRender: ServerSideRender } = wp;
const el = wp.element.createElement;
const icon = el('svg',{
xmlns: 'http://www.w3.org/2000/svg',
viewBox: '0 0 93 93',
},
el('title', 'icon' ),
el('g',{
id: 'Layer_2',
'data-name': 'Layer 2'
},
el('g',{
id: 'Layer_1-2',
'data-name': 'Layer 1'
},
el('path',{
d: 'M30,30V93H93V30ZM80.47,61l-19,19L50.66,69.11,36,83.77V36H87V67.52Z'
}),
el('circle',{
cx: '46.21',
cy: '46.53',
r: '5.76',
}),
el('polygon', {
points: '6 87 6 6 87 6 87 13 93 13 93 0 0 0 0 93 13 93 13 87 6 87'
}),
el('polygon', {
points: '21 87 21 21 87 21 87 28 93 28 93 15 15 15 15 93 28 93 28 87 21 87'
}),
)
)
);
registerBlockType('cw-blocks/responsive-image', {
title: 'Responsive Image',
icon: icon,
category: 'embed',
attributes: {
imgW: {
type: 'number',
default: 1600,
},
imgH: {
type: 'number',
default: 1200,
},
imgWMed: {
type: 'number',
default: 800,
},
imgHMed: {
type: 'number',
default: 600,
},
imgWSmall: {
type: 'number',
default: 400,
},
imgHSmall: {
type: 'number',
default: 300,
},
crop: {
type: 'boolean',
default: false,
},
linkURL: {
type: 'string',
default: ''
},
targetBlank: {
type: 'boolean',
default: false
},
pos: {
type: 'text',
default: ''
},
imgDataObj: {
type: 'array',
default: {}
},
imgID: {
type: 'string',
default: ''
}
},
edit: (props) => {
const blockProps = useBlockProps();
const { className, setAttributes } = props;
const { attributes } = props;
const setImgData = function (imgDataObj){
setAttributes({ imgDataObj: imgDataObj });
setAttributes({ imgID: imgDataObj['id'] });
}
const resetImgData = function (){
setAttributes({ imgDataObj: {} });
setAttributes({ imgID: '' });
}
return [
<InspectorControls>
<PanelBody title="Image" initialOpen={true}>
<MediaUploadCheck>
<MediaUpload
className="cw-resp-image wp-admin-cw-resp-image"
allowedTypes={['image']}
multiple={false}
value={props.attributes.imgDataObj ? props.attributes.imgDataObj.id : ''}
onSelect={setImgData}
render={({ open }) => (
attributes.imgDataObj.id ?
<div>
<p>
<img src={attributes.imgDataObj.url} width={attributes.imgDataObj.width / 2} />
</p>
<p>
<Button onClick={resetImgData} className="button is-small">Remove</Button>
</p>
</div> :
<Button onClick={open} className="button">Select/Upload Image</Button>
)}
/>
</MediaUploadCheck>
<SelectControl
label="Position"
value={props.attributes.pos}
onChange={(pos) => setAttributes({ pos: pos })}
options={[
{ label: 'Left', value: 'left' },
{ label: 'Center', value: 'center' },
{ label: 'Right', value: 'right' },
]}
/>
</PanelBody>
<PanelBody title="URL" initialOpen={false}>
<TextControl
label="URL"
value={props.attributes.linkURL}
onChange={(linkURL) => setAttributes({ linkURL: linkURL })}
type="text"
/>
<ToggleControl
label="Open link in new tab"
checked={props.attributes.targetBlank}
onChange={(targetBlank) => setAttributes({ targetBlank: targetBlank })}
/>
</PanelBody>
<PanelBody title="Sizes" initialOpen={true}>
<PanelRow>
<p>Both width and height are required to create a cropped image.</p>
</PanelRow>
<TextControl
label="Small Width (phones)"
value={props.attributes.imgWSmall}
onChange={(imgWSmall) => setAttributes({ imgWSmall: parseInt(imgWSmall) })}
type="number"
/>
<TextControl
label="Small Height (phones)"
value={props.attributes.imgHSmall}
onChange={(imgHSmall) => setAttributes({ imgHSmall: parseInt(imgHSmall) })}
type="number"
/>
<TextControl
label="Medium Width (tablets)"
value={props.attributes.imgWMed}
onChange={(imgWMed) => setAttributes({ imgWMed: parseInt(imgWMed) })}
type="number"
/>
<TextControl
label="Medium Height (tablets)"
value={props.attributes.imgHMed}
onChange={(imgHMed) => setAttributes({ imgHMed: parseInt(imgHMed) })}
type="number"
/>
<TextControl
label="Large Width (desktop)"
value={props.attributes.imgW}
onChange={(imgW) => setAttributes({ imgW: parseInt(imgW) })}
type="number"
/>
<TextControl
label="Large Height (desktop)"
value={props.attributes.imgH}
onChange={(imgH) => setAttributes({ imgH: parseInt(imgH) })}
type="number"
/>
</PanelBody>
<PanelBody title="Options" initialOpen={false}>
<ToggleControl
label="Crop"
checked={props.attributes.crop}
onChange={(crop) => setAttributes({ crop: crop })}
/>
</PanelBody>
</InspectorControls>,
<div {...blockProps}>
<ServerSideRender
block="cw-blocks/responsive-image"
attributes={{
// no image object sent here
imgW: attributes.imgW,
imgH: attributes.imgH,
imgWMed: attributes.imgWMed,
imgHMed: attributes.imgHMed,
imgWSmall: attributes.imgWSmall,
imgHSmall: attributes.imgHSmall,
crop: attributes.crop,
loading: attributes.loading,
linkURL: attributes.linkURL,
targetBlank: attributes.targetBlank,
pos: attributes.pos,
imgID: attributes.imgID,
}}
/>
</div>
];
},
save: () => {
return null;
},
});
}

and here is the php

<?php
function cw_register_respimg_block(){
wp_register_script('responsive-image', get_template_directory_uri() . '/src/js/admin/image-block.js', array(
'wp-blocks',
'wp'
));
register_block_type(
'cw-blocks/responsive-image',
array(
'attributes' => array(
// no image object received here
'imgW' => array(
'type' => 'number',
'default' => 1600,
),
'imgH' => array(
'type' => 'number',
'default' => 1200,
),
'imgWMed' => array(
'type' => 'number',
'default' => 800,
),
'imgHMed' => array(
'type' => 'number',
'default' => 600,
),
'imgWSmall' => array(
'type' => 'number',
'default' => 400,
),
'imgHSmall' => array(
'type' => 'number',
'default' => 300,
),
'crop' => array(
'type' => 'boolean',
'default' => false,
),
'linkURL' => array(
'type' => 'string',
'default' => ''
),
'targetBlank' => array(
'type' => 'boolean',
'default' => false
),
'pos' => array(
'type' => 'text',
'default' => ''
),
'imgID' => array(
'type' => 'string',
'default' => ''
),
),
'render_callback' => 'cw_respimg_renderer',
'editor_script' => 'responsive-image'
)
);
}
function cw_respimg_renderer($block_attributes, $content){
$html = '';
// need the image id to build custom srcset
if($block_attributes['imgID']) {
// build size option data for image script
$respimg_sizes = array();
if($block_attributes['imgWSmall'] || $block_attributes['imgHSmall']) {
$respimg_sizes['respimg_size_small'] = array(
'w' => $block_attributes['imgWSmall'] ? $block_attributes['imgWSmall'] : NULL,
'w' => $block_attributes['imgHSmall'] ? $block_attributes['imgHSmall'] : NULL,
'crop' => $block_attributes['crop'],
);
}
if($block_attributes['imgWMed'] || $block_attributes['imgHMed']) {
$respimg_sizes['respimg_size_med'] = array(
'w' => $block_attributes['imgWMed'] ? $block_attributes['imgWMed'] : NULL,
'w' => $block_attributes['imgHMed'] ? $block_attributes['imgHMed'] : NULL,
'crop' => $block_attributes['crop'],
);
}
if($block_attributes['imgW'] || $block_attributes['imgH']) {
$respimg_sizes['respimg_size_large'] = array(
'w' => $block_attributes['imgW'] ? $block_attributes['imgW'] : NULL,
'w' => $block_attributes['imgH'] ? $block_attributes['imgH'] : NULL,
'crop' => $block_attributes['crop'],
);
}
$resp_image = get_cw_img($block_attributes['imgID'], 'respimg_size_large', $respimg_sizes);
// build image link
$link_start = '';
$link_end = '';
if($block_attributes['linkURL']) {
$link_start = $block_attributes['targetBlank'] ? '<a href="'.$block_attributes['linkURL'].'" target="_blank">' : '<a href="'.$block_attributes['linkURL'].'">';
$link_end = '</a>';
}
$html .= '<div class="cw-resp-img-mother '.$block_attributes['pos'].'">'.$link_start.$resp_image.$link_end.'</div>';
}
return $html;
}
add_action('init', 'cw_register_respimg_block');

Any help is greatly appreciated.