レビュアーから「最低でも、サイト所有者の明示的な同意を得てから変更してください」と書かれたので、そのとおりに同意フローを実装しました。管理画面に通知を出して、ワンクリックのボタンを置いて、current_user_can と nonce で守って、同意した記録をオプションに保存して。
再提出して、返ってきたのは、また差し戻しでした。
同じ箇所が、また指摘されている。今度のコメントには、こう添えられていました。「同意があっても、実行コードの書き込みは許可されません」。
言われたとおりにしたのに落ちた、という経験は、なかなか堪えます。ただ、そこで初めて、自分がルールの読み方を間違えていたことに気づきました。ページキャッシュのプラグインをWordPress.orgに登録するまでに、6月9日の申請から承認まで1か月とすこし、やり取りは10回を超えました。その記録を、これから申請する人のために置いておきます。
何を作っていたか
ページキャッシュのプラグインです。
この種のプラグインは、伝統的に2つのファイルに触ります。wp-config.php に define( 'WP_CACHE', true ); を足すことと、wp-content/advanced-cache.php というドロップインを置くこと。この組み合わせが、WordPressが公式に用意しているページキャッシュの仕組みです。
だから自分は、これは当然許されるものだと思っていました。標準の仕組みを、標準どおりに使っているだけなので。この思い込みが、1か月の始まりでした。
1回目の指摘:3種類
最初のレビューで、3つのカテゴリを指摘されました。
実行コードの書き込み。wp-config.php に WP_CACHE の行を書く処理と、advanced-cache.php を文字列から組み立てて書き出す処理。指摘のコメントは、こうでした。文字列から生成しているのは「コードを書いている」ことになる、と。
ファイルの場所の決め方。ABSPATH を前提にした判定が、あちこちにありました。テーマやプラグインのディレクトリがWordPressのルート外に移されている構成だと壊れる、という指摘です。WP_CONTENT_DIR、WP_PLUGIN_DIR、get_theme_root()、wp_upload_dir() を使え、と。全部で16箇所ありました。
インラインの style / script。出力バッファでHTMLを書き換えるときに <style> や <script> を返している箇所です。wp_enqueue_* を使えという定型の指摘でした。
直したつもりが、半分だった
まず、advanced-cache.php の生成をやめました。文字列から組み立てるのではなく、プラグインにテンプレートを同梱して、それをコピーして、このインストール固有のパスだけ埋める形に変えました。ドロップインはWordPressが定数を用意する前に読まれるので、パスはコピー時に確定させる必要があります。
ABSPATH 前提の判定も直しました。画像変換の許可パス判定を、WP_CONTENT_DIR とプラグインディレクトリと get_theme_root() と wp_get_upload_dir() から解決する形に。残った ABSPATH 参照は、コア側のファイルを読むための、代替APIが存在しない箇所だけになりました。
インラインの <style> / <script> については、直すのではなく、説明しました。これはエンキューの段階ではなく、すでにレンダリングされ終わったHTMLを出力バッファで書き換えている箇所で、その時点でエンキューのハンドルは存在しない、と。管理画面側のインラインJSは wp_add_inline_script() を使っている、とも添えました。
この説明は、受け入れられました。7月5日の返信で「ドロップインの設置、残った ABSPATH 参照、出力バッファで生成されるインライン CSS/JS についての説明で十分です」と返ってきています。説明で通ることもある、というのは、この審査で得た収穫のひとつでした。指摘が全部「直せ」ではなく、事情を説明すれば納得してもらえる場合がある。ただし、簡潔に、具体例を添えて書く必要があります。
そして、残ったのが wp-config.php でした。
「同意を得てから」という助言と、その落とし穴
7月5日の返信には、こう書かれていました。WP_CACHE 定数が必要な理由は理解しているが、自動で書き換えるのは避けてほしい。最低でも、サイト所有者の明示的な同意を得てから変更してほしい、と。
自分はこれを、「同意さえ取れば書いていい」と読みました。それで、1.10.28 で同意フローを実装しました。
有効化時には何も書かない。定数が既にあれば何もしない。無ければ管理画面に通知を出して、「ページキャッシュには define( 'WP_CACHE', true ); が必要です」と説明し、ワンクリックで追加するボタンと、手で貼るためのスニペットの両方を見せる。ボタンには current_user_can( 'manage_options' ) と nonce。同意はオプションに記録し、アンインストール時に削除。追加する行には // Added by Prime Cache と印を付けて、無効化時にはその印の行だけを消す。
我ながら、ていねいに作ったと思います。そして、落ちました。
7月8日の差し戻しに付いていたコメントは、こうでした。同意があっても、wp-config.php に実行コードを書くのは許可されない。 そして object-cache.php についても、生成したPHPコードで置き換えるのはキャッシュプラグインであっても許可されず、コピーしたドロップインだけが許される、と。
ここで、ようやく分かりました。「同意を得てから」は、書き込みを認めたうえでの条件ではなく、それでも書くならせめて、という譲歩の言い方だったんです。ガイドライン本体の禁止は動いていなかった。レビュアーの助言の言葉尻を、自分に都合よく読んでいました。
通った形:書き込みを、設計から消す
1.10.29 でやったのは、同意の取り方を改善することではありませんでした。書き込みそのものを、設計から消しました。
wp-config.php に書くコードを、全部削除しました。有効化も、自己修復も、無効化も、アンインストールも、1.10.28 で作ったワンクリックのボタンも、ファイルに一切触らない。
そのうえで、WP_CACHE が無くてもページキャッシュが効く動作モードを新しく作りました。定数が無い場合は、プラグインのロード時点でキャッシュ済みのページを自分で返す。WordPressのコアは読み込まれますが、テーマもクエリもレンダリングもスキップされるので、十分に速い。そして、WordPressが読まれる前に返せる従来のドロップイン方式のほうがさらに速いので、設定画面には define( 'WP_CACHE', true ); の一行を表示しておく。追加も削除も完全に手動で、プラグインは定数の有無を検出するだけ。
object-cache.php の生成も、無料版から外しました。生成する処理は、WordPress.orgでは配布しない有料アドオン側に移しました。無料版は、自分が置いた署名付きのドロップインを削除することだけをやり、他のプラグインのファイルには触りません。
これで、7月12日に承認されました。
振り返ると、いちばん時間を溶かしたのは、禁止されている行為を、条件付きで通す方法を探していた期間でした。同意を取る、印を付ける、元に戻せるようにする。どれも誠実さの表明ではあるのですが、禁止のラインそのものは動きません。動かないラインの手前で、設計を変えるほうが、結局は速かった。
これから申請する人へ
自分の経験から、申請前に見ておくと良さそうなことを書きます。
実行可能なPHPを、プラグインが書き出していないか。 これがいちばん大きい落とし穴でした。文字列からPHPを組み立てて file_put_contents する処理があれば、まず引っかかります。ドロップインが必要なら、テンプレートファイルを同梱して、コピーする形にする。生成ではなく複製です。
ユーザーにファイルの編集を要求していないか。 「動かすには wp-config.php にこれを追記してください」を必須にすると、これも指摘対象です。追記が必須ではなく、任意の高速化オプションであれば、表示すること自体は問題になりませんでした。必須かどうかが分かれ目です。
ABSPATH を場所の前提にしていないか。 WP_CONTENT_DIR、plugin_dir_path()、get_theme_root()、wp_upload_dir() で解決できるものは、そちらを使う。ルート直下前提の判定は、移設された構成で壊れます。
指摘が理不尽に見えたら、直す前に説明してみる。 自分の場合、出力バッファでのHTML書き換えは、説明で受け入れられました。返信は簡潔に、該当箇所と理由と、既に正しくやっている部分(wp_add_inline_script() を使っている、など)を添えて書きます。
再提出のたびにテストする。 差し戻しのメールには毎回、クリーンインストールで WP_DEBUG を有効にしてテストしたか、というチェックリストが付いてきます。これを飛ばして落ちると、往復が1回増えて、単純に1週間くらい後ろにずれます。
承認されたあとの、細かい話
承認メールに書いてあって、知らないと戸惑いそうなことも書いておきます。
SVNのコミット権限は、承認から1時間以内に付与されます。SVNのユーザー名はWordPress.orgのユーザー名で、大文字小文字が区別されます。SVNのパスワードは、WordPress.orgのログインパスワードとは別物で、プロフィールの Account & Security から設定します。ここは最初、素直にログインパスワードを入れて弾かれました。
プラグインのページは、SVNにファイルを上げるまで公開されません。承認された時点では、まだ何も見えない状態です。そして、検索結果やプロフィールへの反映には、最大72時間かかることがあります。
もうひとつ。承認は、コードが安全であることの保証ではない、と明記されています。以降は手動での再レビューは行われず、コミュニティや自動スキャナが問題を検出した場合にだけ連絡が来る。そのときはプラグインが一時的に、あるいは恒久的に閉じられることもある、と。承認はゴールではなく、そこからは自分で維持する、という位置づけでした。
早見でまとめ
- 実行可能なPHPを書き出す処理は、キャッシュプラグインでも許可されない。生成ではなく、同梱テンプレートのコピーにする
- 「同意を得てから」は書き込みを許す条件ではない。ガイドラインの禁止は同意では動かない
- 禁止行為を条件付きで通す方法を探すより、書き込みが不要な設計に変えるほうが速い
-
ABSPATH前提の場所判定は指摘対象。WP_CONTENT_DIR/plugin_dir_path()/get_theme_root()/wp_upload_dir()へ - 事情のある実装は、直す前に説明してみる。簡潔に、該当箇所と理由を添えて
- 再提出前に、クリーンインストール+
WP_DEBUGでテストする。飛ばすと往復が増える - SVNパスワードはログインパスワードとは別。プラグインページはSVNに上げるまで公開されない
申請から承認まで、1か月と少し。長かったですが、落ちた理由のほとんどは、ガイドラインを自分に都合よく読んでいたことでした。役に立ったらストックして、申請の前に見返してください。
ふだんはraplsworks.comで、WordPressプラグイン開発やClaude Codeまわりのことを書いています。