― Table of Contents Plus × Gutenberg × REST API 地雷の正体と対処法
発生するエラーの状況
- WordPressのブロックエディタ(Gutenberg)で投稿を保存しようとすると
- 「更新に失敗しました。返答が正しい JSON レスポンスではありません」
- Table of Contents Plus (TOC+)プラグインを使用している
再現条件と環境
- WordPress 8.1.2
- テーマ: オリジナルテーマ
- Gutenbergエディタ使用
- TOC+ バージョン: 2411.1
- 仮ドメイン + 非SSL
エラーの技術的原因
- GutenbergはREST APIで投稿を保存する
- REST APIの
rendered
フィールドにHTMLが含まれる -
[toc]
は<!--TOC-->
に置き換われ、the_content()
フィルターでHTMLに変換される - そのHTMLの中に置き換符号の欠如やJSONと互換性のない文字列があると
JSON.parse()
が爆死
やった対策一覧
プラグイン側
- TOC+ の設定画面で「REST APIに直接含める」を OFFにする
テーマ側
-
rest_prepare_post
フィルターでREST APIのrendered
だけTOC+を取り除いて再生成
5. 最終的な回避コード
add_filter( 'rest_prepare_post', function( \$response, \$post, \$request ) {
remove_filter( 'the_content', [ \$GLOBALS['toc_plus'], 'the_content' ], 100 );
\$response->data['content']['rendered'] = apply_filters( 'the_content', \$post->post_content );
add_filter( 'the_content', [ \$GLOBALS['toc_plus'], 'the_content' ], 100 );
return \$response;
}, 10, 3 );
これをfunctions.php
に追記することで、
- 投稿本文に
[toc]
は残せる - 表示もそのまま
- でもREST APIレスポンスだけTOCを削除でき、JSON.parse()エラーを防げる
補足: SSL環境での違い、Classic Editorとの関係
- SSLでない場合:
SameSite=Lax
のCookieがRESTで送れず、未認証として返答が戻り、Gutenbergが爆死することがある - Classic EditorならRESTを通らず、そもそもこの問題が起こらない
まとめと教訓
- 表示に問題がなくても、REST APIの
rendered
が正式でないとJSONエラーは起きる - TOC+ の出力はちょっと前のタイミングでREST系には向いてない
- 「入力は売る、出力はメンテする」の大事さを思い知らされた
- いずれ直したのも、分析してコード書いたのも、しんどかったのも、結局ずっと現場にいた自分だった
使う側はわけもわからん。説明もない。でも実際には、たったこれだけで?ってなる1行のフィルターで、WordPress保存エラーは消える。
「保存失敗」を、少なくともこの現場からは消したい。