Site icon Hip-Hop Website Design and Development

Adding a custom PanelColorSettings control to a core block, and using the color slug in a custom className

I’m trying to add a custom color control to the group and cover blocks, and if a color is selected, construct a custom className for the block. This won’t be used for the default text color or background color.

What I’ve done:

I’ve been able to get the control to appear, and the className to save to the block when saving the post properly. On the front end, it works.

What’s missing:

The problem I’m having is that the className only applies on save, so if I cycle through all colors in the editor, the className isn’t applied live in the editor, so I can’t see the changes on the fly.

What I think the problem is:

I’m using a filter to save the custom className on save, but there’s nothing I can find for how to do it on the fly in the editor.

My code (updated):

/**
 * External Dependencies
 */
import classnames from 'classnames';

/**
 * WordPress Dependencies
 */
const { __ } = wp.i18n;
const { addFilter } = wp.hooks;
const { Fragment } = wp.element;
const { createHigherOrderComponent } = wp.compose;
const { InspectorControls, getColorObjectByColorValue, PanelColorSettings } = wp.blockEditor;
const { select } = wp.data;


// Restrict to specific block names
const allowedBlocks = ['core/group', 'core/cover'];

/**
 * Add custom attribute for section separator.
 *
 * @param {Object} settings Settings for the block.
 *
 * @return {Object} settings Modified settings.
 */
function addAttributes(settings) {

    //check if object exists for old Gutenberg version compatibility
    //add allowedBlocks restriction
    if (typeof settings.attributes !== 'undefined' && allowedBlocks.includes(settings.name)) {

        settings.attributes = Object.assign(settings.attributes, {
            dividerColor: {
                type: 'string',
                default: null,
            }
        });

    }

    return settings;
}

/**
 * Add section divider controls on Advanced Block Panel.
 *
 * @param {function} BlockEdit Block edit component.
 *
 * @return {function} BlockEdit Modified block edit component.
 */
const withAdvancedControls = createHigherOrderComponent((BlockEdit) => {
    return (props) => {

        if (!allowedBlocks.includes(props.name)) {
            return(<BlockEdit {...props} />);
        }

        const {
            name,
            attributes,
            setAttributes,
            isSelected,
        } = props;

        const {
            dividerColor
        } = attributes;

        const changeColor = (value) => {
            setAttributes({ dividerColor: value });
            console.log(props);
        }

        return (
            <Fragment>
                <BlockEdit {...props} />
                {isSelected && allowedBlocks.includes(name) &&
                    <InspectorControls>
                        <PanelColorSettings 
                            title={__('Section Divider')}
                            colorSettings={[
                                {
                                    value: dividerColor,
                                    onChange: changeColor,
                                    label: __('Choose a color to enable the divider.')
                                }
                            ]}
                        />
                    </InspectorControls>
                }
            </Fragment>
        );
    };
}, 'withAdvancedControls');

/**
 * Add custom element class in save element.
 *
 * @param {Object} extraProps     Block element.
 * @param {Object} blockType      Blocks object.
 * @param {Object} attributes     Blocks attributes.
 *
 * @return {Object} extraProps Modified block element.
 */
function applyExtraClass(extraProps, blockType, attributes) {

    const { dividerColor } = attributes;

    //check if attribute exists for old Gutenberg version compatibility
    //add class only when dividerColor is not empty
    //add allowedBlocks restriction
    if (typeof dividerColor !== 'undefined'
        && dividerColor
        && allowedBlocks.includes(blockType.name)) {
        const settings = select('core/editor').getEditorSettings();
        const colorObject = getColorObjectByColorValue(settings.colors, dividerColor);
        if (colorObject) {
            extraProps.className = classnames(extraProps.className, 'divider divider-' + colorObject.slug);
        }
    }

    return extraProps;
}

/**
 * Add size class to the block in the editor
 *
 * @param {Object} BlockListBlock  BlockListBlock object.
 *
 * @return {Object}                Modified BlockListBlock object.
 */
 const addDividerClass = createHigherOrderComponent((BlockListBlock) => {
    return (props) => {
      const {
        attributes,
        className,
        name,
      } = props;

      const { dividerColor } = attributes;
  
      if (!allowedBlocks.includes(name)) {
        return <BlockListBlock {...props} />;
      }

      const settings = select('core/editor').getEditorSettings();
      const colorObject = getColorObjectByColorValue(settings.colors, dividerColor);

      if (!colorObject) {
        return <BlockListBlock {...props} />;
      }
  
      return (
        <BlockListBlock
          {...props}
          className={classnames(className, 'divider divider-' + colorObject.slug)}
        />
      );
    };
  }, 'addDividerClass');

//add filters

addFilter(
    'blocks.registerBlockType',
    'ursa6/custom-attributes',
    addAttributes
);

addFilter(
    'editor.BlockEdit',
    'ursa6/custom-advanced-control',
    withAdvancedControls
);

addFilter(
    'blocks.getSaveContent.extraProps',
    'ursa6/applyExtraClass',
    applyExtraClass
);

addFilter(
    'editor.BlockListBlock',
    'ursa6/addDividerClass',
    addDividerClass
 );

What I’ve tried:

Updated code above. I have this working a little better. The classes are applied during edit in the block editor, and on save when saved. The classes are not removed when colors are deselected, and the custom color class is not replaced when changing colors.

Can someone tell me where I went wrong?