Math block icon WordPress math block plugin icon showing a formula block with sigma symbol Σ WordPress 6.9〜7.0 の数式ブロッ
ク対応
(latex変換プラグインの更新)

  • WordPress 6.9〜7.0 へのアップデートで、LaTeX貼り付け変換プラグインが動かなくなった原因は window.wp.latexToMathml の消失で、Script Module 化された @wordpress/latex-to-mathml を dynamic import するよう修正して解決しました。
  • display math を core/html ブロックで挿入していたため WordPress から「HTML の中の MathML 文字列」にしか見えておらず、core/math ブロックへ切り替えることで LaTeX 属性の保持と保存形式の整合が取れました。
  • WordPress 7.0 での Math block の変化は「LaTeX入力欄の等幅フォント化」と「色・余白・枠線などのスタイル supports 追加」の2点で、保存形式の根本的な変更はありませんでした。
  • window.wp.* グローバルへの依存はバージョンアップで静かに壊れるリスクがあり、コアの実装に沿って dynamic import で解決する方針に切り替えることが今後の安全策です。

関連記事

1. 問題

WordPress 6.9 で Math block が追加され、7.0 でスタイル機能が追加されました1
LaTeX 貼り付けを MathML へ変換するプラグインをメンテしていたところ、この変化への追従で3つの問題に順番に当たりました。
修正内容と背景にある仕様を整理します。

1.1. 問題の全体像

症状はシンプルでした。
WordPress をアップデートしたら、LaTeX の貼り付け変換が動かなくなりました。
$$...$$ が未変換のまま paragraph に残り、display math も inline math も通常テキストとして保存されます。

ログを確認すると、tokenizer は正常に動いており、mathCount も期待どおり増えていました。
LaTeX を検出する部分は壊れていなかった2
変換実行の手前で詰まっていることがわかりました。

2. 問題 1:window.wp.latexToMathml が消えていた

2.1. 何が起きていたか

実機ログで次を確認しました。

coreMathRegisteredInRegistry: true
coreMathRegisteredInStore: true
latexToMathmlType: "undefined"
wpMathRelatedKeys: []Code language: HTTP (http)

core/math ブロックは正常に登録されていました。
しかし window.wp.latexToMathml は存在しませんでした3

プラグインはこのグローバルを直接呼んでレンダラーを取得していたため、ここで静かに失敗し、LaTeX をそのままフォールバック出力していました。

2.2. なぜ消えたか

WordPress 6.9 で @wordpress/latex-to-mathml パッケージが追加された時点では、wpScript: true 付きで読み込まれており、window.wp.* グローバルに生える前提がある程度成立していました。
ところが PR #73099「MathML block: fix lazy script loading」で、Math block が存在しない場合でも常時読み込まれていた問題が修正され、Script Module 経由の遅延読み込みに切り替わりました4

現在の packages/latex-to-mathml/package.json には wpScriptModuleExports が定義されており、wpScript は存在しません5
コアの edit.jsimport('@wordpress/latex-to-mathml') で動的 import する実装になっています。

2.3. 修正

レンダラー解決を 2 段構えにしました。

// 修正前
const latexToMathml = window.wp?.latexToMathml ?? window.wp?.latexToMathml?.default;
if (!latexToMathml) {
  return fallbackOutput(latex); // ここで静かに失敗していた
}Code language: JavaScript (javascript)
// 修正後
async function resolveRenderer() {
  // 1段目:グローバルが存在する環境はそのまま使う
  const global = window.wp?.latexToMathml ?? window.wp?.latexToMathml?.default;
  if (typeof global === 'function') return global;

  // 2段目:Script Module 経由で解決する
  const module = await import('@wordpress/latex-to-mathml');
  return module.default ?? module.latexToMathML;
}Code language: JavaScript (javascript)

貼り付けイベントで、グローバルが即時取得できる場合は従来どおり同期処理します。
module 解決が必要な場合のみ非同期で待ち、Promise 完了後にブロック差し替えを行います。
実機では display math と inline math の両方が再び MathML へ変換されることを確認しました。

