diff --git a/extensions/blocks/button/attributes.js b/extensions/blocks/button/attributes.js index 2c004670fe2e3..546125eb817cd 100644 --- a/extensions/blocks/button/attributes.js +++ b/extensions/blocks/button/attributes.js @@ -15,6 +15,9 @@ export default { uniqueId: { type: 'string', }, + passthroughAttributes: { + type: 'object', + }, text: { type: 'string', }, diff --git a/extensions/blocks/button/edit.js b/extensions/blocks/button/edit.js index 2ef1e33ccba26..6982c1a519108 100644 --- a/extensions/blocks/button/edit.js +++ b/extensions/blocks/button/edit.js @@ -22,12 +22,14 @@ import applyFallbackStyles from './apply-fallback-styles'; import ButtonBorderPanel from './button-border-panel'; import ButtonColorsPanel from './button-colors-panel'; import { IS_GRADIENT_AVAILABLE } from './constants'; +import usePassthroughAttributes from './use-passthrough-attributes'; import './editor.scss'; function ButtonEdit( { attributes, backgroundColor, className, + clientId, fallbackBackgroundColor, fallbackTextColor, setAttributes, @@ -37,6 +39,8 @@ function ButtonEdit( { } ) { const { borderRadius, element, placeholder, text } = attributes; + usePassthroughAttributes( { attributes, clientId, setAttributes } ); + const onChange = value => { // TODO: Remove `replace` once minimum Gutenberg version is 8.0 (to fully support `disableLineBreaks`) const newValue = 'input' === element ? value.replace( /
/gim, ' ' ) : value; diff --git a/extensions/blocks/button/use-passthrough-attributes.js b/extensions/blocks/button/use-passthrough-attributes.js new file mode 100644 index 0000000000000..5a96cf2022da9 --- /dev/null +++ b/extensions/blocks/button/use-passthrough-attributes.js @@ -0,0 +1,40 @@ +/** + * External dependencies + */ +import { isEmpty, mapValues, pickBy } from 'lodash'; + +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { useEffect } from '@wordpress/element'; + +export default function usePassthroughAttributes( { attributes, clientId, setAttributes } ) { + // `passthroughAttributes` is a map of child/parent attribute names, + // to indicate which parent attribute values will be injected into which child attributes. + // E.g. { childAttribute: 'parentAttribute' } + const { passthroughAttributes } = attributes; + + const { attributesToSync } = useSelect( select => { + const { getBlockAttributes, getBlockHierarchyRootClientId } = select( 'core/block-editor' ); + const parentAttributes = getBlockAttributes( getBlockHierarchyRootClientId( clientId ) ); + + // Here we actually map the parent attribute value to the child attribute. + // E.g. { childAttribute: 'foobar' } + const mappedAttributes = mapValues( passthroughAttributes, key => parentAttributes[ key ] ); + + // Discard all equals attributes + const validAttributes = pickBy( + mappedAttributes, + ( value, key ) => value !== attributes[ key ] + ); + + return { attributesToSync: validAttributes }; + } ); + + useEffect( () => { + if ( ! isEmpty( attributesToSync ) ) { + setAttributes( attributesToSync ); + } + }, [ attributesToSync, setAttributes ] ); +}