From e8ce954f6c0d5f2cb3dfcbd9bf717505a4a99d66 Mon Sep 17 00:00:00 2001 From: Carlos Bravo <37012961+cbravobernal@users.noreply.github.com> Date: Fri, 6 Jun 2025 18:01:29 +0200 Subject: [PATCH 1/3] Add editor preview to acf-field --- assets/src/js/bindings/index.js | 1 + assets/src/js/bindings/sources.js | 79 +++++++++++++++++++++++++++++++ includes/Blocks/Bindings.php | 42 +++++++++++++--- includes/assets.php | 9 ++++ webpack.config.js | 4 +- 5 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 assets/src/js/bindings/index.js create mode 100644 assets/src/js/bindings/sources.js diff --git a/assets/src/js/bindings/index.js b/assets/src/js/bindings/index.js new file mode 100644 index 00000000..278d4879 --- /dev/null +++ b/assets/src/js/bindings/index.js @@ -0,0 +1 @@ +import './sources.js'; diff --git a/assets/src/js/bindings/sources.js b/assets/src/js/bindings/sources.js new file mode 100644 index 00000000..979c17f9 --- /dev/null +++ b/assets/src/js/bindings/sources.js @@ -0,0 +1,79 @@ +/** + * WordPress dependencies. + */ +import { __ } from '@wordpress/i18n'; +import { registerBlockBindingsSource } from '@wordpress/blocks'; +import { store as coreDataStore } from '@wordpress/core-data'; + +/** + * Get the value of a specific field from the ACF fields. + * + * @param {Object} fields The ACF fields object. + * @param {string} fieldName The name of the field to retrieve. + * @returns {string} The value of the specified field, or undefined if not found. + */ +const getFieldValue = ( fields, fieldName ) => fields?.acf?.[ fieldName ]; + +const resolveImageAttribute = ( imageObj, attribute ) => { + if ( ! imageObj ) return ''; + switch ( attribute ) { + case 'url': + case 'content': + return imageObj.source_url; + case 'alt': + return imageObj.alt_text || ''; + case 'title': + return imageObj.title?.rendered || ''; + default: + return ''; + } +}; + +registerBlockBindingsSource( { + name: 'acf/field', + label: 'SCF Fields', + getValues( { context, bindings, select } ) { + const { getEditedEntityRecord, getMedia } = select( coreDataStore ); + let fields = + context?.postType && context?.postId + ? getEditedEntityRecord( + 'postType', + context.postType, + context.postId + ) + : undefined; + const result = {}; + debugger; + + Object.entries( bindings ).forEach( + ( [ attribute, { args } = {} ] ) => { + const fieldName = args?.key; + + const fieldValue = getFieldValue( fields, fieldName ); + if ( typeof fieldValue === 'object' && fieldValue !== null ) { + result[ attribute ] = + ( fieldValue[ attribute ] ?? + ( attribute === 'content' && fieldValue.url ) ) || + ''; + } else if ( typeof fieldValue === 'number' ) { + if ( attribute === 'content' ) { + result[ attribute ] = fieldValue.toString() || ''; + } else { + const imageObj = getMedia( fieldValue ); + result[ attribute ] = resolveImageAttribute( + imageObj, + attribute + ); + } + } else { + result[ attribute ] = fieldValue || ''; + } + } + ); + + return result; + }, + canUserEditValue() { + return false; + }, +} ); diff --git a/includes/Blocks/Bindings.php b/includes/Blocks/Bindings.php index 921558c3..2b2cbc5d 100644 --- a/includes/Blocks/Bindings.php +++ b/includes/Blocks/Bindings.php @@ -37,6 +37,7 @@ public function register_binding_sources() { array( 'label' => _x( 'SCF Fields', 'The core SCF block binding source name for fields on the current page', 'secure-custom-fields' ), 'get_value_callback' => array( $this, 'get_value' ), + 'uses_context' => array( 'postId', 'postType' ), ) ); } @@ -78,15 +79,42 @@ public function get_value( array $source_attrs, \WP_Block $block_instance, strin } } - $value = $field['value']; + switch ( $attribute_name ) { + case 'id': + // The value is the field value. + $value = $field['value']['id'] ?? ''; + break; + case 'alt': + // The label is the field label. + $value = $field['value']['alt'] ?? ''; + break; + case 'url': + // The URL is the field value. + $value = $field['value']['url'] ?? $field['value'] ?? ''; + break; + case 'title': + // The title is the field value. + $value = $field['value']['title'] ?? ''; + break; + case 'rel': + // Handle checkbox field for rel attribute by joining array values. + if ( is_array( $field['value'] ) ) { + $value = implode( ' ', $field['value'] ); + } else { + $value = $field['value'] ?? ''; + } + break; + default: + $value = $field['value']; - if ( is_array( $value ) ) { - $value = implode( ', ', $value ); - } + if ( is_array( $value ) ) { + $value = wp_json_encode( $value ); + } - // If we're not a scalar we'd throw an error, so return early for safety. - if ( ! is_scalar( $value ) ) { - $value = null; + // Ensure we're returning a scalar value. + if ( ! is_scalar( $value ) && null !== $value ) { + $value = ''; + } } } diff --git a/includes/assets.php b/includes/assets.php index 5b166adb..e010d85a 100644 --- a/includes/assets.php +++ b/includes/assets.php @@ -189,6 +189,14 @@ public function register_scripts() { 'version' => $version, 'in_footer' => true, ), + 'scf-bindings' => array( + 'handle' => 'scf-bindings', + 'src' => acf_get_url( sprintf( $js_path_patterns['base'], 'scf-bindings' ) ), + 'asset_file' => acf_get_path( sprintf( $asset_path_patterns['base'], 'scf-bindings' ) ), + 'version' => $version, + 'deps' => array(), + 'in_footer' => true, + ), ); // Define style registrations. @@ -529,6 +537,7 @@ public function enqueue_scripts() { // @todo integrate into the above. Previously, they were simply hooked into the hook below. wp_enqueue_script( 'acf-pro-input' ); wp_enqueue_script( 'acf-pro-ui-options-page' ); + wp_enqueue_script( 'scf-bindings' ); wp_enqueue_style( 'acf-pro-input' ); /** diff --git a/webpack.config.js b/webpack.config.js index 699b7fe2..d0c06c3d 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -16,7 +16,8 @@ const commonConfig = { 'js/acf-internal-post-type': './assets/src/js/acf-internal-post-type.js', 'js/commands/scf-admin': './assets/src/js/commands/admin-commands.js', - 'js/commands/scf-custom-post-types': './assets/src/js/commands/custom-post-type-commands.js', + 'js/commands/scf-custom-post-types': + './assets/src/js/commands/custom-post-type-commands.js', 'js/acf': './assets/src/js/acf.js', 'js/pro/acf-pro-blocks': './assets/src/js/pro/acf-pro-blocks.js', 'js/pro/acf-pro-field-group': @@ -24,6 +25,7 @@ const commonConfig = { 'js/pro/acf-pro-input': './assets/src/js/pro/acf-pro-input.js', 'js/pro/acf-pro-ui-options-page': './assets/src/js/pro/acf-pro-ui-options-page.js', + 'js/scf-bindings': './assets/src/js/bindings/index.js', // CSS files 'css/acf-dark': './assets/src/sass/acf-dark.scss', From e7b46a5674d21438d5ed7f225f9a4967fef393fc Mon Sep 17 00:00:00 2001 From: Carlos Bravo <37012961+cbravobernal@users.noreply.github.com> Date: Tue, 10 Jun 2025 17:16:45 +0200 Subject: [PATCH 2/3] Follow recommendations --- assets/src/js/bindings/sources.js | 13 +++++++++---- includes/Blocks/Bindings.php | 12 +++--------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/assets/src/js/bindings/sources.js b/assets/src/js/bindings/sources.js index 979c17f9..ccd9a052 100644 --- a/assets/src/js/bindings/sources.js +++ b/assets/src/js/bindings/sources.js @@ -51,10 +51,15 @@ registerBlockBindingsSource( { const fieldValue = getFieldValue( fields, fieldName ); if ( typeof fieldValue === 'object' && fieldValue !== null ) { - result[ attribute ] = - ( fieldValue[ attribute ] ?? - ( attribute === 'content' && fieldValue.url ) ) || - ''; + let value = ''; + + if ( fieldValue[ attribute ] ) { + value = fieldValue[ attribute ]; + } else if ( attribute === 'content' && fieldValue.url ) { + value = fieldValue.url; + } + + result[ attribute ] = value; } else if ( typeof fieldValue === 'number' ) { if ( attribute === 'content' ) { result[ attribute ] = fieldValue.toString() || ''; diff --git a/includes/Blocks/Bindings.php b/includes/Blocks/Bindings.php index 2b2cbc5d..494b18dd 100644 --- a/includes/Blocks/Bindings.php +++ b/includes/Blocks/Bindings.php @@ -81,21 +81,15 @@ public function get_value( array $source_attrs, \WP_Block $block_instance, strin switch ( $attribute_name ) { case 'id': - // The value is the field value. - $value = $field['value']['id'] ?? ''; - break; case 'alt': - // The label is the field label. - $value = $field['value']['alt'] ?? ''; + case 'title': + // The value is in the field of the same name. + $value = $field['value'][ $attribute_name ] ?? ''; break; case 'url': // The URL is the field value. $value = $field['value']['url'] ?? $field['value'] ?? ''; break; - case 'title': - // The title is the field value. - $value = $field['value']['title'] ?? ''; - break; case 'rel': // Handle checkbox field for rel attribute by joining array values. if ( is_array( $field['value'] ) ) { From 61f7db5b6b2a7442c67bd9dd94ea5ac0028e7fe5 Mon Sep 17 00:00:00 2001 From: Carlos Bravo <37012961+cbravobernal@users.noreply.github.com> Date: Tue, 10 Jun 2025 17:37:36 +0200 Subject: [PATCH 3/3] More fixes --- assets/src/js/bindings/sources.js | 1 - includes/Blocks/Bindings.php | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/assets/src/js/bindings/sources.js b/assets/src/js/bindings/sources.js index ccd9a052..0dcfced6 100644 --- a/assets/src/js/bindings/sources.js +++ b/assets/src/js/bindings/sources.js @@ -43,7 +43,6 @@ registerBlockBindingsSource( { ) : undefined; const result = {}; - debugger; Object.entries( bindings ).forEach( ( [ attribute, { args } = {} ] ) => { diff --git a/includes/Blocks/Bindings.php b/includes/Blocks/Bindings.php index 494b18dd..33b56081 100644 --- a/includes/Blocks/Bindings.php +++ b/includes/Blocks/Bindings.php @@ -103,10 +103,7 @@ public function get_value( array $source_attrs, \WP_Block $block_instance, strin if ( is_array( $value ) ) { $value = wp_json_encode( $value ); - } - - // Ensure we're returning a scalar value. - if ( ! is_scalar( $value ) && null !== $value ) { + } elseif ( ! is_scalar( $value ) && null !== $value ) { $value = ''; } }