如何将ACF字段用作自定义Gutenberg块属性并保持数据自动更新?
核心解决思路
你当前的问题根源是把元数据作为静态属性固化到了Gutenberg块的存储内容(文章post_content字段)中,自然不会跟随ACF字段更新。对于不需要在块内编辑、需要跟随外部数据实时同步的内容,统一使用动态渲染块实现即可。
具体修改步骤
1. 修改PHP块注册逻辑
移除块注册时的固定属性传值,改用render_callback实时拉取ACF字段输出前端内容,同时将块设置为动态模式:
function registerBlocks() { wp_register_script( 'domain/opening-paragraph-editor', asset('scripts/opening-paragraph.editor.js')->uri(), ['sage/vendor.js'] ); wp_register_style( 'domain/opening-paragraph', asset('styles/opening-paragraph.css')->uri() ); register_block_type( 'domain/lead-project', [ 'api_version' => 2, 'editor_script' => 'domain/opening-paragraph-editor', 'editor_style' => 'domain/opening-paragraph', 'render_callback' => function($block_attributes, $content) { wp_enqueue_style('domain/opening-paragraph'); // 实时拉取最新ACF值 $post_id = get_the_ID(); $projectClient = get_field('project_client', $post_id) ?: ''; $projectDateStart = get_field('project_dates_start', $post_id); $projectDateEnd = get_field('project_dates_end', $post_id); $projectDate = $projectDateStart ? $projectDateStart . ($projectDateEnd ? ' – ' . $projectDateEnd : '') : ''; $projectLocation = get_field('project_location', $post_id) ?: ''; // 组装输出结构 ob_start(); ?> <div class="wp-block-domain-lead-project"> <div class="wp-block-domain-lead-project__wrap"> <div class="wp-block-domain-lead-project__inner"> <?php echo $content; // 输出InnerBlocks存储的段落内容 ?> </div> <div class="wp-block-domain-lead-project__summary"> <p><?php echo esc_html($projectClient); ?></p> <p><?php echo esc_html($projectDate); ?></p> <p><?php echo esc_html($projectLocation); ?></p> </div> </div> </div> <?php return ob_get_clean(); } ] ); } add_action('init', 'registerBlocks');
2. 修改JS编辑器逻辑
移除元数据相关的属性定义,改为直接读取当前文章的元数据用于编辑器内预览,不需要将值存储到块属性中:
import React from 'react'; import {__} from '@wordpress/i18n'; import {registerBlockType} from '@wordpress/blocks'; import {InnerBlocks, useBlockProps} from '@wordpress/block-editor'; import { useEntityProp } from '@wordpress/core-data'; const ALLOWED_BLOCKS = ['core/paragraph']; const TEMPLATE = [ ['core/paragraph', { className: 'lead' }], ['core/paragraph'] ]; registerBlockType('domain/lead-project', { apiVersion: 2, title: __('Lead Project'), description: __('Opening lead paragraph with project meta block.'), icon: 'editor-paragraph', category: 'text', edit: () => { const blockProps = useBlockProps(); // 直接读取当前文章的元数据 const [meta] = useEntityProp('postType', 'project', 'meta'); const projectClient = meta?.project_client || ''; const projectDateStart = meta?.project_dates_start || ''; const projectDateEnd = meta?.project_dates_end || ''; const projectDate = projectDateStart ? `${projectDateStart}${projectDateEnd ? ' – ' + projectDateEnd : ''}` : ''; const projectLocation = meta?.project_location || ''; return ( <div { ...blockProps }> <div className="wp-block-domain-lead-project__wrap"> <div className="wp-block-domain-lead-project__inner"> <InnerBlocks allowedBlocks={ALLOWED_BLOCKS} template={TEMPLATE} templateLock="all" /> </div> <div className="wp-block-domain-lead-project__summary"> <p>{projectClient}</p> <p>{projectDate}</p> <p>{projectLocation}</p> </div> </div> </div> ); }, // 仅存储可编辑的段落内容 save: () => { return <InnerBlocks.Content />; } });
3. 简化块模板定义
移除模板中的属性传值,避免版本不匹配提示:
function registerBlockTemplates() { $post_id = isset($_GET['post']) ? $_GET['post'] : null; if (get_post_type($post_id) == 'project') { $project_object = get_post_type_object('project'); $project_object->template = [ ['domain/lead-project'], ['domain/inner-blocks'] ]; $project_object->template_lock = 'all'; } } add_action('init', 'registerBlockTemplates', 999, 0);
方案优势
- 前端和编辑器展示的元数据永远和ACF字段实时同步,不需要额外更新逻辑
- 块存储内容只保留可编辑的段落内容,无冗余数据,不会出现模板不匹配提示
- ACF字段的修改不需要同步更新块存储内容,完全解耦
- 完全保留你需要的HTML结构自定义能力
内容的提问来源于stack exchange,提问作者Twansparant
相关产品推荐
相关产品推荐

