构建自定义块编辑器

WordPress块编辑器是一个强大的工具,允许您以各种方式创建和格式化内容。它的部分动力来自@wordpress/块编辑器包,这是一个JavaScript库,提供编辑器的核心功能。

此包还可以用于为几乎任何其他web应用程序创建自定义块编辑器。这意味着你可以在WordPress之外使用相同的块和块编辑体验。

替换文本

这种灵活性和互操作性使块成为跨多个应用程序构建和管理内容的强大工具。它还使开发人员更容易创建最适合其用户的内容编辑器。

本指南介绍了创建第一个自定义块编辑器的基本知识。

介绍

古腾堡代码库有很多包和组件,一开始可能会让人望而却步。但其核心是管理和编辑块。因此,如果你想使用编辑器,那么了解块编辑在基本层面上是如何工作的是至关重要的。

本指南将引导您在WordPress中构建一个功能齐全的自定义块编辑器“实例”。在此过程中,我们将向您介绍关键的包和组件,以便您可以了解块编辑器是如何在幕后工作的。

在本文结束时,您将对块编辑器的内部工作有一个坚实的理解,并且能够很好地创建自己的块编辑器实例。

本指南中使用的代码可在附带的WordPress插件。此插件中的演示代码是一个基本资源。

代码语法

本指南中的代码片段使用JSX语法。然而,如果您愿意,可以使用纯JavaScript。然而,一旦熟悉了JSX,许多开发人员就会发现它更容易阅读和编写,因此《块编辑器手册》中的所有代码示例都使用此语法。

你要建造什么

在本指南中,您将创建一个(几乎)功能齐全的块编辑器实例。结果如下:

在自定义WordPress管理页面中用示例块填充的Standalone Editor实例

虽然看起来很相似,但这个编辑器将不同块编辑器你很熟悉在WordPress中创建帖子和页面。相反,它将是一个完全自定义的实例,位于名为“块编辑器”的自定义WordPress管理页面中

编辑器将具有以下功能:

  • 能够添加和编辑所有核心块。
  • 熟悉的视觉样式和主/侧栏布局。
  • 基本页面重新加载之间的块持久性。

插件设置和组织

自定义编辑器将被构建为WordPress插件。为了简单起见,插件将被命名为独立块编辑器演示因为它就是这样做的。

插件文件结构如下所示:

替换文本

以下是所发生事情的简要总结:

  • 插件.php–带有注释元数据的标准插件“条目”文件,需要初始化.php.
  • 初始.php–处理主插件逻辑的初始化。
  • 型钢混凝土/(目录)–这是JavaScript和CSS源文件所在的位置。这些文件是插件直接排队。
  • webpack.config.js–自定义Webpack配置扩展了@wordpress/脚本npm包允许自定义CSS样式(通过Sass)。

上面唯一没有显示的项目是建造/目录,其中已编译JS和CSS文件由输出@wordpress/脚本这些文件由插件单独排队。

在本指南中,文件名引用将放在每个代码段顶部的注释中,以便您可以继续阅读。

有了基本的文件结构,让我们看看需要什么包。

编辑的“核心”

虽然WordPress编辑器由许多移动部件组成,但其核心是@wordpress/块编辑器包,最好用它自己的自述文件文件:

此模块允许您创建和使用独立的块编辑器。

很好,这是您将用于创建自定义块编辑器实例的主包。但首先,您需要为编辑器创建一个主页。

创建自定义“块编辑器”页面

让我们从在WordPress管理中创建一个自定义页面开始,该页面将容纳自定义块编辑器实例。

如果您已经熟悉在WordPress中创建自定义管理页面的过程,您可能想向前跳.

注册页面

要做到这一点,你需要注册自定义管理页面使用标准WordPress添加_菜单_页面()帮手:

//文件:init.php添加菜单页面(“独立块编辑器”,//可见页面名称“块编辑器”,//菜单标签“edit_posts”,//所需功能'getdavesbe',//页面的Hook/slug“getdave_sbe_render_block_editor”,//用于呈现页面的函数'dashicons-welcome-widgets-menus'//自定义图标);

这个获取dave_sbe_render_block_editor函数将用于呈现管理页面的内容。作为提醒,每个步骤的源代码都可以在附带的插件.

添加目标HTML

由于块编辑器是一个React-powered应用程序,您需要将一些HTML输出到JavaScript可以渲染块编辑器的自定义页面。

让我们使用获取dave_sbe_render_block_editor上述步骤中引用的函数。

//文件:init.php函数getdave_sbe_render_block_editor(){?><迪夫id=“getdave-sbe-block-editor”class=“getdave-sbe-block-editor”>正在加载编辑器。。。</div><?php(电话)}

