Set block attributes depending on the block position

In a project, I wanted to use the sizes attribute for the images in a slider block. But because the slider is used in different widths, the value of the sizes attribute needs to change depending on the position of the slider block.

I use the subscribe() function for the solution. When the editor’s state changes, the block list is checked and the maxWidth attribute for slide blocks is updated depending on the position of its slider parent block in the block list.

This is the complete code (or as a Gist):

const { select, } = wp.data; wp.domReady( () => { /** * Get the slider blocks. * * @param {object} block * @param {array} sliderBlocks */ const getSliderBlocks = ( block, sliderBlocks ) => { if ( block.innerBlocks.length === 0 ) { return; } // Check if it is a slider block. If so, push innerBlocks to the sliderBlocks array. if ( block.name === 'slug/slider' ) { sliderBlocks.push( block ); return; } block.innerBlocks.map( innerBlock => getSliderBlocks( innerBlock, sliderBlocks ) ); }; const getBlockList = () => select( 'core/editor' ).getBlocks(); wp.data.subscribe( () => { let blockList = getBlockList(); if ( blockList ) { // Get slider blocks. let sliderBlocks = []; blockList.map( block => getSliderBlocks( block, sliderBlocks ) ); sliderBlocks.map( sliderBlock => { // Set maxWidth depending on position and settings of block. const blockParents = select( 'core/block-editor' ).getBlockParents( sliderBlock.clientId ); let maxWidth; // Check if the slider block has no parents. if ( blockParents.length === 0 ) { const align = sliderBlock.attributes.align; // Set maxWidth to 100vw if full align. if ( align !== undefined && align === 'full' ) { maxWidth = '100vw'; } // Set maxWidth to 1170 if no align. if ( align === undefined || align !== 'full' ) { maxWidth = '1170'; } } else { // Get column parents. const columnParents = select( 'core/block-editor' ).getBlockParentsByBlockName( sliderBlock.clientId, 'core/column' ); if ( columnParents.length > 0 ) { const columnParent = select( 'core/block-editor' ).getBlock( columnParents[0] ); let columnWidth = columnParent.attributes !== undefined && columnParent.attributes.width !== undefined && columnParent.attributes.width !== '' ? columnParent.attributes.width : 50; maxWidth = 1170 / 100 * columnWidth; } else { maxWidth = '1170'; } } // Set the attributes for the slide blocks. sliderBlock.innerBlocks.map( slideBlock => { slideBlock.attributes.maxWidth = maxWidth; } ); } ); } } ); } );
Code language: JavaScript (javascript)

After the DOM is ready, we define the function getSliderBlocks() at line 12, which gets a block and an array. The slider block works with the InnerBlocks component with the single slides being blocks themself, so if block.innerBlocks.length is 0, it cannot be a slider block and we exit the function early.

If the block is a slider block, we add it to the array we got as a function parameter and quit the function again. If it is not a slider block but has innerBlocks, we run the getSliderBlocks() function again for the innerBlocks, to also get sliders inside group blocks, columns, or other blocks that contain other blocks.

At line 26, we create the getBlockList() function to get a list of the blocks in the editor. After that, we listen to editor changes via wp.data.subscribe() and fetch the current block list. If we have blocks, we create a sliderBlocks array and run the getSliderBlocks() function for the top-level blocks at line 32. And, like described above, getSliderBlocks() also handles nested blocks, so after line 32 we have all slider blocks in sliderBlocks.

Now we need to loop the slider blocks and check their current position. For that, we get the parent blocks to each slider block at line 36 via wp.data.select( 'core/block-editor' ).getBlockParents().

If we get an empty result for parent blocks, the slider is on the top level in the editor. Now we need to check if the block width is set to full width, and that setting is saved in the align attribute. So we get the align value at line 42 and check if it equals full. If that is the case, we set maxWidth to 100vw. If align is something other than full, we set maxWidth to 1170, the content width of my website project in pixels.

If we have parent blocks, we check for column blocks in them, and if there are column blocks, we use the width of the first parent column block to calculate a percentage value for the maxWidth.

If the slider is not inside a column block, we set the maxWidth to 1170.

To use the calculated width value for the image, we loop through the slide blocks at lines 66 to 68 and set its maxWidth attribute. With that, the maxWidth attribute of a slide block should always contain the correct value for sizes depending on the position of the slider block.

It would be great to not run that code on every editor status change but just when something changes for a slider block. If someone knows a solution for that, I would be happy to hear about it 🙂

Leave a Reply

Your email address will not be published.