👌

[toc] を使ったら WordPress 投稿が『返答が正しい JSON レスポンスではありません』で保存できなくなった話

に公開

― 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保存エラーは消える。
「保存失敗」を、少なくともこの現場からは消したい。

Discussion