该函数输出一些基本的占位符HTML。请注意身份证件属性获取dave-sbe-block-editor,稍后将使用。

排队JavaScript和CSS

有了目标HTML,现在可以将一些JavaScript和CSS排队,以便它们在自定义管理页面上运行。

要做到这一点,让我们开始管理员队列脚本.

首先,您必须确保自定义代码仅在自定义管理页面上运行。因此,在回调函数的顶部,如果页面与页面标识符不匹配,请提前退出:

//文件:init.php函数getdave_sbe_block_editor_init($hook){//如果页面不正确,请退出。if('toplevel_page_getdavesbe'!==$hook){回报;}}add_action(“admin_enqueue_scripts”,“getdave_sbe_block_editor_init”);

有了这一点,您就可以使用标准的WordPress安全地注册主JavaScript文件wp_enqueue_script()功能:

//文件:init.phpwp_enqueue_script($script_handle、$script_url、$script_asset['dependencies']、$script_asset['版本']);

为了节省时间和空间$脚本_变量赋值被省略。你可以在这里查看这些.

请注意脚本依赖项的第三个参数,$script_asset[“依赖关系”]。这些依赖关系是
使用动态生成@wordpress/dependency-extraction-webpack-plugin语言哪一个会
确保WordPress提供的脚本不包括在构建的
捆绑。

您还需要注册自定义CSS样式和WordPress默认格式库,以利用一些不错的默认样式:

//文件:init.php//排队默认编辑器样式。wp_enqueue_style(“wp-format-library”);//加入自定义样式。wp_排队_样式(“getdave-sbe-styles”,//句柄plugins_url('build/index.css',__FILE__),//块编辑器css数组(“wp-edit-blocks”),//在其后面包含CSS的依赖项文件时间(__DIR__.'/build/index.css'));

内联编辑器设置

查看@wordpress/块编辑器包,您可以看到它接受settings对象配置编辑器的默认设置。它们在服务器端可用,因此需要公开它们以便在JavaScript中使用。

要做到这一点,让我们将设置对象内联为JSON分配给全局window.getdaveSBe设置对象:

//文件:init.php//获取自定义编辑器设置。$settings=getdave_sbe_get_block_editor_settings();//内联所有设置。wp_add_inline_script($script_handle,'window.getdaveBeSettings='.wp_json_encode($settings).';');

注册和渲染自定义块编辑器

使用上面的PHP创建管理页面后,您现在终于可以使用JavaScript将块编辑器呈现到页面的HTML中了。

首先打开干管源代码/索引.js文件。然后拉入所需的JavaScript包并导入CSS样式。请注意,使用Sass需要延伸默认值@wordpress/脚本Webpack配置。

//文件:src/index.js//外部依赖性。从“react-dom”导入{createRoot};//WordPress依赖项。从“@wordpress/dom-ready”导入domReady;从“@wordpress/block-library”导入{registerCoreBlocks};//内部依赖性。从“导入编辑器”/编辑器';导入”/styles.scss’;

接下来,一旦DOM就绪,您需要运行一个函数,该函数:

  • 从中获取编辑器设置window.getdaveSBe设置(以前从PHP内联)。
  • 使用注册所有核心WordPress块寄存器核心块.
  • 呈现<编辑器>组件进入等待<div>在自定义管理页面上。
domReady(函数(){const root=createRoot(document.getElementById('getdave-sbe-block-editor'));const-settings=window.getdaveSbeSettings||{};寄存器核心块();根.根.根(<编辑器设置={settings}/>);} );
可以从PHP呈现编辑器,而无需创建不必要的JS全局变量。查看编辑网站Gutenberg插件中的包就是一个例子。

查看<Editor>组件

让我们仔细看看<编辑器>在上述代码中使用并位于中的组件src/editor.js格式配套插件.

尽管名称如此,但这并不是块编辑器的实际核心。相反,它是一个包装器组件,该组件将包含构成自定义编辑器主体的组件。

依赖关系

在里面做的第一件事<编辑器>就是拉入一些依赖项。

//文件:src/editor.js从“组件/通知”导入通知;从“components/Header”导入Header;从“组件/侧边栏”导入侧边栏;从“components/block-editor”导入BlockEditor;

其中最重要的是内部组件块编辑器提要栏,稍后将介绍。

其余组件主要由构成编辑器布局和周围用户界面(UI)的静态元素组成。这些元素包括标题和通知区域等。

编辑器渲染

有了这些组件,您可以定义<编辑器>组件。

//文件:src/editor.js函数编辑器({settings}){返回(<DropZone提供程序><div className=“getdavesbe-block-editor-layot”><通知/><标题/><提要栏/><BlockEditor设置={settings}/></div></DropoZoneProvider>);}

