🐥

unifiedでHTMLからWordPressに変換する機構を作成した"

に公開

この記事はSmartCampアドベントカレンダーの10日目の記事になっています!
https://qiita.com/advent-calendar/2025/smartcamp

はじめに

既存のHTMLファイルからWordPressブロックに変化する、みたいなことを行ったので備忘録として残しておきます。
WordPressの知識については省きます。

行ったこと

実際にやったことは以下です。

既存のHTML -> unifiedでHTMLをパース -> 自作したunifiedプラグインでHTMLタグをWordPresブロックに変換 -> 変換したWordPressブロックを連結してWordPressの記事にする。

HTMLのパースにはunifiedを使い、unifiedのプラグインを自作することにより変換を可能にしています。

WordPressブロックの形式

下記の記事にまとめております。
https://zenn.dev/smartcamp/articles/516012b64642d3

簡単にまとめるとWordPressではWordPress用のカスタムHTMLが使われており、ParagraphをWordPerssエディタ上で挿入すると以下の形のHTMLが挿入されます。

<!-- wp:paragraph -->
<p>テキスト</p>
<!-- /wp:paragraph -->

タグの他にWordPressのプロパティを保持するためのコメントが一緒に入ります。
WordPressブロックの種類によってHTMLの構成は決まっています。WordPressのコードエディタを使用すると実際に見れるので試してみることをお勧めします。
このWordPressブロックの形にタグを一つ一つ変換して行けば良いわけですね。

unifiedのインストール

お好きなパッケージマネージャでインストールを行います。

npm i unified

ついでにHTMLをパースするためのプラグインと構文木を扱いやすくするためunistをインストールします。

npm i rehype-parse
npm i unist

unifiedとプラグインは以下のようにして使います。
このプラグインを自作していきます。

const wordpress = unified()
  .use(rehypeParse)
  .parse(htmlContent);

unifiedのコンパイラプラグインを作成する

unifiedにいくつかプラグインのサンプルがあるのでそれを参考にしつつ、作成します。

import type { CompileResults, Compiler, Processor } from "unified";
import type { Node } from "unist";
import { childProcess } from "./childProcess.ts";

export default function compiler(this: Processor) {
  const compile: Compiler<Node, CompileResults> = (node, file) => {
    file.value = "";
    childProcess(node, file); //WordPressへの変換を開始する関数
    return file.value;
  };

  this.compiler = compile;
}

自作したプラグインはuseで使えるようになります。

const wordpress = unified()
  .use(rehypeParse)
  .use(compiler) //作成したプラグイン
  .parse(htmlContent);

HTMLタグに合わせて変換する

今回変換するサンプルHTML

今回の変換を想定しているサンプルです。
下記が入力される値とします。

<html>
  <body>
    <p>text</p>
  </body>
</html>

実際のコードでは以下のようになると思います。

import { compiler } from './compiler.ts'
const wordpress = unified()
  .use(rehypeParse)
  .use(compiler) //作成したプラグイン
  .parse(`
<html>
  <body>
    <p>text</p>
  </body>
</html>
`);
console.log(wordpress.value.toString();)

変換した出力結果は以下になる想定です。

<!-- wp:paragraph -->
<p>テキスト</p>
<!-- /wp:paragraph -->

自作プラグインのコード(再掲)

//compiler.ts
import type { CompileResults, Compiler, Processor } from "unified";
import type { Node } from "unist";
import { childProcess } from "./childProcess.ts";

export default function compiler(this: Processor) {
  const compile: Compiler<Node, CompileResults> = (node, file) => {
    file.value = "";
    childProcess(node, file); //WordPressへの変換を開始する関数
    return file.value;//valueの中に結果が入っている。
  };

  this.compiler = compile;
}

変換機構

以下が変換機構になります。順を追って説明します。

//childProcess.ts
import type { Node } from "unist";
import type { VFile } from "vfile";

export function childProcess(node: Node, file: VFile): void {
  node.children.forEach((child) => {
    if(child.tagName === "body") {
      childProcess(child, file);
      return;
    }

    if (child.tagName === "p") {
      file.value += '<!-- wp:paragraph -->' + '<p>' 
      childProcess(child, file);
      file.value += '</p>' + '<!-- /wp:paragraph -->'
      return;
    }

    if (child.type === 'text') {
      file += node.value
      return;
    }
  })
}

以下でパースされたHTMLのNodeを受け取り、子Nodeをループして取り出しています。

export function childProcess(node: Node, file: VFile): void {
  node.children.forEach((child) => {

WordPressにはbodyタグは不要なのでそのまま再帰で自分自身に渡しています。

if(child.tagName === "body") {
  childProcess(child, file);
  return;
}

子Nodeにpタグが見つかればWordPressブロックのコメントを結果に追加します。
pタグのテキストはpタグの子Nodeとして入っているので再帰で渡し最後に閉じタグを追加します。

if (child.tagName === "p") {
  file.value += '<!-- wp:paragraph -->' + '<p>' 
  childProcess(child, file);
  file.value += '</p>' + '<!-- /wp:paragraph -->'
  return;
}

typetextのNodeはそのまま結果に追加します。Nodeにはtypeが存在しており要素はelement、テキストはtextで入っています。
今回の例で行くとpタグのtestの文字列はtypeがtextのNodeになります。

if (child.type === 'text') {
  file += node.value
  return;
}

これで変換が完了します。

最後に

テキスト上だと少しややこしいですが何かの参考になれば……。

GitHubで編集を提案
SMARTCAMP Engineer Blog

Discussion