diff --git a/backport-changelog/6.7/7298.md b/backport-changelog/6.7/7298.md
new file mode 100644
index 0000000000000..4c01ef5d4f46e
--- /dev/null
+++ b/backport-changelog/6.7/7298.md
@@ -0,0 +1,3 @@
+https://github.com/WordPress/wordpress-develop/pull/7298
+
+* https://github.com/WordPress/gutenberg/pull/65099
\ No newline at end of file
diff --git a/lib/compat/wordpress-6.7/block-bindings.php b/lib/compat/wordpress-6.7/block-bindings.php
index 9e82c1843f35a..a8f68c0f0f04e 100644
--- a/lib/compat/wordpress-6.7/block-bindings.php
+++ b/lib/compat/wordpress-6.7/block-bindings.php
@@ -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 );
diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js
index 732b8dbf2c089..387f388b8fdad 100644
--- a/packages/block-editor/src/components/rich-text/index.js
+++ b/packages/block-editor/src/components/rich-text/index.js
@@ -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.
@@ -178,6 +179,10 @@ export function RichTextWrapper(
const blockBindingsSource = getBlockBindingsSource(
relatedBinding.source
);
+ const fieldsList = blockBindingsSource?.getFieldsList?.( {
+ registry,
+ context: blockContext,
+ } );
const _disableBoundBlock =
! blockBindingsSource?.canUserEditValue?.( {
@@ -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 {
@@ -201,7 +210,14 @@ export function RichTextWrapper(
_bindingsPlaceholder,
};
},
- [ blockBindings, identifier, blockName, blockContext, adjustedValue ]
+ [
+ blockBindings,
+ identifier,
+ blockName,
+ blockContext,
+ registry,
+ adjustedValue,
+ ]
);
const shouldDisableEditing = readOnly || disableBoundBlock;
@@ -371,7 +387,6 @@ export function RichTextWrapper(
element.focus();
}
- const registry = useRegistry();
const TagName = tagName;
return (
<>
diff --git a/packages/block-editor/src/hooks/block-bindings.js b/packages/block-editor/src/hooks/block-bindings.js
index a0bd8820d36c5..33284b4cd27fd 100644
--- a/packages/block-editor/src/hooks/block-bindings.js
+++ b/packages/block-editor/src/hooks/block-bindings.js
@@ -61,7 +61,7 @@ function BlockBindingsPanelDropdown( { fieldsList, attribute, binding } ) {
{ registeredSources[ name ].label }
) }
- { Object.entries( fields ).map( ( [ key, value ] ) => (
+ { Object.entries( fields ).map( ( [ key, args ] ) => (
@@ -77,10 +77,10 @@ function BlockBindingsPanelDropdown( { fieldsList, attribute, binding } ) {
checked={ key === currentKey }
>
- { key }
+ { args?.label }
- { value }
+ { args?.value }
) ) }
@@ -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 );
@@ -110,14 +110,16 @@ function BlockBindingsAttribute( { attribute, binding } ) {
>
{ isSourceInvalid
? __( 'Invalid source' )
- : args?.key || sourceProps?.label || sourceName }
+ : fieldsList?.[ sourceName ]?.[ args?.key ]?.label ||
+ sourceProps?.label ||
+ sourceName }
) }
);
}
-function ReadOnlyBlockBindingsPanelItems( { bindings } ) {
+function ReadOnlyBlockBindingsPanelItems( { bindings, fieldsList } ) {
return (
<>
{ Object.entries( bindings ).map( ( [ attribute, binding ] ) => (
@@ -125,6 +127,7 @@ function ReadOnlyBlockBindingsPanelItems( { bindings } ) {
) ) }
@@ -164,6 +167,7 @@ function EditableBlockBindingsPanelItems( {
}
@@ -276,6 +280,7 @@ export const BlockBindingsPanel = ( { name: blockName, metadata } ) => {
{ readOnly ? (
) : (
{
- metaFields[ key ] = props.default;
- } );
+ Object.entries( registeredFields || {} ).forEach(
+ ( [ key, props ] ) => {
+ if ( props.default ) {
+ metaFields[ key ] = props.default;
+ }
+ }
+ );
} else {
metaFields = getEditedEntityRecord(
'postType',
@@ -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;
},
@@ -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,
+ },
+ ] )
);
},
};