在这个过程中,编辑器布局的核心被搭建起来,还有一些专门的上下文提供程序使特定功能在整个组件层次结构中可用。

让我们更详细地研究一下:

  • <DropZone提供程序>–支持使用拖放功能的dropzone
  • <通知>–提供“快餐店”通知,如果向核心/通知商店
  • <标题>–在编辑器UI顶部呈现静态标题“独立块编辑器”
  • <块编辑器>–自定义块编辑器组件

键盘导航

有了这个基本的组件结构,剩下唯一要做的事情就是
将所有内容都包装在导航区域HOC公司在布局中的不同“区域”之间提供键盘导航。

//文件:src/editor.js导出默认导航区域(编辑器);

自定义<BlockEditor>

现在核心布局和组件已经就位。现在是探索块编辑器本身的自定义实现的时候了。

此组件称为<块编辑器>这就是魔术发生的地方。

正在打开src/components/block-editor/index.js显示它是迄今为止遇到的最复杂的组件。有很多事情要做,所以首先要关注<块编辑器>组件:

//文件:src/components/block-editor/index.js返回(<div className=“getdavesbe-block-editor”><块编辑器提供程序值={块}onInput={updateBlocks}onChange={persistBlocks}设置={设置}><提要栏。检验员填充><块检查器/></提要栏。检验员填充><BlockCanvas height=“400px”/></区块编辑器提供程序></div>);

关键组件包括<块编辑器提供程序><区块列表>。让我们检查一下这些。

了解<BlockEditorProvider>组件

<块编辑器提供程序>是层次结构中最重要的组件之一。它为新的块编辑器建立了新的块编辑上下文。

因此,它是基本的实现这个项目的全部目标。

的孩子们<块编辑器提供程序>组成块编辑器的UI。然后这些组件可以访问数据(通过上下文),使他们能够提供管理块及其在编辑器中的行为。

//文件:src/components/block-editor/index.js<块编辑器提供程序value={blocks}//块对象数组onInput={updateBlocks}//管理块更新的处理程序onChange={persistBlocks}//管理块更新/持久性的处理程序settings={settings}//编辑器“settings”对象/>

块编辑器道具

你可以看到<块编辑器提供程序>接受一个(已解析的)块对象数组作为其价值prop,当在编辑器中检测到更改时,调用onChange(更改时)和/或onInput(输入)处理程序属性(将新块作为参数传递)。

在内部,它通过订阅提供的注册表(通过使用注册表提供程序HOC公司),侦听块更改事件,确定块更改是否持久,然后调用适当的onChange|输入处理程序。

对于这个简单的项目,这些功能允许您:

  • 将状态中的当前块数组存储为阻碍.
  • 更新阻碍内存状态打开onInput(输入)通过调用hook setter
    updateBlocks(块).
  • 将块的基本持久性处理为本地存储使用onChange(更改时)。这是当块更新被视为“已提交”时激发.

还值得一提的是,组件接受设置属性。在这里,您将添加先前内联为JSON的编辑器设置初始化.php。您可以使用这些设置配置自定义颜色、可用图像大小和更多.

了解<BlockList>组件

沿着<块编辑器提供程序>接下来最有趣的部分是<区块列表>.

这是最重要的组成部分之一,因为它的作用是将块列表呈现到编辑器中.

它之所以能做到这一点,部分是因为它是<块编辑器提供程序>,它可以完全访问编辑器中有关当前块状态的所有信息。

如何阻止列表工作?

发动机罩下,<区块列表>依赖于其他几个较低级别的组件来渲染块的列表。

这些组件的层次结构可以是近似的如下:

//伪代码仅供示例使用。<区块列表>/*呈现rootClientId中的块列表*/<块列表块>/*渲染块列表中的单个块*/<区块编辑>/*渲染块的标准可编辑区域*/<Component/>/*呈现由其“edit()”实现定义的块UI。*/</BlockEdit></BlockListBlock></阻止列表>

下面大致介绍了如何将其结合在一起渲染块列表:

  • <阻止列表>循环遍及整个区块客户端ID
    渲染每个通孔<块列表块/>.
  • <块列表块/>反过来,渲染单个块
    使用自己的子组件<块编辑>.
  • 最后块本身使用组件占位符组件。

这个@wordpress/块编辑器包组件是最复杂和最复杂的组件之一。如果您想掌握编辑器在基本级别上的功能,那么了解它们是至关重要的。强烈建议研究这些成分。

查看侧边栏

也在渲染<块编辑器>,是<提要栏>组件。

//文件:src/components/block-editor/index.js返回(<div className=“getdavesbe-block-editor”><块编辑器提供程序><提要栏。检查员填充>/*<--SIDEBAR*/<块检查器/></提要栏。检验员填充><BlockCanvas height=“400px”/></BlockEditorProvider></div>);

