3

I currently have a block that passes some of its attributes down to the nested InnerBlocks using React's Context API (the version of WordPress that I'm on does not yet have the Block Context feature. This allows me to successfully access the parent block's attributes in the nested blocks' edit function.

registerBlockType("myblock", {
  title: "My Block",
  attributes: {
    someValue: {
      type: 'string',
      default: '',
    },
  },
  edit(props) {
    const { someValue } = props.attributes;

    // ...other code...

    return (
      <MyContext.Provider value={someValue}>
        <InnerBlocks />
      </MyContext.Provider>
    );
  },
  save(props) {
    const { someValue } = props.attributes;

    return (
      <InnerBlocks.Content />
    );
  }
});

However, I also want to access the parent block's attributes in the save function of the nested blocks. I have not been able to get React's Context API to work. Is there a method for doing this in WordPress's Block API?

2 Answers 2

4

You can pass data to a child via the select and dispatch hooks. So you would set up your child block with the inherited attribute and update that when the setting on the parent block changes.

Parent Block

Import dependencies

import { dispatch, select } from "@wordpress/data";

Your edit function might look something like this:

edit({ attributes, className, setAttributes, clientId }) {
    const { headerStyle } = attributes;

    const updateHeaderStyle = function( value ) {
        setAttributes({ headerStyle: value });

        // Update the child block's attributes
        var children = select('core/block-editor').getBlocksByClientId(clientId)[0].innerBlocks;
        children.forEach(function(child){
            dispatch('core/block-editor').updateBlockAttributes(child.clientId, {inheritedHeaderStyle: value})
        });
    }
    

    return (
        <>
            <InspectorControls>
                <PanelBody>
          

                    <RadioControl
                        label="Section Header Style"
                        selected = {headerStyle}
                        options = { [
                            { label: 'h2', value: 'h2' },
                            { label: 'h3', value: 'h3' },
                            { label: 'h4', value: 'h4' },
                            { label: 'h5', value: 'h5' },
                            { label: 'h6', value: 'h6' },
                        ]}
                        onChange= {updateHeaderStyle}
                    />
                </PanelBody>
            </InspectorControls>
            <InnerBlocks
              ...
            />
         <>
  );
  }

Child Block

The above function will update on change, but within the edit function of the child block you can grab the parent attribute and set it if undefined...

if (!inheritedHeaderStyle) {
    var parent = select('core/block-editor').getBlockParents(clientId);
    const parentAtts = select('core/block-editor').getBlockAttributes(parent);
    setAttributes( { inheritedHeaderStyle: parentAtts.headerStyle } )
}
1
  • ok. watching this answer a 20th time i now finally realize, what is happening here. you use the parent element to set the attribute to itself AND to its children. got this working on my end, finally <3
    – honk31
    Dec 7, 2021 at 14:20
1

To achieve this you can use build in feature Context.

Parent Block

registerBlockType( 'my-plugin/parent', {
 
    attributes: {
        switch: {
            type: 'boolean',
            default:false
        },
    },
 
    providesContext: {
        'my-plugin/switch': 'switch',
    },

    edit: Edit,

    save,
} );

Child Block

registerBlockType( 'my-plugin/child', {
     attributes: {
        switch: {
            type: 'boolean',
            default:false
        },
    },

    usesContext: [ 'my-plugin/switch' ],
 
    edit({ attributes, setAttributes, context }) {

        // copy value from parent context into child attribute
        setAttributes({
          switch: context["my-plugin/switch"],
        });
    },
 
    save({ attributes }) {

        // use this attribute
        
    },
} );

API Reference: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-context/

1
  • 1
    As written, this causes problems when initializing the block in the editor because setAttributes() modifies the component's state, which should not happen during rendering. You can fix this by wrapping the setAttributes call inside useEffect(): useEffect( () => { setAttributes({ switch: context['my-plugin/switch'] }); }, [context, setAttributes]);
    – Jesse
    Jun 19, 2023 at 21:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.