I’m extending the button block, adding extra options such adding theme colors (a color picker) and icons (radio group). This adds class names for each of the options. has-icon
, has-icon-{icon}
, is-theme-{color}
, and also is-style
classes.
When saving the block as a pattern with the classes, and inserting this pattern into a post, the classes that were saved as the pattern can no longer be changable, and any changes added to the button is prepended, which breaks the block and clashes with the other class names.
Pattern html (Just the button markup)
<div class="wp-block-buttons is-content-justification-right cta-buttons">
<!-- wp:button {"className":"is-style-solid is-theme-yellow has-icon has-icon-arrow-diagonal"} -->
<div class="wp-block-button is-style-solid is-theme-yellow has-icon has-icon-arrow-diagonal is-theme-blue"><a class="wp-block-button__link" href="#form">Request</a></div>
<!-- /wp:button -->
</div>
The output class names when trying to change button settings:
wp-block is-theme-red has-icon has-icon-download is-selected wp-block-button is-style-solid is-theme-yellow has-icon has-icon-arrow-diagonal
With
is-style-solid is-theme-yellow has-icon has-icon-arrow-diagonal
Being the styles that aren’t being removed.
The fix to this is by removing the classes that’s there in the class names box, but that isn’t really a solution.
Here’s a snippet that’s extending the button block:
const addInspectorControl = createHigherOrderComponent(
(BlockEdit) => (props) => {
const {
attributes: { color, icon, className },
setAttributes,
name,
} = props;
if (!enabledBlocks.includes(name)) return <BlockEdit {...props} />;
const isStandaloneStyle =
className?.includes("is-style-standalone") ?? false;
if (isStandaloneStyle) {
setAttributes({
color: getObjByKey(buttonColorOptions, "name", "link-blue"),
});
}
return (
<Fragment>
<InspectorControls>
<PanelBody
title={__("Button Style Settings", "button/style-settings")}
>
<BaseControl>
<BaseControl.VisualLabel>Button Color</BaseControl.VisualLabel>
<ColorPalette
colors={
!isStandaloneStyle
? buttonColorOptions
: [getObjByKey(buttonColorOptions, "name", "link-blue")]
}
value={color.color}
style={{ width: "400px" }}
clearable={false}
disableCustomColors={true}
onChange={(selectedColor) => {
console.log(props, selectedColor);
return setAttributes({
color: getObjByKey(
buttonColorOptions,
"color",
selectedColor
),
});
}}
/>
</BaseControl>
<BaseControl help={`Selected Icon: ${icon.title}`}>
<BaseControl.VisualLabel>Button Icon</BaseControl.VisualLabel>
<RadioGroup
id="button-icon-selector"
onChange={(selectedIcon) =>
setAttributes({
icon: getObjByKey(buttonIconOptions, "slug", selectedIcon),
})
}
defaultChecked="none"
label="Button Icon Selection" //aria-label - not label really
checked={icon.slug}
>
{buttonIconOptions.map((iconObj) => {
return (
<Radio value={iconObj.slug}>
<Icon icon={iconObj.icon} />
</Radio>
);
})}
</RadioGroup>
</BaseControl>
</PanelBody>
</InspectorControls>
<BlockEdit {...props} />
</Fragment>
);
},
"withInspectorControl"
);
const addClassEditor = createHigherOrderComponent((BlockListBlock) => {
return (props) => {
const {
attributes: { color, icon },
className,
name,
} = props;
if (!enabledBlocks.includes(name)) return <BlockListBlock {...props} />;
console.log(typeof color, typeof icon);
console.log(props);
return (
<BlockListBlock
{...props}
className={classnames(
className,
!isEmpty(color) ? `is-theme-${color.name}` : "",
!isEmpty(icon) && icon.slug !== "none"
? `has-icon has-icon-${icon.slug}`
: ""
)}
/>
);
};
}, "withEditorColorClass");
const addClassFrontend = (props, block, attributes) => {
if (!enabledBlocks.includes(block.name)) return props;
const { className } = props;
const { color, icon } = attributes;
return assign({}, props, {
className: classnames(
className,
!isEmpty(color) ? `is-theme-${color.name}` : "",
!isEmpty(icon) && icon.slug !== "none"
? `has-icon has-icon-${icon.slug}`
: ""
),
});
};
Registering the pattern snippet
register_block_pattern(
'cta/standard-reversed',
array(
'title' => __( 'Standard CTA - Reversed', 'standard-cta-reversed' ),
'description' => _x( 'Standard CTA - Reversed', 'Block pattern description', 'ux' ),
'categories' => array( 'ctas' ),
'content' => "<!-- wp:generateblocks/container {"uniqueId":"6ec90db7","paddingTop":"1","paddingRight":"5","paddingBottom":"1","paddingLeft":"5","paddingUnit":"em","paddingRightTablet":"3","paddingLeftTablet":"3","paddingRightMobile":"2","paddingLeftMobile":"2","backgroundColor":"#283139","gradientColorOne":"#3c4042","gradientColorOneOpacity":1,"gradientColorStopOne":3,"gradientColorTwo":"#cf2e2e","gradientColorTwoOpacity":1,"gradientSelector":"pseudo-element","textColor":"#ffffff","linkColor":"#0693e3","bgImage":{"id":11904,"image":{"url":"/funky-lines.png","height":400,"width":400,"orientation":"landscape"}},"bgOptions":{"selector":"element","opacity":0.3,"overlay":false,"position":"center center","size":"actual","repeat":"repeat","attachment":""},"align":"full","shapeDividers":[],"isDynamic":true,"blockVersion":2,"className":"bg-bm-cb cta-container cta-standard-inverse cta-standard","opacities":[],"transitions":[],"boxShadows":[],"transforms":[],"textShadows":[],"filters":[],"advBackgrounds":[]} --><!-- wp:columns --><div class="wp-block-columns"><!-- wp:column {"width":"35%","className":"cta-col-image"} --><div class="wp-block-column cta-col-image" style="flex-basis:35%"><!-- wp:image {"id":12548,"sizeSlug":"large","linkDestination":"media","className":"cta-image"} --><figure class="wp-block-image size-large cta-image"><a href="/Product_Wheel_Full2000px-e1639176460709.png"><img src="/Product_Wheel_Full2000px-e1639176460709-1024x718.png" alt="" class="wp-image-12548"/></a></figure><!-- /wp:image --></div><!-- /wp:column --><!-- wp:column {"width":"55%","className":"cta-col-content"} --><div class="wp-block-column cta-col-content" style="flex-basis:55%"><!-- wp:heading {"style":{"typography":{"fontSize":"30px"}},"textColor":"white","className":"cta-heading"} --><h2 class="cta-heading has-white-color has-text-color" style="font-size:30px">Get Started with the Industry’s Best Strategic Portfolio Management Platform</h2><!-- /wp:heading --><!-- wp:buttons {"contentJustification":"right","className":"cta-buttons"} --><div class="wp-block-buttons is-content-justification-right cta-buttons"><!-- wp:button {"className":"is-style-solid is-theme-yellow has-icon has-icon-arrow-diagonal"} --><div class="wp-block-button is-style-solid is-theme-yellow has-icon has-icon-arrow-diagonal is-theme-blue"><a class="wp-block-button__link" href="#form">Request a Demo</a></div><!-- /wp:button --></div><!-- /wp:buttons --></div><!-- /wp:column --></div><!-- /wp:columns --><!-- /wp:generateblocks/container -->"
)
);