创建自定义古腾堡块——第 10 部分:获取文章和高阶组件

2023/01/05
创建自定义古腾堡块——第 10 部分:获取文章和高阶组件

在 Gutenberg 自定义块教程系列的最后一部分中,我们将学习如何使用高阶组件来利用 WordPress 的组件来执行对帖子和其他核心 WordPress 信息的查询。

在上一部分中,我们了解了动态块,我们最终实现了输入帖子 ID 并使用 PHP 动态获取帖子并在前端和预览模式下呈现它的功能。手动输入帖子 ID 不直观或用户友好。最好为用户提供某种方式来通过帖子标题选择或搜索帖子,然后单击某些内容来选择一个。

解决这个问题的一部分相当容易;如何从您的区块edit功能中查询帖子。为此,我们有几个选择,最好的选择是使用 WordPress 中的一些所谓的高阶组件。您还可以使用 Javascript 浏览器方法使用例如fetch或 axios 对 WordPress REST API 执行 AJAX 调用。WordPress 实际上提供了自己的fetch:版本apiFetch()

解决这个问题的另一部分取决于你;这就是如何在我们的块中呈现列表或选项。您将如何呈现可供选择的帖子列表?在选择中,复选框或单选按钮列表?或者您想提供搜索的可能性,从而实现自动完成解决方案或过滤器解决方案?您应该允许选择多个帖子还是只选择一个?通常您可以通过使用不同的 WordPress 组件来解决这个问题,但是您需要决定要实施哪种解决方案。

让我们先了解一下高阶组件和 WordPress 数据模块,然后再了解如何在我们的块中执行后查询。

WordPress 核心数据模块和高阶组件

使用 React 时,您经常需要将状态向下传递给子组件或向上传递给公共父级组件,以便所有其他子组件都可以访问它们。解决集中应用程序状态问题的解决方案是使用Redux。使用 Redux,您可以构建存储——存储应用程序状态和信息的对象。

WordPress数据模块是不同商店的枢纽,提供管理不同模块之间数据的功能。它建立在 Redux 之上——但不要将它误认为是 WordPress 的 Redux,因为它们之间存在很多差异。您可以在 WordPress 中注册自己的商店,或者更重要的是,访问 WordPress 的注册商店。

这是 WordPress 数据模块中可用商店的概述(可能会随着时间的推移而改变)。所有 WordPress 的商店都包含在核心数据模块中。例如,有存储编辑器数据 ( core/editor)、通知 ( core/notices)、块数据 ( core/blocks)、视口信息 ( core/viewport),以及最后但并非最不重要的主存储本身 – core

为了从商店访问数据,您需要使用选择器。WordPress 在wp.data包中有一个选择器;select(). 您还可以使用 来操作商店dispatch,但这不在本教程系列中。实际上,您可以真正轻松地亲自试用选择器,看看 WordPress 商店中有哪些可用的东西。

试用选择器

在 Chrome 中打开古腾堡编辑器,然后打开控制台调试器工具。输入:

wp.data.select(‘core’)

然后按 Enter。你应该得到一个对象作为你可以使用的所有选择器(函数)的响应。作为示例,您会发现getMediagetTaxonomygetAuthors等函数。我们将用来查询帖子的那个也在那里,但没有直观的名称;它被称为getEntityRecords。目前,其中一些功能已记录在案,但不幸的是,大多数都没有。

也可以尝试其他商店core,例如:

wp.data.select(‘core/editor’).getBlocks()

这将返回有关您帖子中当前所有块的所有信息。你可以在 Chrome 控制台调试器中尝试这个,并尝试调用一些函数来查看你得到的响应。有些需要参数,有些则不需要。

为了使用选择器和访问存储,我们需要在高阶组件中使用它们。高阶组件只是 React 中做某事的一种模式。我们将组件传递给可以添加一些道具的函数(或组件),然后返回一个新组件。

在 WordPress 数据模块中,我们发现withSelect;一个高阶组件,可用于使用已注册的选择器注入道具。换一种说法; 在withSelect其中我们可以访问选择器select()并可以使用它来执行调用。选择器结果将是我们传递给组件的道具withSelect。如果您需要组合多个高阶组件,WordPress 数据模块提供了该compose功能,但这不在本教程的讨论范围之内。我们将只使用一个高阶组件;withSelect.

