WordPress源码深度解析之:古腾堡的`block.json`:`metadata`文件的作用与底层解析。

各位朋友,大家好!我是老码农,今天咱们来聊聊WordPress古腾堡编辑器里一个挺有意思的小东西——block.json,特别是里面的metadata部分。别看它个头不大,作用可不小,搞清楚它,能让你在自定义区块的路上少踩不少坑。

咱们这次讲座的目标很简单:

  1. 理解block.json的地位和作用: 它是区块的“身份证”,没有它,区块就没法在古腾堡里混。
  2. 深入metadata 搞清楚metadata里各个字段的含义,以及它们是如何影响区块的行为的。
  3. block.json的底层解析: 看看WordPress是怎么读取和使用block.json的。
  4. 实战演练: 通过一些实际的例子,让你明白怎么用metadata来定制区块。

好了,废话不多说,咱们开始吧!

1. block.json:区块的“身份证”

想象一下,你要在一个大型的社交场合(古腾堡编辑器)介绍自己(你的区块),你需要什么?当然是身份证啊!block.json就是区块的身份证,它告诉WordPress:

  • 我是谁(name
  • 我长什么样(attributes定义了区块的数据结构)
  • 我有什么功能(supports定义了区块支持的功能)
  • 我在哪里(file指定了区块的脚本和样式文件)

一个最简单的block.json可能长这样:

{
  "name": "my-plugin/my-block",
  "title": "My Block",
  "category": "common",
  "icon": "smiley",
  "attributes": {
    "content": {
      "type": "string",
      "default": "Hello, world!"
    }
  },
  "supports": {
    "align": true
  },
  "editorScript": "file:./index.js",
  "style": "file:./style.css"
}

这个JSON文件告诉WordPress,我们有一个名为my-plugin/my-block的区块,它显示一个笑脸图标,有一个可以编辑的文本内容,并且支持对齐。

2. metadata:区块的“详细信息”

metadata并不是block.json里一个单独的字段。 实际上, block.json 就是 区块的元数据文件。 里面的每一个键值对,都描述了区块的不同方面的属性。它包含了区块的所有关键信息,包括但不限于:

  • apiVersion 指定区块API的版本。
  • name 区块的唯一标识符,格式为plugin-slug/block-name
  • title 区块在编辑器中显示的名字。
  • description 区块的描述信息。
  • category 区块所属的分类(common, formatting, layout, widgets, embed)。
  • icon 区块的图标。可以是 Dashicons 的名称,也可以是 SVG 元素。
  • keywords 关键词,方便用户搜索区块。
  • attributes 定义区块的数据结构。每个属性都有一个type(string, number, boolean, array, object)和一个default值。
  • supports 定义区块支持的功能,例如align(对齐)、anchor(锚点)、color(颜色)、spacing(间距)。
  • providesContext 区块向子区块提供的上下文数据。
  • usesContext 区块使用的上下文数据。
  • example 区块的示例数据,用于在区块面板中预览。
  • editorScript 编辑器中使用的 JavaScript 文件。
  • editorStyle 编辑器中使用的 CSS 文件。
  • style 前端使用的 CSS 文件。
  • render PHP 回调函数,用于在前端渲染区块。
  • textdomain 区块的文本域,用于国际化。
  • parent 指定允许包含此区块的父区块。
  • ancestor 指定允许此区块存在的祖先区块。
  • variations: 区块的变体。

这些字段就像是区块的“详细信息”,告诉WordPress这个区块是干什么的,怎么用。

3. block.json的底层解析

WordPress在初始化古腾堡编辑器时,会扫描所有已注册的区块,并解析它们的block.json文件。这个过程主要发生在WP_Block_Type_Registry类中。

简单来说,WordPress会做以下几件事:

  1. 查找block.json WordPress会根据区块的名称(例如my-plugin/my-block)查找对应的block.json文件。它会在插件目录、主题目录等地方查找。
  2. 读取和解析JSON: WordPress会读取block.json文件的内容,并将其解析成一个PHP数组。
  3. 创建WP_Block_Type对象: WordPress会根据解析后的数据,创建一个WP_Block_Type对象。这个对象包含了区块的所有信息,例如名称、属性、支持的功能等。
  4. 注册区块类型: WordPress会将WP_Block_Type对象注册到WP_Block_Type_Registry中。这样,古腾堡编辑器就能识别并使用这个区块了。

你可以通过以下代码来获取一个区块的WP_Block_Type对象:

<?php
$block_type = WP_Block_Type_Registry::get_instance()->get( 'my-plugin/my-block' );

if ( $block_type ) {
  // 现在你可以访问区块的各种属性了
  echo '区块名称:' . $block_type->name . '<br>';
  echo '区块标题:' . $block_type->title . '<br>';
  // ...
} else {
  echo '区块未找到!';
}
?>

这段代码演示了如何从WordPress的区块类型注册表中获取一个区块的信息。WP_Block_Type_Registry::get_instance()->get() 方法接收区块的名称作为参数,并返回一个 WP_Block_Type 对象,如果该区块存在的话。如果区块不存在,则返回 null。通过这个对象,你可以访问区块的各种属性,比如名称、标题、属性等等。

4. 实战演练:用metadata定制区块

光说不练假把式,咱们来通过几个例子,看看怎么用metadata来定制区块。

例子1:自定义区块的对齐方式

假设你想让你的区块只支持居中对齐和靠右对齐,你可以这样修改block.json

{
  "name": "my-plugin/my-block",
  "title": "My Block",
  "category": "common",
  "icon": "smiley",
  "attributes": {
    "content": {
      "type": "string",
      "default": "Hello, world!"
    }
  },
  "supports": {
    "align": ["center", "right"]
  },
  "editorScript": "file:./index.js",
  "style": "file:./style.css"
}

这样,在古腾堡编辑器中,你的区块就只会显示居中对齐和靠右对齐的选项了。

例子2:使用providesContextusesContext传递数据

providesContext允许一个区块向其子区块提供数据,而usesContext允许一个区块使用其父区块提供的数据。

假设我们有一个父区块叫做my-plugin/parent-block,它提供一个名为my-plugin/theme的上下文,值为darklight

// block.json for my-plugin/parent-block
{
  "name": "my-plugin/parent-block",
  "title": "Parent Block",
  "category": "common",
  "icon": "smiley",
  "attributes": {
    "theme": {
      "type": "string",
      "default": "light"
    }
  },
  "providesContext": {
    "my-plugin/theme": "theme"
  },
  "editorScript": "file:./index.js",
  "style": "file:./style.css"
}

然后在index.js中,我们可以使用useBlockPropsuseSetting来设置编辑器中的样式,并更新属性theme:

import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, SelectControl } from '@wordpress/components';

