You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

古腾堡编辑器自定义区块:如何仅在创建时设置postDate

问题

我正在为WordPress古腾堡编辑器开发一款自定义区块,用于展示并保存内容与日期。原本打算通过postDate属性保存每个区块的创建日期,虽然能通过save函数成功保存,但所有区块的postDate都是第一个区块的创建日期,无法随新区块更新。

需求是:仅在区块创建时设置一次postDate,后续编辑不可修改该值。工作流程为用户创建区块时保存postDate;创建新区块时重复流程,每个区块拥有唯一日期。

之前尝试在useEffect的!blockId条件中设置postDate,但会导致每次渲染都更新值,请问应该在何处调用setAttribute设置postDate以实现仅创建时更新?

原代码如下:

registerBlockType(metadata.name, {
    attributes: {
        content: {
            type: "string",
            source: "html",
            selector: "h2",
        },
        postDate: {
            type: "string",
            default: moment().tz("Europe/Paris").locale("fr").format(), 
        },
        blockId: {
            type: "string",
        },
    },

    edit({ attributes, setAttributes, clientId }) {
        const blockProps = useBlockProps();

        const { postDate, blockId } = attributes;

        React.useEffect(() => {
            if (!blockId) {
                setAttributes({ blockId: clientId });
            }
        }, []);


        const TEMPLATE = [["core/paragraph", {}]];

        const ALLOWED_BLOCKS = useMemo(
            () =>
                wp.blocks
                    .getBlockTypes()
                    .filter((block) => block.name !== metadata.name)
                    .map((block) => block.name),
            [metadata.name]
        );
        
        return (
            <div className="wp-post-live-block">
                <time dateTime={postDate}>
                    {moment(postDate).format("D/M H:mm:ss")}
                </time>
                <RichText
                    {...blockProps}
                    tagName="h2"
                    value={attributes.content}
                    onChange={(content) => setAttributes({ content })}
                    placeholder={__("Add title")}
                />
                <InnerBlocks template={TEMPLATE} allowedBlocks={ALLOWED_BLOCKS} />
            </div>
        );
    },

    save({ attributes }) {
        const blockProps = useBlockProps.save();
        const { postDate, blockId } = attributes;

        return (
            <div data-timestamp={postDate} id={blockId} className="wp-post-live-block">
                <RichText.Content
                    {...blockProps}
                    tagName="h2"
                    value={attributes.content}
                />
                <InnerBlocks.Content />
            </div>
        );
    },
});

解决方案

核心问题分析

你当前的postDate属性在定义时设置了default值,这个值是在区块注册阶段(registerBlockType执行时)就计算完成的,而不是每个区块实例创建时动态生成。所以所有新创建的区块都会复用这个初始计算的日期,导致所有区块日期一致。

实现步骤

  1. 移除postDate的默认值:将postDate的default配置删除,让其默认值为undefined,这样可以区分区块是新创建的还是已存在的。
  2. 在useEffect中判断并设置日期:结合postDate是否存在以及blockId的初始化逻辑,确保只在区块首次创建时设置一次日期。同时要正确设置useEffect的依赖项,避免重复执行。

修改后的代码

registerBlockType(metadata.name, {
    attributes: {
        content: {
            type: "string",
            source: "html",
            selector: "h2",
        },
        postDate: {
            type: "string",
            // 移除默认值,让新创建的区块postDate为undefined
        },
        blockId: {
            type: "string",
        },
    },

    edit({ attributes, setAttributes, clientId }) {
        const blockProps = useBlockProps();
        const { postDate, blockId } = attributes;

        React.useEffect(() => {
            // 仅当区块是新创建(无postDate且无blockId)时执行
            if (!blockId && !postDate) {
                setAttributes({
                    blockId: clientId,
                    postDate: moment().tz("Europe/Paris").locale("fr").format()
                });
            }
        }, [blockId, postDate, clientId, setAttributes]); // 添加必要依赖项

        const TEMPLATE = [["core/paragraph", {}]];

        const ALLOWED_BLOCKS = useMemo(
            () =>
                wp.blocks
                    .getBlockTypes()
                    .filter((block) => block.name !== metadata.name)
                    .map((block) => block.name),
            [metadata.name]
        );
        
        return (
            <div className="wp-post-live-block">
                <time dateTime={postDate}>
                    {moment(postDate).format("D/M H:mm:ss")}
                </time>
                <RichText
                    {...blockProps}
                    tagName="h2"
                    value={attributes.content}
                    onChange={(content) => setAttributes({ content })}
                    placeholder={__("Add title")}
                />
                <InnerBlocks template={TEMPLATE} allowedBlocks={ALLOWED_BLOCKS} />
            </div>
        );
    },

    save({ attributes }) {
        const blockProps = useBlockProps.save();
        const { postDate, blockId } = attributes;

        return (
            <div data-timestamp={postDate} id={blockId} className="wp-post-live-block">
                <RichText.Content
                    {...blockProps}
                    tagName="h2"
                    value={attributes.content}
                />
                <InnerBlocks.Content />
            </div>
        );
    },
});

额外说明

  • 依赖项中加入blockId、postDate、clientId和setAttributes,确保useEffect仅在这些值变化时触发,避免不必要的渲染。
  • 同时判断!blockId和!postDate,确保只有全新的区块才会设置日期,已保存过的区块不会被修改。

内容的提问来源于stack exchange,提问作者MrFacundo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 21:12:50