Skip to content

Commit

Permalink
Block Bindings: Use post meta label from register_meta in block bin…
Browse files Browse the repository at this point in the history
…dings workflows (#65099)

* Initial commit. Add meta field to post types.

* Add post meta

* Add todos

* Add fields in all postType

* WIP: Add first version to link templates and entities

* Revert "WIP: Add first version to link templates and entities"

This reverts commit a43e391.

* Only expose public fields

* Add subtype to meta properties

* Render the appropriate fields depending on the postType in templates

* Use context postType when available

* Fetch the data on render, preventing one click needed

* Yoda conditions..

* Try: Expose registered meta fields in schema

* Try: Create a resolver to get registered post meta

* Use rest namespace

* Move actions and selectors to private.

* Merge useSelect

* Fix duplicated

* Add object_subtype to schema

* Update docs to object_subtype

* Add explanatory comment

* Block Bindings: Use default values in connected custom fields in templates (#65128)

* Abstract `getMetadata`  and use it in `getValues`

* Adapt e2e tests

* Update e2e

---------

Co-authored-by: SantosGuillamot <santosguillamot@git.wordpress.org>
Co-authored-by: cbravobernal <cbravobernal@git.wordpress.org>
Co-authored-by: gziolo <gziolo@git.wordpress.org>
Co-authored-by: mtias <matveb@git.wordpress.org>

* Try removing all object subtype

* Fix e2e

* Update code

* Fix `useSelect` warning

* Remove old comment

* Remove support for generic templates

* Revert changes to e2e tests

* Change the value returned by `getFieldsList` to include label

* Use label in bindings panel

* Use label in rich text placeholders

* Add filter to include `label`

* Use title instead of label in schema

* Add safety check

* Adapt branch after rebase

* Remove extra spaces

* Don't rely on key outside of post meta

* Remove key from bindings component

* Read title instead of label

* Add backport to changelog

* Update translator comment

---------
Unlinked contributors: dannyreaktiv.

Co-authored-by: cbravobernal <cbravobernal@git.wordpress.org>
Co-authored-by: SantosGuillamot <santosguillamot@git.wordpress.org>
Co-authored-by: gziolo <gziolo@git.wordpress.org>
Co-authored-by: mtias <matveb@git.wordpress.org>
  • Loading branch information
5 people committed Sep 18, 2024
1 parent 2607bd3 commit c754c78
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 28 deletions.
3 changes: 3 additions & 0 deletions backport-changelog/6.7/7298.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
https://github.com/WordPress/wordpress-develop/pull/7298

* https://github.com/WordPress/gutenberg/pull/65099
32 changes: 32 additions & 0 deletions lib/compat/wordpress-6.7/block-bindings.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,35 @@ function gutenberg_add_can_update_block_bindings_editor_setting( $editor_setting
}

add_filter( 'block_editor_settings_all', 'gutenberg_add_can_update_block_bindings_editor_setting', 10 );

/**
* Add `label` to `register_meta`.
*
* @param array $args Array of arguments for registering meta.
* @return array Modified arguments array including `label`.
*/
function gutenberg_update_meta_args_with_label( $args ) {
// Don't update schema when label isn't provided.
if ( ! isset( $args['label'] ) ) {
return $args;
}

$schema = array( 'title' => $args['label'] );
if ( ! is_array( $args['show_in_rest'] ) ) {
$args['show_in_rest'] = array(
'schema' => $schema,
);
return $args;
}

if ( ! empty( $args['show_in_rest']['schema'] ) ) {
$args['show_in_rest']['schema'] = array_merge( $args['show_in_rest']['schema'], $schema );
} else {
$args['show_in_rest']['schema'] = $schema;
}

return $args;
}

// Priority must be lower than 10 to ensure the label is not removed.
add_filter( 'register_meta_args', 'gutenberg_update_meta_args_with_label', 5, 1 );
25 changes: 20 additions & 5 deletions packages/block-editor/src/components/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export function RichTextWrapper(
const { clientId, isSelected: isBlockSelected, name: blockName } = context;
const blockBindings = context[ blockBindingsKey ];
const blockContext = useContext( BlockContext );
const registry = useRegistry();
const selector = ( select ) => {
// Avoid subscribing to the block editor store if the block is not
// selected.
Expand Down Expand Up @@ -178,6 +179,10 @@ export function RichTextWrapper(
const blockBindingsSource = getBlockBindingsSource(
relatedBinding.source
);
const fieldsList = blockBindingsSource?.getFieldsList?.( {
registry,
context: blockContext,
} );

const _disableBoundBlock =
! blockBindingsSource?.canUserEditValue?.( {
Expand All @@ -186,12 +191,16 @@ export function RichTextWrapper(
args: relatedBinding.args,
} );

const bindingKey =
fieldsList?.[ relatedBinding?.args?.key ]?.label ??
blockBindingsSource?.label;

const _bindingsPlaceholder = _disableBoundBlock
? relatedBinding?.args?.key || blockBindingsSource?.label
? bindingKey
: sprintf(
/* translators: %s: source label or key */
/* translators: %s: connected field label or source label */
__( 'Add %s' ),
relatedBinding?.args?.key || blockBindingsSource?.label
bindingKey
);

return {
Expand All @@ -201,7 +210,14 @@ export function RichTextWrapper(
_bindingsPlaceholder,
};
},
[ blockBindings, identifier, blockName, blockContext, adjustedValue ]
[
blockBindings,
identifier,
blockName,
blockContext,
registry,
adjustedValue,
]
);

const shouldDisableEditing = readOnly || disableBoundBlock;
Expand Down Expand Up @@ -371,7 +387,6 @@ export function RichTextWrapper(
element.focus();
}

const registry = useRegistry();
const TagName = tagName;
return (
<>
Expand Down
17 changes: 11 additions & 6 deletions packages/block-editor/src/hooks/block-bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function BlockBindingsPanelDropdown( { fieldsList, attribute, binding } ) {
{ registeredSources[ name ].label }
</DropdownMenuV2.GroupLabel>
) }
{ Object.entries( fields ).map( ( [ key, value ] ) => (
{ Object.entries( fields ).map( ( [ key, args ] ) => (
<DropdownMenuV2.RadioItem
key={ key }
onChange={ () =>
Expand All @@ -77,10 +77,10 @@ function BlockBindingsPanelDropdown( { fieldsList, attribute, binding } ) {
checked={ key === currentKey }
>
<DropdownMenuV2.ItemLabel>
{ key }
{ args?.label }
</DropdownMenuV2.ItemLabel>
<DropdownMenuV2.ItemHelpText>
{ value }
{ args?.value }
</DropdownMenuV2.ItemHelpText>
</DropdownMenuV2.RadioItem>
) ) }
Expand All @@ -94,7 +94,7 @@ function BlockBindingsPanelDropdown( { fieldsList, attribute, binding } ) {
);
}

function BlockBindingsAttribute( { attribute, binding } ) {
function BlockBindingsAttribute( { attribute, binding, fieldsList } ) {
const { source: sourceName, args } = binding || {};
const sourceProps =
unlock( blocksPrivateApis ).getBlockBindingsSource( sourceName );
Expand All @@ -110,21 +110,24 @@ function BlockBindingsAttribute( { attribute, binding } ) {
>
{ isSourceInvalid
? __( 'Invalid source' )
: args?.key || sourceProps?.label || sourceName }
: fieldsList?.[ sourceName ]?.[ args?.key ]?.label ||
sourceProps?.label ||
sourceName }
</Text>
) }
</VStack>
);
}

function ReadOnlyBlockBindingsPanelItems( { bindings } ) {
function ReadOnlyBlockBindingsPanelItems( { bindings, fieldsList } ) {
return (
<>
{ Object.entries( bindings ).map( ( [ attribute, binding ] ) => (
<Item key={ attribute }>
<BlockBindingsAttribute
attribute={ attribute }
binding={ binding }
fieldsList={ fieldsList }
/>
</Item>
) ) }
Expand Down Expand Up @@ -164,6 +167,7 @@ function EditableBlockBindingsPanelItems( {
<BlockBindingsAttribute
attribute={ attribute }
binding={ binding }
fieldsList={ fieldsList }
/>
</Item>
}
Expand Down Expand Up @@ -276,6 +280,7 @@ export const BlockBindingsPanel = ( { name: blockName, metadata } ) => {
{ readOnly ? (
<ReadOnlyBlockBindingsPanelItems
bindings={ filteredBindings }
fieldsList={ fieldsList }
/>
) : (
<EditableBlockBindingsPanelItems
Expand Down
54 changes: 37 additions & 17 deletions packages/editor/src/bindings/post-meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,20 @@ import { store as coreDataStore } from '@wordpress/core-data';
import { store as editorStore } from '../store';
import { unlock } from '../lock-unlock';

function getMetadata( registry, context ) {
function getMetadata( registry, context, registeredFields ) {
let metaFields = {};
const { type } = registry.select( editorStore ).getCurrentPost();
const { getEditedEntityRecord } = registry.select( coreDataStore );
const { getRegisteredPostMeta } = unlock(
registry.select( coreDataStore )
);

if ( type === 'wp_template' ) {
const fields = getRegisteredPostMeta( context?.postType );
// Populate the `metaFields` object with the default values.
Object.entries( fields || {} ).forEach( ( [ key, props ] ) => {
metaFields[ key ] = props.default;
} );
Object.entries( registeredFields || {} ).forEach(
( [ key, props ] ) => {
if ( props.default ) {
metaFields[ key ] = props.default;
}
}
);
} else {
metaFields = getEditedEntityRecord(
'postType',
Expand All @@ -37,13 +37,20 @@ function getMetadata( registry, context ) {
export default {
name: 'core/post-meta',
getValues( { registry, context, bindings } ) {
const metaFields = getMetadata( registry, context );
const { getRegisteredPostMeta } = unlock(
registry.select( coreDataStore )
);
const registeredFields = getRegisteredPostMeta( context?.postType );
const metaFields = getMetadata( registry, context, registeredFields );

const newValues = {};
for ( const [ attributeName, source ] of Object.entries( bindings ) ) {
// Use the key if the value is not set.
// Use the value, the field label, or the field key.
const metaKey = source.args.key;
newValues[ attributeName ] =
metaFields?.[ source.args.key ] ?? source.args.key;
metaFields?.[ metaKey ] ??
registeredFields?.[ metaKey ]?.title ??
metaKey;
}
return newValues;
},
Expand Down Expand Up @@ -103,18 +110,31 @@ export default {
return true;
},
getFieldsList( { registry, context } ) {
const metaFields = getMetadata( registry, context );
const { getRegisteredPostMeta } = unlock(
registry.select( coreDataStore )
);
const registeredFields = getRegisteredPostMeta( context?.postType );
const metaFields = getMetadata( registry, context, registeredFields );

if ( ! metaFields || ! Object.keys( metaFields ).length ) {
return null;
}

// Remove footnotes or private keys from the list of fields.
// TODO: Remove this once we retrieve the fields from 'types' endpoint in post or page editor.
return Object.fromEntries(
Object.entries( metaFields ).filter(
( [ key ] ) => key !== 'footnotes' && key.charAt( 0 ) !== '_'
)
Object.entries( metaFields )
// Remove footnotes or private keys from the list of fields.
.filter(
( [ key ] ) =>
key !== 'footnotes' && key.charAt( 0 ) !== '_'
)
// Return object with label and value.
.map( ( [ key, value ] ) => [
key,
{
label: registeredFields?.[ key ]?.title || key,
value,
},
] )
);
},
};

0 comments on commit c754c78

Please sign in to comment.