这部分用于通过<区块检查器>组件。

<提要栏。检验员填充><块检查器/></提要栏。检验员填充>

然而,你们中间热心的读者已经注意到了<边栏>中的组件<编辑器>(src/editor.js格式)组件的
布局:

//文件:src/editor.js<通知/><标题/><提要栏/>//<--这是什么?<BlockEditor设置={settings}/>

打开src/components/sidebar/index.js文件,您可以看到这实际上是在中呈现的组件<编辑器>以上。然而,实施利用了
插槽/填充以显示填充(<提要栏。检验员填充>),它随后被导入并呈现在<块编辑器>组件(见上文)。

有了这个,您就可以渲染<块检查器/>作为边栏。检验员填充这会让你<块检查器>在React上下文中<块编辑器提供程序>同时允许在单独的位置(即<边栏>).

这似乎过于复杂,但为了<块检查器>以访问有关当前块的信息。如果没有插槽/填充,此设置将极难实现。

这样你就涵盖了自定义的渲染<块编辑器>.

<区块检查器>
它实际上呈现了一个狭槽对于<检验员控制>。这就是允许您提供<检验员控制>>内部组件
这个编辑()定义块并具有
它显示在编辑器的侧栏中。建议更详细地研究此组件。

块持久性

在创建自定义块编辑器的过程中,您已经走过了漫长的路。但还有一个主要领域需要触及——阻止持久性。换句话说,拥有
已保存且可用的块之间页面刷新。

替换文本

因为这只是一个实验,本指南选择使用浏览器的本地存储用于处理保存块数据的API。在实际场景中,您可能会选择更可靠、更健壮的系统(例如数据库)。

也就是说,让我们仔细看看如何处理保存块。

存储处于状态的块

查看src/components/block编辑器/index.js文件中,您会注意到已经创建了一些状态来将块存储为数组:

//文件:src/components/block-editor/index.jsconst[blocks,updateBlocks]=useState([]);

如前所述,阻碍传递给“受控”组件<块编辑器提供程序>作为它的价值道具。这就用最初的一组块来“水合”它。类似地updateBlocks(更新块)setter连接到onInput(输入)上的回调<块编辑器提供程序>,确保块状态与编辑器中对块所做的更改保持同步。

保存块数据

如果您现在将注意力转向onChange(更改时)处理程序,您会注意到它连接到一个函数持久块()定义如下:

//文件:src/components/block-editor/index.js函数persistBlocks(newBlocks){updateBlocks(newBlocks);window.localStorage.setItem('getdavesbeBlocks',序列化(newBlocks));}

此函数接受“提交的”块更改数组并调用状态设置器updateBlocks(更新块)。它还将块存储在键下的LocalStorage中获取davesbeBlocks。为了实现这一点,将块数据序列化为古腾堡“块语法”格式,这意味着它可以安全地存储为字符串。

如果打开DeveloperTools并检查LocalStorage,您将看到在编辑器中发生更改时存储和更新的序列化块数据。以下是格式示例:

<!-- wp:标题--><h2>WordPress管理员中独立块编辑器的实验</h2><!-- /wp:标题--><!-- wp:段落--><p>这是一个实验,旨在发现在WordPress管理员中创建块编辑器的独立实例有多容易(或其他)</p>(第页)<!-- /wp:段落-->

正在检索以前的块数据

保持持久性是很好的,但只有在检索数据并恢复在每次重新加载整页时在编辑器中。

访问数据是一种副作用,因此必须使用使用效果钩子来处理这个。

//文件:src/components/block-editor/index.js使用效果(()=>{const-storedBlocks=window.localStorage.getItem('getdavesbeBlocks');if(存储块&&storedBlocks.length){updateBlocks(()=>解析(storedBlocks));createInfoNotice(“加载的块”{type:“snackbar”,isDismissible:正确,} );}},[]);

此处理程序:

  • 从本地存储中获取序列化块数据。
  • 使用parse()实用程序。
  • 调用状态设置器updateBlocks(更新块)导致阻碍要在状态中更新的值,以反映从LocalStorage检索到的块。

由于这些操作<块编辑器提供程序>组件使用从LocalStorage恢复的块进行更新,从而使编辑器显示这些块。

最后,您需要生成一个通知,该通知将显示在<通知>组件作为“snackbar”通知-指示块已恢复。

总结

祝贺您完成本指南。现在您应该更好地了解块编辑器是如何在后台工作的。

您刚刚构建的自定义块编辑器的完整代码是GitHub上提供。下载并亲自试用。然后进行实验,并将事情做得更深入。