英文:
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.
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: "string",
source: "html",
selector: "h2",
},
postDate: {
type: "string",
source: "attribute",
selector: "div",
attribute: "data-timestamp", // source of datetime value
default: "" // safe default
}
// Removed blockId
},
edit({ attributes, setAttributes, clientId }) {
const blockProps = useBlockProps();
const { postDate, content } = attributes;
React.useEffect(() => {
// Default is empty string, so the time will be set when block is added
if (postDate === "") {
setAttributes({ postDate: moment().tz("Europe/Paris").locale("fr").format() });
}
}, [postDate]); // Watch postDate, which after being saved, won't be empty so will be initial time block was added
...
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'}); // Add className to blockProps
const { postDate, content } = attributes;
return (
<div data-timestamp={postDate} {...blockProps}>
<RichText.Content
tagName="h2"
value={content}
/>
...
</div>
);
},
});
NB. Removed the InnerBlocks related code unrelated to the issue so the changes to enable datetime to work are easier to see.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论