3. 問題 2:display math を core/html で挿入していた

renderer が直ったあと、今度は「変換は成功しているが、ブロックとして core/html に入っている」問題が浮かびました。

3.1. core/htmlcore/math の違い

core/html は任意の HTML を直接保持するブロックです。
block.json では content 属性が source: "raw" で、save()RawHTML でそのまま出力します。
数式専用の UI も LaTeX 属性も持ちません6

core/math は数式専用のブロックです。
latex 属性に入力 LaTeX を、mathML 属性に <math> 要素の内側 HTML を保持します。
スタイル supports として色・余白・枠線・フォントサイズも有効化されており、再編集時に LaTeX 入力欄が使えます7

core/html で display math を入れていた状態では、WordPress からは「HTML block の中に MathML らしき文字列がある」にしか見えていませんでした。
core/math としての扱いを受けられていませんでした。

3.2. 修正

createDisplayMathBlock() の返す block を切り替えました。

// 修正前
function createDisplayMathBlock(mathMLString) {
  return wp.blocks.createBlock('core/html', {
    content: mathMLString, // <math display="block">...</math> 全体
  });
}Code language: JavaScript (javascript)

// 修正後
function createDisplayMathBlock(latex, mathMLString) {
  // core/math の mathML 属性は <math> の内側だけを受け取る
  const innerMathML = extractInnerMathML(mathMLString);

  return wp.blocks.createBlock('core/math', {
    latex: latex,
    mathML: innerMathML,
  });
}

function extractInnerMathML(mathMLString) {
  const parser = new DOMParser();
  const doc = parser.parseFromString(mathMLString, 'text/html');
  const math = doc.querySelector('math');
  return math ? math.innerHTML : '';
}Code language: JavaScript (javascript)

core/mathsave()<div><math display="block" dangerouslySetInnerHTML={{ __html: mathML }} /></div> で保存するため、mathML 属性に渡すべきなのは <math> 全体ではなく inner HTML です。
名前だけ core/math に変えて <math>...</math> 全体を渡すと、コアの保存形式とズレます8

3.3. 実機確認

修正後の保存コードはこうなりました。

<!-- wp:math {"latex":"O(n \\cdot p + n^2 \\cdot d)"} --> <div class="wp-block-math"><math display="block">...</math></div> <!-- /wp:math -->

core/math として保存され、latex 属性がブロックコメントに残っています。

4. 問題 3:WordPress 6.9〜7.0 の Math block 仕様の変化を把握できていなかった

renderer 問題と block 種別問題が解決した後、そもそも「なぜこうなったか」を整理しました。

4.1. Math block の来歴

Math block は WordPress 6.9 で追加されました。
6.9 Field Guide では、MathML と LaTeX renderer に対応し、ブロック数式だけでなく rich text 内の inline math にも対応すると説明されています。

7.0 での変化は2点です。