上面讲了很多理论,所以让我们开始看一些代码和实际例子。

使用 withSelect、select 和 getEntityRecords 获取帖子

综上所述,我们需要withSelect为我们的块设置高阶组件。在这里面我们可以使用选择器来访问 WordPress 的商店,这将是我们传递给组件的道具withSelect。我们将使用core商店和选择器getEntityRecords来查询帖子。

getEntityRecords不幸的是,目前还没有很好地记录该功能。但我了解到我们可以将postType第一个参数(实体类型)传递,然后将帖子类型作为第二个参数(例如“ post”或“ page”)传递。第三个参数是可选的,可以是带有查询参数的对象。稍后我们将查看第三个参数。

如果您按照上一部分中的本系列教程进行操作,您将拥有一个自定义块,该块接受在文本输入中手动输入的帖子 ID。该块使用 PHP 在前端(和预览模式)动态呈现帖子。让我们删除手动输入帖子 ID 的要求,并将其替换为更直观的内容。如前所述,您需要自己决定如何呈现帖子列表以及让用户选择帖子的最佳方式。为简单起见,我们将添加所有帖子标题的选择以供选择。

编码withSelect

让我们开始编码。首先我们需要从数据包中解构我们需要的东西;

const { withSelect, select } = wp.data;

然后我们withSelect在块的edit函数中使用并传递我们的编辑组件;FirstBlockEdit. 在内部withSelect,我们解构select为参数并使用选择器select()来查询带有getEntityRecords. 我们返回一个对象,该对象具有我们调用的一个属性,该属性posts保存调用的结果select()


edit: withSelect(select => {
return {
posts: select(‘core’).getEntityRecords(‘postType’, ‘post’)
}
})(FirstBlockEdit),
save: () => { return null }

使用我们组件上方的代码FirstBlockEdit,现在将有一个新的道具;posts. 无论我们在withSelect高阶组件中返回什么,都可以作为我们传递的组件的 props 访问(在最后的括号中)。

处理来自选择器的文章

我们现在可以进入我们的组件FirstBlockEdit并查看新的props.posts. 因为我们的组件是基于类的组件,所以我们需要使用thisrender()让我们在函数中的控制台中将其注销FirstBlockEdit

render() {
const { attributes, setAttributes } = this.props;
console.log(this.props.posts);

}

留意你的控制台调试器。您可能会注意到这将记录两次;首先null,然后稍后它会记录一系列帖子。这是因为查询帖子是异步完成的。我们的组件首先在响应之前呈现,此时props.postsnull。一旦我们得到响应,我们的组件将再次重新渲染并填充 prop。您应该始终记住在代码中没有数据的情况下适应这个小时间段。

添加一个选择以显示帖子

让我们准备用返回的帖子填充选择,为此我们将使用 WordPress 组件SelectControl。该组件SelectControl接受一组选择,其中每个选择都是一个具有属性value和的对象label

如果您查看控制台记录的(第二个)响应,您可以看到我们获得了一组 post 对象。每个帖子都包含帖子的大部分信息,但对于选择中的选择,我们只对作为值的帖子 ID 和作为标签的帖子标题感兴趣。所以我们将遍历postsprop 并填充一个数组变量,我们将传递给SelectControl. 不要忘记处理posts道具所在的小时间范围null。在这种情况下,我们将使用一个标签为“Loading…”的选项填充选择数组。

let choices = [];
if (this.props.posts) {
choices.push({ value: 0, label: __(‘Select a post’, ‘awhitepixel’) });
this.props.posts.forEach(post => {
choices.push({ value: post.id, label: post.title.rendered });
});
} else {
choices.push({ value: 0, label: __(‘Loading…’, ‘awhitepixel’) })
}

请注意,我们需要将帖子标题称为post.title.rendered. 您可以在登录的控制台中查找自己,posts并查看每个帖子的信息结构。

