社区新闻

使用 InnerBlocks 和文章元数据设置多区块插件

查看官方原文 ↗ 发布于

WordPress 一直以其惊人的灵活性和可定制性著称。区块编辑器和站点编辑器正在扩展我们创建自定义体验的能力,而创建自定义区块的能力则进一步增强了这种能力。

目前,create-block 工具每次只允许创建一个区块,并且不提供多区块设置的选项。例如,如果你想创建两个或更多相关的区块,特别是当一个自定义区块需要使用另一个来策划用户体验时,该怎么办?如果你的目标是使用文章元数据为用户提供额外上下文,又该如何?这些都是常见的用例,也是 WordPress 一直表现出色的领域。

下面,你将学习如何使用 create-block 工具来构建多区块方法。

让我们通过设置一个能够对文章或自定义文章类型进行评分,并将该评分包含在另一个可用于查询循环的自定义区块中的功能,来延续这种灵活性。这可以用于创作者发布评论(书籍、电影、产品)并需要在其文章中显示评分系统的场景。最终效果应如下所示:

完成的区块包括评论卡片区块和评分区块。

具体来说,你将构建:

  1. 一个包含三个特定内部区块的评论卡片区块:
    1. 标题 (core/post-title)
    2. 评分区块(我们也将制作这个区块)
    3. 摘要 (core/post-excerpt)
  2. 一个评分区块,它将:
    1. 用一到五颗星或心形来评价一篇文章(或 CPT)
    2. 使用文章元数据存储评分
    3. 在文章查询区块中使用该区块来显示每篇文章的评分。

你需要设置一个本地环境,并安装有 NodeJS 的终端来运行命令。如果你还没有设置本地环境,可以使用 wp-nowLocalWP此处 列出的其他适合你需求的选项。

如果你想参考最终代码,可以在 这个 Github 仓库 中找到,并将根据需要更新;欢迎提交 PR!

设置多区块插件

让我们从设置项目结构开始。在终端中,进入你的 wp-content/plugins 目录。如果你使用 wp-now,可以在任何你喜欢的目录中工作。

搭建插件文件

运行 npx @wordpress/create-block@latest post-review-blocks。这将在名为 post-review-blocks 的目录中搭建一个名为“Post Review Blocks”的区块插件。进入该目录并在你选择的代码编辑器中打开它。你应该看到一个 post-review-blocks.php 文件。打开它,你的代码应该如下所示(不含默认注释):

