WordPress 块转换

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 $200 免费信用额度!

对于我们 CSS-Tricks 来说,今年是古腾堡的一年。事实上,这是我们在去年年底设定的目标。我们比我想象的要更进一步,在块编辑器¹中创作所有新的内容,现在为所有内容启用块编辑器。这意味着当我们打开大多数旧帖子时,我们会看到所有内容都在“经典”块中。它看起来像这样

在使用块编辑器之前,在 CSS-Tricks 上撰写的一篇帖子。

帖子的整个内容都在单个块中,所以没有完全利用块编辑器。它仍然是“可视化的”,就像块编辑器一样,但它更像是使用 TinyMCE 的旧可视化编辑器。我从未使用过它,因为它以我不喜欢的方式强行扭曲了 HTML。

这是我最担心的问题

将经典块转换为新块与选择经典块并选择“转换为块”选项一样简单。

选择该选项,一个块将变成多个块。

当我们从“转换为块”选项中告诉它这样做时,块编辑器如何处理对旧内容进行块化?如果它在转换过程中完全搞乱了内容怎么办?我们是否能够切换?

答案:它做得相当不错。 但是……仍然存在问题。不是“错误”,而是我们的旧内容中有自定义 HTML,它不知道如何处理它——更不用说如何将其转换为我们希望它那样转换的块。有一种方法!

基本块转换

这就是“块转换”这个想法的来源。所有(好吧,大多数?)原生块都有“to”和“from”转换。您可能已经熟悉它在 UI 中的表现方式。例如,段落可以转换为“to”引用,反之亦然。这是一张关于这段段落的超级元截图

这些转换不是魔法;它们是显式编码的。当您注册一个块时,您会指定转换。假设您要注册自己的自定义代码块。您需要确保您可以对其进行转换……

  • From 到默认的内置代码块,以及可能还有其他一些可能有用的块。
  • 返回内置代码块。

它可能看起来像