在此之后,我们只需要SelectControl在我们想要的地方添加一个。它可以在块本身内(最好在编辑模式的代码内),或在 Inspector 内。

<SelectControl
label={__(‘Selected Post’, ‘awhitepixel’)}
options={choices}
value={attributes.selectedPostId}
onChange={(newval) => setAttributes({ selectedPostId: parseInt(newval) })}
/>

我们将 设置SelectControl为引用selectedPostId我们在上一步中定义的属性。我们在 prop 中设置保存的值并在 prop 中value处理更新它onChange——就像我们之前做过几次一样。我们确保使用 using 存储数字,parseInt()因为selectedPostId的类型为number。我们在 prop 中传递生成的选择数组options

仅此而已!如果您遵循上一步中的代码,您应该已经有了读取保存的帖子 ID 并显示它的代码!

当然,我建议您以不同于简单选择的方式来实现帖子列表和选择。这不是一个漂亮或用户友好的解决方案,尤其是对于有很多帖子的网站。说到帖子数,您是否注意到选择器 getEntityRecords 最多只返回 10 个最新帖子?这是 getEntityRecords 的默认行为,但我们可以通过传递第三个参数来修改发布查询。

修改 getEntityRecords 的查询

通过将对象作为第三个参数传递给 getEntityRecords,我们可以修改发布查询。如前所述,不幸的getEntityRecords是缺少文档。但是通过阅读整个网络,我收集了一个可能的查询参数列表;

  • per_page:设置为一个数字来限制帖子的数量。设置为-1以获取最大值 100。默认值10
  • exclude:从查询中排除某些帖子。设置为一个帖子 ID 或多个帖子 ID 的数字数组。
  • parent_exclude:排除某些父职位。设置为一个帖子 ID 或多个帖子 ID 的数组。
  • orderby: 决定帖子的顺序。您很可能可以使用与WP_Query 的 orderby中相同的参数。可以是例如 ‘ menu_order‘。
  • order:'asc'或 ‘desc'用于升序或降序。
  • status:按帖子状态过滤。可以是字符串、以逗号分隔的具有多个状态的字符串或状态字符串数组。例如['publish', 'draft'],查询已发布和起草的帖子。
  • categories:按特定类别过滤帖子。提供类别 ID 或类别 ID 数组。我相信这只适用于帖子类别而不适用于其他自定义分类法。
  • tags:按某些标签过滤帖子。提供标签 ID 或标签 ID 数组。仅适用于帖子标签,不适用于其他自定义分类法。
  • search:添加搜索查询(字符串)。

注意:这不是一个详尽的列表,并且可能会发生变化!

让我们修改我们的查询。我们想做两件事;首先,我们要获取所有帖子,而不仅仅是最新的 10 篇。为此,我们提供-1per_page。其次,我们想通过将当前帖子 ID 提供给 来从帖子列表中排除当前帖子exclude。显示帖子快捷方式或当前帖子本身的预览通常没有意义。

你可能认为; 稍等,我们如何获得当前的帖子 ID?不要忘记我们在高阶组件中withSelect并使用select选择器可以访问所有 WordPress 的核心数据存储。当前的帖子 ID 很自然地存储在 WordPress 核心商店之一中。我们在其中core/editor找到了功能getCurrentPostId()

让我们将withSelect返回值修改成这样:

edit: withSelect(select => {
const currentPostId = select(‘core/editor’).getCurrentPostId();
const query = {
per_page: -1,
exclude: currentPostId
}
return {
posts: select(‘core’).getEntityRecords(‘postType’, ‘post’, query)
}
})(FirstBlockEdit),

上面的变化是不言自明的。我们生成一个具有属性的查询对象,per_page并将exclude其作为第三个参数传递给getEntityRecords(). 现在我们props.posts的组件内部FirstBlockEdit应该列出所有帖子但排除当前帖子。

结论

这篇文章结束了如何创建自定义古腾堡块教程系列。该系列旨在介绍开发您自己的自定义块的基础知识,为您提供开发您自己的和更复杂的块的起点。一定要留意更多与古腾堡相关的教程。也许您会找到一个更具体地解释您想自己做的事情的教程!

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注