export default function Edit({ attributes, setAttributes }) {
    const { theme } = attributes;

    return (
        <>
            <InspectorControls>
                <PanelBody title="Theme Settings">
                    <SelectControl
                        label="Theme"
                        value={theme}
                        options={[
                            { label: 'Light', value: 'light' },
                            { label: 'Dark', value: 'dark' },
                        ]}
                        onChange={(newTheme) => setAttributes({ theme: newTheme })}
                    />
                </PanelBody>
            </InspectorControls>
            <div {...useBlockProps()}>
                {/* Parent Block Content */}
                <p>Parent Block - Theme: {theme}</p>
            </div>
        </>
    );
}

现在,假设我们有一个子区块叫做my-plugin/child-block,它想使用父区块提供的my-plugin/theme上下文:

// block.json for my-plugin/child-block
{
  "name": "my-plugin/child-block",
  "title": "Child Block",
  "category": "common",
  "icon": "smiley",
  "usesContext": ["my-plugin/theme"],
  "editorScript": "file:./index.js",
  "style": "file:./style.css"
}

然后在index.js中,我们可以使用useContext来获取父区块提供的theme值:

import { useBlockProps, useContext } from '@wordpress/block-editor';

export default function Edit() {
    const theme = useContext('my-plugin/theme');

    return (
        <div {...useBlockProps()}>
            {/* Child Block Content */}
            <p>Child Block - Theme: {theme || 'default'}</p>
        </div>
    );
}

这样,子区块就能根据父区块提供的theme值来改变自己的样式或行为了。

例子3:使用variations创建区块变体

区块变体允许你创建一个区块的多个版本,每个版本都有不同的属性和样式。

假设我们有一个名为my-plugin/button的区块,它有两个变体:primarysecondary

{
  "name": "my-plugin/button",
  "title": "Button",
  "category": "common",
  "icon": "button",
  "attributes": {
    "text": {
      "type": "string",
      "default": "Click me!"
    },
    "style": {
      "type": "string",
      "default": "primary"
    }
  },
  "variations": [
    {
      "name": "primary",
      "title": "Primary Button",
      "description": "A primary button.",
      "attributes": {
        "style": "primary"
      },
      "icon": "button"
    },
    {
      "name": "secondary",
      "title": "Secondary Button",
      "description": "A secondary button.",
      "attributes": {
        "style": "secondary"
      },
      "icon": "button"
    }
  ],
  "editorScript": "file:./index.js",
  "style": "file:./style.css"
}

index.js中,我们可以根据style属性来应用不同的样式:

import { useBlockProps, RichText } from '@wordpress/block-editor';

export default function Edit({ attributes, setAttributes }) {
  const { text, style } = attributes;

  let buttonClass = 'my-button';
  if (style === 'primary') {
    buttonClass += ' my-button-primary';
  } else if (style === 'secondary') {
    buttonClass += ' my-button-secondary';
  }

  return (
    <button {...useBlockProps({ className: buttonClass })}>
      <RichText
        tagName="span"
        value={text}
        onChange={(newText) => setAttributes({ text: newText })}
      />
    </button>
  );
}

这样,用户就可以在古腾堡编辑器中选择创建primarysecondary按钮了。

5. 总结

block.json是古腾堡区块的基石,而metadata则是block.json的核心。 掌握了metadata的各个字段的含义,以及WordPress是如何解析和使用block.json的,你就能更灵活地定制区块,创建出功能强大的自定义区块。

今天我们主要讲了:

  • block.json是区块的“身份证”。
  • metadata包含了区块的所有关键信息。
  • WordPress会解析block.json,并将其转换为WP_Block_Type对象。
  • 可以通过supportsprovidesContextusesContextvariations等字段来定制区块。

希望这次讲座能让你对block.jsonmetadata有更深入的理解。 记住,实践是检验真理的唯一标准,多动手尝试,你才能真正掌握这些知识。

下次有机会,咱们再聊聊其他更有意思的WordPress开发话题! 谢谢大家!

发表回复

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