1つ目は、LaTeX 入力欄が等幅フォントになったことです(PR #72557)。
packages/block-library/src/math/editor.scss に次が追加されました。

.wp-block-math__textarea-control textarea {
  font-family: $font-family-mono;
  direction: ltr;
}Code language: SCSS (scss)

保存される MathML には影響しません。
編集ポップオーバー内の入力欄の見た目の変更です。

2つ目は、block supports が追加されたことです(PR #73544)。
block.jsonsupportsanchorbordercolorspacingtypography.fontSize が追加され、display math のブロックから色・余白・枠線・フォントサイズをサイドバーで調整できるようになりました9

4.2. プラグインへの影響

保存形式が全面的に変わったわけではありません。
ただし block supports が追加されたことで、保存される HTML に class や style 属性が増えることがあります。
保存後の HTML の構造を前提にした処理がある場合は再確認が必要です。

旧保存形式(deprecated.js の v1)では <math> に直接 useBlockProps.save() が付いていましたが、現行形式では <div> ラッパーの内側に <math> があります10
wrapper 構造を前提にした検出や復元の処理は、このズレを踏む可能性があります。

5. まとめ

今回当たった問題は3つありました。

window.wp.latexToMathml が Script Module 化されたことによるレンダラー解決の失敗、display math を core/html で挿入していたことによる block 種別のズレ、そして 6.9〜7.0 の Math block 変化の把握不足です。
保存形式の根本的な変更はありませんでしたが、block supports 追加・wrapper 構造・Script Module 化という3点がプラグインの前提と静かにズレていました。

WordPress 側の仕様変化は公式 PR やコアの実装に直接当たるのが確実です。
window.wp.* グローバルに依存するコードは今後も同様のズレを踏む可能性があるため、dynamic import で解決する方針に切り替えておくのが安全です。

  1. Math block は WordPress 6.9 に同梱された Gutenberg のバージョンで追加されました。6.9 Field Guide では、MathML と LaTeX renderer に対応したブロック数式および rich text 内の inline math に対応すると説明されています。 – WordPress 6.9 Field Guide – Make WordPress Core
  2. tokenizer とは、入力テキストを $$...$$$...$ などのデリミタで区切り、数式トークンと通常テキストに分類する処理です。この段階では LaTeX の文字列としての検出だけを行っており、MathML への変換は行いません。
  3. WordPress では従来、wp-scripts ビルドで wpScript: true を持つパッケージが window.wp.パッケージ名 というグローバル変数として読み込まれる仕組みがありました。@wordpress/blockswindow.wp.blocks として使えるのも同じ仕組みです。 – @wordpress/build – Block Editor Handbook
  4. WordPress の Script Modules API は 6.5 で導入されました。<script type="module"> タグで読み込まれ、import map によってモジュール識別子と URL が紐づけられます。従来の wp_enqueue_script とは独立した仕組みで、スクリプトとモジュールの間で依存関係を共有することはできません。 – Script Modules in 6.5 – Make WordPress Core
  5. wpScriptModuleExports は Gutenberg のビルドシステムが参照する内部フィールドで、そのパッケージを WordPress の Script Module としてバンドルする対象に含めることを宣言します。サードパーティ向けの公開 API ではなく、Gutenberg 自身のビルドパイプラインが読み取ります。 – PR #66428 – WordPress/gutenberg
  6. core/html では、unfiltered_html 権限を持たないユーザーが CSS や JavaScript を含む HTML を保存しようとすると、保存時にそれらが除去されます。数式目的で <math> 要素のみを保持する場合はこの問題に当たりにくいですが、スクリプトを含む HTML を扱う場合は注意が必要です。 – packages/block-library/src/html/modal.js – WordPress/gutenberg
  7. MathML は現在、Chrome・Firefox・Safari・Edge の主要ブラウザすべてでネイティブサポートされています。Chrome は 109 から MathML Core に対応しており、以前のように MathJax などの JavaScript ライブラリでの polyfill が必須という状況ではなくなっています。 – MathML in Web Browsers – Igalia
  8. @wordpress/latex-to-mathml の内部では、LaTeX→MathML の変換に temml ライブラリを使っています。temml は KaTeX をフォークして HTML 出力部分を削除し、MathML 出力に特化した軽量ライブラリです。minified で約 170KB と MathJax の半分程度のサイズです。 – Temml – GitHub
  9. PR #73544 のレビュー会話では、typography support に fontSize だけを含め、letterSpacingtextTransform などは除外した理由について、「数式フォントにそれらの調整は馴染まない」という判断が示されています。 – Math: enable styles options – PR #73544
  10. Gutenberg ブロックの deprecated.js は、保存形式が変わった際に旧バージョンの save() を保持するファイルです。WordPress はブロックを読み込む際に現行の save() と保存済み HTML を比較し、一致しない場合は deprecated にある旧バージョンを順番に試してブロックを復元します。旧形式のまま保存されているコンテンツも、このしくみで引き続き正しく表示されます。 – packages/block-library/src/math/deprecated.js – WordPress/gutenberg