-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Try changing setBlockAttributes
to update dynamicContent
#54233
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ import { | |
switchToBlockType, | ||
synchronizeBlocksWithTemplate, | ||
getBlockSupport, | ||
store as blocksStore, | ||
} from '@wordpress/blocks'; | ||
import { speak } from '@wordpress/a11y'; | ||
import { __, _n, sprintf } from '@wordpress/i18n'; | ||
|
@@ -157,18 +158,96 @@ export function receiveBlocks( blocks ) { | |
* @param {boolean} uniqueByBlock true if each block in clientIds array has a unique set of attributes | ||
* @return {Object} Action object. | ||
*/ | ||
export function updateBlockAttributes( | ||
clientIds, | ||
attributes, | ||
uniqueByBlock = false | ||
) { | ||
return { | ||
type: 'UPDATE_BLOCK_ATTRIBUTES', | ||
clientIds: castArray( clientIds ), | ||
attributes, | ||
uniqueByBlock, | ||
export const updateBlockAttributes = | ||
( clientIds, attributes, uniqueByBlock = false ) => | ||
( { select, dispatch, registry } ) => { | ||
if ( ! window.__experimentalPatterns ) { | ||
dispatch( { | ||
type: 'UPDATE_BLOCK_ATTRIBUTES', | ||
clientIds: castArray( clientIds ), | ||
attributes, | ||
uniqueByBlock, | ||
} ); | ||
return; | ||
} | ||
|
||
const updates = {}; | ||
for ( const clientId of castArray( clientIds ) ) { | ||
const attrs = uniqueByBlock ? attributes[ clientId ] : attributes; | ||
const parentBlocks = select.getBlocksByClientId( | ||
select.getBlockParents( clientId ) | ||
); | ||
const parentPattern = parentBlocks.findLast( | ||
( parentBlock ) => parentBlock.name === 'core/block' | ||
); | ||
const block = select.getBlock( clientId ); | ||
if ( | ||
! parentPattern || | ||
! registry | ||
.select( blocksStore ) | ||
.hasBlockSupport( block.name, '__experimentalPattern' ) | ||
) { | ||
updates[ clientId ] = attrs; | ||
continue; | ||
} | ||
Comment on lines
+177
to
+192
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the explorations you and @aaronrobertshaw have worked on! Given the block bindings API is going to support a bunch of different data sources, I wonder how this can be made generic/pluggable, and done in a way where the Having read through the block bindings issue, it seems like the blocks inside the pattern will have some config denoting their connections (which I guess the pattern creator will define), which could be read here. Then there's the need to discover the source of the data for those connections, which is what happens here but somewhat hard-coded. I think maybe we're close to the point where we can try modelling those connections and abstracting the discovery of the data source that happens here. It could be that the connection 'type' determines the strategy used to find the data source (the pattern block). Or alternatively the pattern block is somehow defined as source. But we should at the same time connect back with the other data bindings work around custom fields to make sure the approach taken works in both places. Looking at the POCs so far for custom fields (#53300), the challenge is that they focus more on the PHP part as it stands. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, exactly which blocks and their attributes should be connected was still undecided. This part was just following the existing exploration in the base branch. The main goal for this PR is to find a performant and extendible way to allow override of |
||
|
||
const contentAttributes = registry | ||
.select( blocksStore ) | ||
.getBlockSupport( block.name, '__experimentalPattern' ); | ||
const dynamicContent = {}; | ||
const updatedAttributes = {}; | ||
for ( const attributeKey of Object.keys( attrs ) ) { | ||
if ( Object.hasOwn( contentAttributes, attributeKey ) ) { | ||
dynamicContent[ attributeKey ] = attrs[ attributeKey ]; | ||
} else { | ||
updatedAttributes[ attributeKey ] = attrs[ attributeKey ]; | ||
} | ||
} | ||
if ( Object.keys( dynamicContent ).length > 0 ) { | ||
let id = block.attributes.metadata?.id; | ||
if ( ! id ) { | ||
// The id just has to be unique within the pattern context, so we | ||
// use the block's clientId as a convenient unique identifier. | ||
id = block.clientId; | ||
updatedAttributes.metadata = { | ||
...block.attributes.metadata, | ||
id, | ||
}; | ||
} | ||
|
||
updates[ parentPattern.clientId ] = { | ||
dynamicContent: { | ||
...parentPattern.attributes.dynamicContent, | ||
[ id ]: dynamicContent, | ||
}, | ||
}; | ||
} | ||
if ( Object.keys( updatedAttributes ).length > 0 ) { | ||
updates[ clientId ] = updatedAttributes; | ||
} | ||
} | ||
|
||
if ( | ||
Object.values( updates ).every( | ||
( updatedAttributes, _index, arr ) => | ||
updatedAttributes === arr[ 0 ] | ||
) | ||
) { | ||
dispatch( { | ||
type: 'UPDATE_BLOCK_ATTRIBUTES', | ||
clientIds: Object.keys( updates ), | ||
attributes: Object.values( updates )[ 0 ], | ||
uniqueByBlock: false, | ||
} ); | ||
} else { | ||
dispatch( { | ||
type: 'UPDATE_BLOCK_ATTRIBUTES', | ||
clientIds: Object.keys( updates ), | ||
attributes: updates, | ||
uniqueByBlock: true, | ||
} ); | ||
} | ||
}; | ||
} | ||
|
||
/** | ||
* Action that updates the block with the specified client ID. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is interesting. I wonder if the override for attributes should also happen on the store level, similar to how modifications get applied to
updateBlockAttributes
. Otherwise, we risk that folks could omit usingattributes
passed toEdit
and get local values for dynamic content when accessing the store directly similar to what would happen when they useupdateBlockAttributes
.