Custom block type on Gutenberg Editor, setting and saving values on block creation.

huangapple go评论56阅读模式
英文:

Custom block type on Gutemberg Editor, setting and saving values on block creation

问题

我理解你的问题。你想知道如何在 WordPress Gutenberg 编辑器的自定义块类型中,只在块创建时更新 postDate 属性,而不是在每次渲染时都更新。你可以尝试在块编辑函数 edit 中使用 useState 来实现这一目标。

edit 函数中,你可以使用 useState 来追踪是否已经更新了 postDate 属性。以下是一个示例代码片段,说明如何实现这一点:

import { useState, useEffect } from 'react';

// 在 edit 函数中定义一个状态变量来追踪是否已更新 postDate
const [postDateUpdated, setPostDateUpdated] = useState(false);

// 在 useEffect 中检查是否需要更新 postDate
useEffect(() => {
  if (!postDateUpdated) {
    // 更新 postDate
    setAttributes({ postDate: yourUpdatedPostDateValue });
    // 将 postDateUpdated 设置为 true,以便不再更新
    setPostDateUpdated(true);
  }
}, [postDateUpdated]);

// 然后你可以在返回的 JSX 中使用 postDate 属性

请确保替换 yourUpdatedPostDateValue 为你想要的 postDate 值。这样,postDate 只会在块创建时更新一次,并在后续的编辑中保持不变。

英文:

I am working on a custom block type for the WordPress Gutemberg editor.

The block type displays and saves content and a date.

Custom block type on Gutenberg Editor, setting and saving values on block creation.

I'm trying to save the creation date for every block by setting a postDate value on the block type attributes. And I could successfully save this value using the save function.

However, the value is not updated on every block creation, it stays the same and every block has the same postDate value (the creation of the first block) passed to the database.

I need it to be updated so it can be saved in the "save" function. It needs to be updated only once, when a block is created.

This is the workflow I'm trying to achieve:

User creates a block / user edits the block / edits and hits the "Update" button (preferably the first option) -> postDate for that block is saved only once

User creates a different block -> same process occurs. Each block has its postDate value saved. The value can not be altered by subsequent edits

here is the function:

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>
		);
	},
});

I've tried setting the postDate value on the useEffect tool, inside the if (!blockId) condition. However, this makes the function try to update the value on every render.

Where can I hook the setAttribute(postDate) so that it updates only once, when the block is created?

答案1

得分: 1

你的代码实际上非常接近了!postDate 属性应该是一个安全的默认值为“空字符串”以表示日期时间,而不是当前时间。通过使用空字符串,edit() 函数可以确定是否先前设置了日期,如果没有,则设置它。

第二部分是 save() 函数,其中你有 data-timestamp 用于时间戳,但这并没有正确配置到 postDate 属性上。通过设置正确的选择器和 postDate 属性,保存的时间戳将会被使用,而不会每次都重新创建,例如:

JS

registerBlockType(metadata.name, {
    attributes: {
        content: {
            type: "string",
            source: "html",
            selector: "h2",
        },
        postDate: {
            type: "string",
            source: "attribute",
            selector: "div",
            attribute: "data-timestamp", // 时间值的来源
            default: "" // 安全的默认值
        }
        // 移除了 blockId
    },

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

        const { postDate, content } = attributes;

        React.useEffect(() => {
            // 默认为空字符串,因此在添加块时将设置时间
            if (postDate === "") { 
                setAttributes({ postDate: moment().tz("Europe/Paris").locale("fr").format() });
            }
        }, [postDate]); // 观察 postDate,在保存后它不会为空,所以会是块被添加时的初始时间

        // 其他代码...

        return (
            <div {...blockProps}>
                <time dateTime={postDate}>
                    {moment(postDate).format("D/M H:mm:ss")}
                </time>
                <RichText
                    tagName="h2"
                    value={attributes.content}
                    onChange={(content) => setAttributes({ content })}
                    placeholder={__("Add title")}
                />
                {/* 其他代码... */}
            </div>
        );
    },

    save({ attributes }) {
        const blockProps = useBlockProps.save({className: 'wp-post-live-block'}); // 为 blockProps 添加 className
        const { postDate, content } = attributes;

        return (
            <div data-timestamp={postDate} {...blockProps}>
                <RichText.Content
                    tagName="h2"
                    value={content}
                />
                {/* 其他代码... */}
            </div>
        );
    },
});

注意:已删除与问题无关的 InnerBlocks 相关的代码,以便更容易看到使日期时间工作的更改。

英文:

Your code is actually very close! The postDate attribute should be a safe default "empty string" for the datetime, not the current time. By using an empty string, the edit() function can determine if a date was previously set and if not, set it.

The second part is the save() function, where you have the data-timestamp for the timestamp, but this is not properly configured to the postDate attribute. By setting the correct selector and attribute for postDate, the saved timestamp will be used and not recreated each time, eg:

JS

registerBlockType(metadata.name, {
    attributes: {
        content: {
            type: &quot;string&quot;,
            source: &quot;html&quot;,
            selector: &quot;h2&quot;,
        },
        postDate: {
            type: &quot;string&quot;,
            source: &quot;attribute&quot;,
            selector: &quot;div&quot;,
            attribute: &quot;data-timestamp&quot;, // source of datetime value
            default: &quot;&quot; // safe default 
        }
        // Removed blockId
    },

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

        const { postDate, content } = attributes;

        React.useEffect(() =&gt; {
			// Default is empty string, so the time will be set when block is added
			if (postDate === &quot;&quot;) { 
				setAttributes({ postDate: moment().tz(&quot;Europe/Paris&quot;).locale(&quot;fr&quot;).format() });
			}
		}, [postDate]); // Watch postDate, which after being saved, won&#39;t be empty so will be initial time block was added

		...
        
        return (
            &lt;div {...blockProps}&gt;
                &lt;time dateTime={postDate}&gt;
                    {moment(postDate).format(&quot;D/M H:mm:ss&quot;)}
                &lt;/time&gt;
                &lt;RichText
                    tagName=&quot;h2&quot;
                    value={attributes.content}
                    onChange={(content) =&gt; setAttributes({ content })}
                    placeholder={__(&quot;Add title&quot;)}
                /&gt;
                ...
            &lt;/div&gt;
        );
    },

    save({ attributes }) {
        const blockProps = useBlockProps.save({className: &#39;wp-post-live-block&#39;}); // Add className to blockProps
        const { postDate, content } = attributes;

        return (
            &lt;div data-timestamp={postDate} {...blockProps}&gt;
                &lt;RichText.Content
                    tagName=&quot;h2&quot;
                    value={content}
                /&gt;
                ...
            &lt;/div&gt;
        );
    },
});

NB. Removed the InnerBlocks related code unrelated to the issue so the changes to enable datetime to work are easier to see.

huangapple
  • 本文由 发表于 2023年5月25日 18:37:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76331360.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定