registerBlockType("my/code-block", {
  title: __("My Code Block"),
  ...
  transforms: {
    from: [
      {
        type: "block",
        priority: 7,
        blocks: ["core/code", "core/paragraph", "core/preformatted"],
        transform: function (attributes) {
          return createBlock("my/code-block", {
            content: attributes.content,
          });
        },
      },
    ],
    to: [
      {
        type: "block",
        blocks: ["core/code"],
        transform: ({ content }) => createBlock("core/code", { content }),
      },
    ],
   
   ...

这些是到其他块和从其他块的转换。幸运的是,这是一个非常简单的块,我们只是在对content进行排列。更复杂的块可能需要传递更多数据,但我还没有遇到过这种情况。

更神奇的东西:从原始代码进行块转换

这是对旧内容的真相时刻

“转换为块”选项。

在这种情况下,块不是从其他块创建的,而是从原始代码创建的。毫不夸张地说,HTML 正在被查看,并且正在做出关于从哪些 HTML 块中创建哪些块的选择。这就是块编辑器在做出选择时表现得如此出色,以及它可能出错并失败、做出错误的块选择或破坏内容的地方。

在我们的旧内容中,帖子中的代码块(一个非常重要的事情)看起来像这样

<pre rel="JavaScript"><code class="language-javascript" markup="tt">
  let html = `<div>cool</div>`;
</code></pre>

有时块转换会对这些块进行良好处理,将其转换为原生代码块。但有一些问题

  1. 我不想使用原生代码块。我希望它转换为我们自己的新的代码块(此处对此进行了博客文章)。
  2. 我需要这些属性中的一些信息来告知新块的设置,例如代码类型。
  3. 我们旧代码块中的 HTML没有转义,我需要它不要被这些内容卡住。

我还没有所有答案,因为这是一个不断发展过程,但我现在已经有一些块转换正在运行,效果还不错。以下是“原始”转换(与“块”转换相对)的示例

registerBlockType("my/code-block", {
  title: __("My Code Block"),
  // ...
  transforms: {
    from: [
      {
        type: "block",
        priority: 7,
        // ...
      },
      {
        type: "raw",
        priority: 8,
        isMatch: (node) =>
          node.nodeName === "PRE" &&
          node.children.length === 1 &&
          node.firstChild.nodeName === "CODE",
        transform: function (node) {
          let pre = node;
          let code = node.querySelector("code");

          let codeType = "html";
          if (pre.classList.contains("language-css")) {
            codeType = "css";
          }
          if (pre.getAttribute("rel") === "CSS") {
            codeType = "css";
          }
          if (pre.classList.contains("language-javascript")) {
            codeType = "javascript";
          }
          if (code.classList.contains("language-javascript")) {
            codeType = "javascript";
          }
          // ... other data wrangling...

          return createBlock("csstricks/code-block", {
            content: code.innerHTML,
            codeType: codeType,
          });
        },
      },
    ],
    to: [
      // ... 
    ],
   
   // ...

}

isMatch函数运行在找到的每个 HTML 节点上,因此这是在您需要的特殊情况下从该函数中返回true的重大机会。请注意上面的代码中,我专门在寻找看起来像<pre ...><code ...>的 HTML。当匹配时,转换将运行,并且我可以返回一个createBlock调用,该调用会传递使用 JavaScript 从节点中提取的数据和内容。

另一个示例:粘贴 URL

“原始”转换不仅发生在您“转换为块”时。它们也发生在您将内容粘贴到块编辑器中时。您可能之前遇到过这种情况。假设您从某处复制了一些表格标记并将其粘贴到块编辑器中——它可能会作为表格粘贴。YouTube URL 可能会粘贴到嵌入中。这种类型的操作是为什么从 Word 文档等中复制/粘贴通常在块编辑器中运行良好。

假设您希望在将特定类型的 URL 粘贴到编辑器中时执行一些特殊行为。这是我使用我们自定义 CodePen 嵌入块时的状况。我想要它这样,如果你粘贴了一个 codepen.io URL,它会使用这个自定义块,而不是默认的嵌入。

这是一个“from”转换,它看起来像这样

{
  type: "raw",
  priority: 8, // higher number to beat out default
  isMatch: (node) =>
    node.nodeName === "P" &&
    node.innerText.startsWith("https://codepen.io/"),

  transform: function (node) {
    return createBlock("cp/codepen-gutenberg-embed-block", {
      penURL: node.innerText,
      penID: getPenID(node.innerText), // helper function
    });
  },
}

所以……

它很乱吗?有点。但它强大到你所需要的一切。如果你有一个旧网站,其中有很多定制的 HTML、简码等等,那么进入块转换是唯一的选择。

我很高兴去参加了WPBlockTalk 并观看了 K. Adam White 关于简码的演讲,因为那里有一张幻灯片让我明白这甚至可能是可行的。有一些关于它的文档

我想弄清楚的一件事是,是否可以在数据库中的所有旧内容上运行这些转换。这听起来有点可怕,但也像是某些情况下一个好主意。一旦我的转换真正稳定,我就可以看到这样做,这样当打开它时,所有旧内容都会在块编辑器中准备就绪。我只是不知道如何进行。

不过我很高兴能够在一定程度上掌控它,因为我现在超级喜欢块编辑器。用它写东西和构建内容很愉快。我喜欢Justin Tadlock 的说法

块系统不会消失。WordPress 已经超越了我们应该将块编辑器视为一个独立实体的程度。它是 WordPress 的一个组成部分,最终将触及编辑屏幕之外的更多领域。

它将继续存在。拥抱块编辑器并将其弯曲到我们的意志是关键。

  1. 我们到底叫它什么呢?“古腾堡”似乎已经不再合适了。感觉它会逐渐消失,尽管它的开发仍然发生在古腾堡插件中。我认为我只会称之为“块编辑器”,除非专门指代那个插件。