/**
 * Plugin Name:       Post Review Blocks
 * Description:       Example block scaffolded with Create Block tool.
 * Requires at least: 6.1
 * Requires PHP:      7.0
 * Version:           0.1.0
 * Author:            The WordPress Contributors
 * License:           GPL-2.0-or-later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       post-review-blocks
 *
 * @package CreateBlock
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

function create_block_post_review_blocks_block_init() {
	register_block_type( __DIR__ . '/build );
}
add_action( 'init', 'create_block_post_review_blocks_block_init' );

插件本身应具有类似这样的文件结构:

- build/
- src/
- .editorconfig
- .gitignore
- .package-lock.json
- .package.json
- post-review-blocks.php
- readme.md

在本教程中,你将在 post-review-blocks.php 文件和 src 目录中工作,build 目录将自动构建。

搭建区块

接下来,删除 src 目录中的所有文件,使 src 为空,如果尚未进入,请 cd 进入 src

运行以下两个命令:

npx @wordpress/create-block@latest review-card-block --no-plugin
npx @wordpress/create-block@latest rating-block --no-plugin --variant dynamic

这将创建我们多区块设置所需的两个自定义区块。请注意两个命令中的 --no-plugin 标志。该标志表示这只是创建区块文件,而不是所有需要的插件文件。另外,你可以看到 rating-block 将是一个“动态”区块,使用 PHP 渲染。为什么?这让你可以同时练习 静态和动态区块

现在,我们的 src 文件夹中有两个区块:

  • rating-block
  • review-card-block

你还可以处理几件事:

  • 进入 rating-blockblock.json 文件,将“icon”属性从“smiley”更改为“star-filled”。
  • 在每个区块的 block.json 文件中,添加“keywords”属性,值为 "keywords": ["rating", "review"]。你的用户在搜索时会更容易找到新区块。
  • post-review-blocks.php 文件中,更新 create_block_post_review_blocks_block_init 以注册两个区块,如下所示:
function create_block_post_review_blocks_block_init() {
	register_block_type( __DIR__ . '/build/rating-block' );
	register_block_type( __DIR__ . '/build/review-card-block' );
}
add_action( 'init', 'create_block_post_review_blocks_block_init' );

构建区块并激活插件

现在,从 post-review-blocks 插件的根目录(“根”与 package.json 文件同级)运行 npm start,区块应该会构建到 build 中各自的子目录中。你可以在本教程的剩余部分让此脚本保持运行。或者,如果你想运行其他命令或更改 block.json 等文件时,可以停止并重新启动它。脚本需要运行,任何更改才会出现在编辑器中。

构建成功后,在 WordPress 仪表板中或通过 WP-CLI 使用 wp plugin activate post-review-blocks 激活插件。

此时,你可以通过创建新文章并检查插入器中的区块来验证区块是否已注册,输入我们使用的关键字之一:

评论卡片和评分区块已加载。

成功!🎉

你现在知道如何设置多区块插件的结构了。你可以使用 create-blocksrc 文件夹添加新区块,并在 build 目录中注册它们生成的脚本。

现在是时候添加文章元数据功能、分配内部区块并限制区块的使用位置了。

注册文章元数据

再次打开 post-review-blocks.php,并将以下代码粘贴到 create_block_post_review_blocks_block_init 函数之后:

// Add some post meta
function register_review_rating_post_meta() {
	$post_meta = array(
		'_rating'      => array( 'type' => 'integer'	),
		'_ratingStyle' => array( 'type' => 'string'	),
	);

	foreach ( $post_meta as $meta_key => $args ) {
		register_post_meta(
			'post',
			$meta_key,
			array(
				'show_in_rest'  => true,
				'single'        => true,
				'type'          => $args['type'],
				'auth_callback' => function() {
					return current_user_can( 'edit_posts' );
				}
			)
		);
	}
}
add_action( 'init', 'register_review_rating_post_meta' );

此函数注册你将需要的两个文章元数据键:

  • _rating
  • _ratingStyle

这些需要注册。否则,当你更新我们的评分区块时,数据将不会被保存。你还会注意到两个元数据键都以下划线 _ 为前缀。这可以“保护”元数据不被用于文章的自定义字段部分,并可能被该元数据框中的值覆盖。

最后,请注意 show_in_rest 设置为 true,并且 auth_callback 检查以确保用户至少拥有 edit_posts 权限。如果元数据未出现在 WordPress REST API 中,则无法在区块编辑器中编辑。

关于在 REST API 中显示数据的快速说明(超出本教程范围):请谨慎处理。如果你需要从公共 API 中过滤数据,请在 PHP 的其他地方进行,或选择其他方法来处理敏感数据。

构建评分区块

评分区块允许你的用户在一到五的范围内对文章进行评分,并选择显示星形表情符号(⭐)或心形表情符号(❤️)。你可以将这些表情符号复制到你的代码中。通过此功能,该区块实现了两个目标:

  1. 演示如何保存和从文章元数据中提取数据
  2. 允许在查询循环文章模板中使用文章元数据

这种功能在 CPT 中有 许多应用,包括:

  • 带有 emailposition 元数据的员工目录
  • 带有 ratingISBN 元数据的图书目录
  • 带有 tastinessprep_time 元数据的食谱索引

可能性是无限的!

好的,本节中的所有编辑都将在 src/rating-block 目录内进行。

添加基本 CSS

以下 CSS 用于 styles.scss 文件。打开该文件,删除其中的任何 CSS,并粘贴以下内容,这将在区块周围添加内边距,并确保星星是黄色的,心形是红色的。

.wp-block-create-block-rating-block {
	padding: 1rem 0;
}

.wp-block-create-block-rating-block span.rating-star {
	color: yellow;
}

.wp-block-create-block-rating-block span.rating-heart {
	color: red;
}

根据你的喜好调整这些并保存文件。

向 block.json 文件添加属性和 usesContext

打开评分区块的 block.json 文件并添加以下属性:

"usesContext": ["postId", "postType"],
"attributes": {
	"rating": {
		"type": "integer",
		"default": 5
	},
	"ratingStyle": {
		"type": "string",
		"default": "star"
	}
},
"example": {
	"attributes": {
		"rating": 4,
		"ratingStyle": "star"
	}
}

上面的 JSON 执行以下操作:

  • usesContext:允许我们获取文章的 ID 和类型的值
  • attributes:标识要在区块上保存的属性
  • example:提供添加区块时可能外观的预览

点击此处查看最终的 block.json 文件。

更新 edit.js 文件

有很多内容需要处理。你可以将其分为三个部分:

  • 导入和赋值
  • 检索和存储文章元数据的功能
  • 带有编辑器侧边栏组件的返回方法

完整文件可以在 GitHub 上找到。

删除文件中当前的内容。然后,在 edit.js 文件的顶部添加以下内容:

import { __ } from "@wordpress/i18n";
import { useEffect } from "@wordpress/element";
import { useBlockProps, InspectorControls } from "@wordpress/block-editor";
import { PanelBody, RangeControl, SelectControl } from "@wordpress/components";
import { useEntityProp } from "@wordpress/core-data";

import "./editor.scss";

此部分设置我们的导入:

  • __ 是我们的国际化方法
  • useEffect 允许你更新元数据
  • useBlockProps 为你提供要使用的区块属性
  • InspectorControls 允许你向检查器侧边栏添加控件
  • PanelBodyRangeControlSelectControl 都是用于设置区块属性用户控件的组件
  • useEntityProp 提供对文章元数据的访问
  • 最后,导入 SCSS 文件

接下来,添加以下内容:

export default function Edit( {
	attributes: { rating, ratingStyle },
	setAttributes,
	context: { postType, postId },
} ) {
	const [meta, updateMeta] = useEntityProp(
		"postType",
		postType,
		"meta",
		postId,
	);

	// Add functionality code here

	// Add return() method here
	
	// Other code will go here, don't forget or delete the closing curly brace!
}

这是 Edit 方法,它控制区块编辑器中显示的内容。首先,你传入并分配以下内容:

  • ratingratingStyle 被传入并分配给属性状态对象
  • setAttributes 是更新 attributes 状态对象的方法
  • postType 和 postId 通过你上面定义的 usesContext 中的上下文传入

接下来,你会看到 meta 的状态对象和 updateMeta 方法正在从 useEntityProp 方法分配,该方法 被区块用来获取或更改元数据值

好的,到目前为止一切顺利?现在是功能部分!

在“Add functionality code here”注释的位置,添加以下方法:


useEffect(() => {
    const initStyle = meta?._ratingStyle ? meta?._ratingStyle : "star";
    setAttributes({
        rating: meta?._rating || 0,
        ratingStyle: initStyle,
    });
}, []);
const onChangeRating = (val) => {
    updateMeta({
        ...meta,
        _rating: val,
    });
    setAttributes({
        rating: val
    });
};
const onChangeRatingStyle = (val) => {
    updateMeta({
        ...meta,
        _ratingStyle: val,
    });
    setAttributes({
        ratingStyle: val
    });
};
const getRatingEmojis = () => {
    let ratingEmojis = "";
    for (let i = 0; i < rating; i++) {
        ratingEmojis += ratingStyle === "star" ? "⭐" : "❤️";
    }
    return ratingEmojis;
};

这些方法各自做什么?:

  • useEffect 在加载时运行(给定第二个参数为 []),并从存储的文章元数据中检查并分配 ratingratingStyle 的值,默认为星星(⭐)
  • onChangeRating 将在检查器中更改评分时更新评分的值
  • onChangeRatingStyleratingStyle 执行相同的操作
  • getRatingEmojis 是一个循环,返回正确数量和样式的星星或心形用于评分。

最后,在“Add return() method here”注释的位置添加以下内容:

return (
    <>
        <InspectorControls>
            <PanelBody title={ __( "Rating", "multiblock-plugin" ) }>
                <RangeControl
                    label={ __( "Rating", "multiblock-plugin") }
                    value={ rating }
                    onChange={ onChangeRating }
                    min={ 1 }
                    max={