WordPress の管理画面内のみ特定の投稿のカテゴリを非表示にするプラグイン

管理画面の投稿一覧・投稿編集画面でカテゴリの一覧の表示を少なくするプラグインを作りました。

経緯

カテゴリを大量に使用している WordPress サイトがあるのですが、投稿編集画面や投稿一覧画面でカテゴリを選択使用とした際にどこにあるのかスクロールバーを右往左往させることが多いのが悩みでした。

サイトの用途として

  • フロント側:
    • カテゴリで記事を辿ることがままある (検索的な用途)
      • カテゴリの一覧としては残しておきたい
        • 「カテゴリを削除・整理する」のは今回の用途では不適
  • 管理画面:
    • カテゴリの新規追加はそこそこある
      • 過去記事もカテゴリを付け直すことがある (上述の検索用途のため)
    • ただし、一度追加した既存のカテゴリはホットな時期が終われば以降はほぼ再利用しない

という状態です。端的に言えば「追加するだけ追加するけど、一定の期間を終えたらそのカテゴリを使用することはほぼない」「検索用途として使用するため、カテゴリの削除は基本しない」という運用です。

そうなると、冒頭のように「(編集の際に)大量のカテゴリのチェックボックスからスクロールしまくって目的のカテゴリを探す」羽目になるわけです。

これをどうにかしたい。

機能

この悩みを解決するために、以下のような機能を考えました。

  • 設定画面:
    • カテゴリの一覧から非表示にするカテゴリを選択する
      • カテゴリを選択した際に子孫カテゴリがいる場合は、これも一括で非表示にする
  • 投稿一覧画面:
    • 設定画面で選択したカテゴリを非表示
  • 新規投稿画面・投稿編集画面:
    • 設定画面で選択したカテゴリを非表示
  • フロント画面:
    • 記事のカテゴリ一覧の出力やカテゴリアーカイブのウィジェット等、カテゴリの表示は上述の設定に依らず通常通り全てのカテゴリを表示する

プラグイン

できたものがこちらになります。

動作デモ(キャプチャ画像)

1. カテゴリのサンプル

カテゴリのサンプル
カテゴリのサンプル

まずは準備。適当な WordPress サイトを Docker 等で建てて上述のようなサンプルのカテゴリを作成します。

  • test
    • テスト子供1
      • テスト孫1
        • テストひ孫1
    • テスト子供2
  • サンプル
    • サンプル子供
  • 未分類 (デフォルト)

これで試験します。

2. 設定画面

次に設定画面。

プラグイン設定画面
プラグイン設定画面

非表示にする投稿のカテゴリを選択するチェックボックスと、 JavaScript 側の制御のタイムアウト期限の2つの枠を作りました。

前者は親子関係にきちんと沿った表示をするために Walker_Category_Checklistクラス を extends して start_elメソッド をカスタマイズしています。

後者は JavaScript でポーリングする回数の最大値(後述)です。

これについては、投稿新規作成画面と投稿編集画面でのカテゴリ一覧の非表示で壁に当たったのがきっかけで作りました。

これらの画面は AJAX 経由でカテゴリ一覧を作成しているようなので、サーバサイド( PHP )での制御は難しいと判断しました(やるとしたら、 WP REST API の出力を絞る?)。

また、仮にサーバサイドでカテゴリ一覧を絞ってしまうと、過去記事のカテゴリを整理する際に

  • プラグインで非表示にする前にチェックを付けていた
  • 記事編集時点ではプラグインで非表示設定にしている

の2つの条件を満たすカテゴリが存在した場合、チェックされずに記事の保存が行われてしまう、つまり「カテゴリに既に付けてあったチェックが外れてしまう」可能性が考えられるため、この点でもサーバサイドのみでの制御は難しいと考えました。

そこで苦肉の策ではありますが、 JavaScript で「一定時間おきにカテゴリの一覧が描画されたか(クラス editor-post-taxonomies__hierarchical-terms-list の要素があるか)をポーリング」し、「存在したことを確認したら該当カテゴリの項目を非表示にする」ことにしました。

このポーリングの回数が上述のタイムアウト期限の項目になります。

2.1. バリデーション

register_setting のコールバックにバリデーションも登録しました。

タイムアウト期限に意図しない入力値を設定する
タイムアウト期限に意図しない入力値を設定する

開発者ツールを使ってタイムアウト期限の input タグを type="number" から type="text" に変えて文字列を入力します。

バリデーションエラー (タイムアウト期限に意図しない入力値を設定して送信)
バリデーションエラー (タイムアウト期限に意図しない入力値を設定して送信)

結果、エラー表示されました。

正しい入力の場合 (タイムアウト期限)
正しい入力の場合 (タイムアウト期限)

正しい入力の場合は保存の通知が表示されます。

非表示にする項目の設定に意図しない入力値を設定する
非表示にする項目の設定に意図しない入力値を設定する

今度はチェックボックスで送信される値を操作します。

バリデーションエラー (非表示にする項目の設定に意図しない入力値を設定して送信)
バリデーションエラー (非表示にする項目の設定に意図しない入力値を設定して送信)

結果、エラー表示されました。

正しい入力の場合 (非表示にする項目の設定)
正しい入力の場合 (非表示にする項目の設定)

こちらも正しい入力の場合は保存の通知が表示されます。

2.2. 子孫要素だけチェックを外すことを阻害

「カテゴリを選択した際に子孫カテゴリがいる場合は、これも一括で非表示にする」という仕様ですが、これもやや頭を悩ませるものでした。

というのは、 Walker_Category_Checklistクラス で探索するカテゴリは「自身から見て親と子」の情報は持っていますが、親のさらに上の祖先や、逆に孫以下の情報は直接は持っていなさそうでした。

そのため、「あるカテゴリを非表示にした」場合、子供はともかく孫以降まで非表示にする判定をして行かなければなりません。

逆に、あるカテゴリに非表示のチェックが付いていなかったとしても、親より上の祖先のカテゴリが非表示チェックが付いていないか判定しなければなりません。

どちらも再帰的に探索して潰していく形になるので、そこそこ面倒かと。

今回は実装スピードを重視したかったので、上述のような再帰的な判定ではなく、「設定画面であるカテゴリにチェックを付けたら、子孫カテゴリも全て連動してチェックを付ける」機能を JavaScript 側で実装しました。

親以上のカテゴリでチェックが付いていたら子孫カテゴリはチェックを外せない
親以上のカテゴリでチェックが付いていたら子孫カテゴリはチェックを外せない

そこで、「親以上のカテゴリでチェックが付いていたら子孫カテゴリはチェックを外せない」という機能も追加しました。

3. 投稿編集画面

続いて、投稿編集画面(新規投稿、既存投稿の編集)。

テストのため、「テスト子供2」の他に、非表示にする予定の「テスト孫1」「サンプル子供」もカテゴリとしてチェックを付ける
テストのため、「テスト子供2」の他に、非表示にする予定の「テスト孫1」「サンプル子供」もカテゴリとしてチェックを付ける

テストのため、一度プラグインを無効化して、表示し続ける予定の「テスト子供2」の他に、非表示にする予定の「テスト孫1」「サンプル子供」もカテゴリとしてチェックを付けておきます。

投稿一覧画面で「テスト子供2」「テスト孫1」「サンプル子供」のカテゴリに所属していることを確認
投稿一覧画面で「テスト子供2」「テスト孫1」「サンプル子供」のカテゴリに所属していることを確認

投稿一覧画面で「テスト子供2」「テスト孫1」「サンプル子供」のカテゴリに所属していることを確認しておきます。

続いてプラグインを有効化し、以下のように非表示設定をします。

  • test
    • ✅テスト子供1
      • ✅テスト孫1
        • ✅テストひ孫1
    • テスト子供2
  • サンプル
    • ✅サンプル子供
  • 未分類 (デフォルト)

先ほどの投稿では、上述の通り「テスト子供2」は残りますが、「テスト孫1」「サンプル子供」の2つは非表示になります。

投稿編集画面で「テスト孫1」「サンプル子供」が非表示になっていることを確認
投稿編集画面で「テスト孫1」「サンプル子供」が非表示になっていることを確認

投稿編集画面で「テスト孫1」「サンプル子供」が非表示になっていることを確認。「テスト子供2」だけ表示上残っています。

投稿編集画面で「未分類」もチェック
投稿編集画面で「未分類」もチェック

この状態で「未分類」カテゴリにも所属するようにチェックを付けて「更新」します。

投稿一覧画面で「テスト子供2」「未分類」「テスト孫1」「サンプル子供」に所属していることを確認
投稿一覧画面で「テスト子供2」「未分類」「テスト孫1」「サンプル子供」に所属していることを確認

投稿一覧画面で元々チェックが付いていて表示されていた「テスト子供2」、新規で追加した「未分類」はもちろん、非表示になっている「テスト孫1」「サンプル子供」も依然として所属していることが確認できました(原案時点、 display: none; で全くの非表示にした場合は「テスト孫1」「サンプル子供」のチェックが外れてしまったので、若干の工夫が必要でした)。

なお、投稿編集画面のカテゴリは以下の操作を行う度にメニューの中が再描画されるため、最初の編集画面表示時以外のタイミングでも非表示にするように JavaScript の調整が必要でした。

  • ⚙ボタンを押してメニューの表示・非表示を切り替える
  • タブで「ブロック」を表示させた後、「文書」タブに戻る

4. 投稿一覧画面

続いて投稿一覧画面。

投稿一覧画面で「テスト子供2」「テスト孫1」「サンプル子供」に所属していることを確認
投稿一覧画面で「テスト子供2」「テスト孫1」「サンプル子供」に所属していることを確認

いったん先ほどのテスト投稿のカテゴリを「テスト子供2」「テスト孫1」「サンプル子供」の3つに戻しておきます。

クイック編集のカテゴリ一覧の表示
クイック編集のカテゴリ一覧の表示

この状態で「クイック編集」をクリックし、カテゴリの一覧を表示させます。先ほどと同様、「テスト孫1」「サンプル子供」の2つは非表示になっています。

この状態で「更新」。

投稿一覧画面で「テスト子供2」「テスト孫1」「サンプル子供」に所属していることを確認
投稿一覧画面で「テスト子供2」「テスト孫1」「サンプル子供」に所属していることを確認

投稿一覧画面に戻り、依然「テスト子供2」「テスト孫1」「サンプル子供」の3つに所属し続けています。

躓いたポイント

  • カテゴリの一覧を親子関係を保持したまま表示させるために Walker_Category_Checklistクラス をカスタマイズした
    • 設定画面だけでなく、投稿一覧画面で項目を非表示にする際も同様の手法を採用
  • 投稿編集画面で JavaScript 側で非表示の制御をかけた点(結局 jQuery で頑張ることに)
    • 上述したように、「⚙ボタンを押す」「ブロック→文書に戻る」などのタイミングで再描画が走ってしまうため、再度非表示にする処理が走るように調整
  • 投稿編集画面、投稿一覧画面共に非表示の項目を display: none; で潰してしまうと、保存時にチェックが外れてしまうので 1x1px で position: absolute; して……など、「見た目上は非表示に見えるが要素としては存在している」状態にした
  • wp_terms_checklist_args は投稿編集画面、投稿一覧画面以外でもフックが発火するので、「管理画面内」全体でアクションフックを掛けると動作に不具合が出るため、アクションフック発火前に別個でページ判定を実施し、意図した部分だけアクションフックが掛かるように制限した点
    • 独自 css や JavaScript を読み込むアクションフックについてはそこまでシビアではないので、メソッド内で $hook_suffix で判定して回避可能
  • 上述したように、非表示の処理の際にカテゴリの階層が深くなってしまうと探索が難しいので、設定画面で親カテゴリにチェックを付けたら子孫カテゴリ全てに連動してチェックを付けるように処理を追加

他、WordPress の head タグの中を整理するプラグイン (設定画面付き) の自作に類する点。


連続でプラグインを作ったことで、ある程度知見を貯めることはできたのではないかと個人的には思います。

備考

今回は

  • カテゴリの兄弟や子孫(一本の木の中の枝、森の中の木)を非表示(切る)にする
  • 非表示にする(見えない)
  • あくまで非表示にするだけで、削除などの実際のデータに影響を及ぼすわけではない(気配はあるが、証拠が掴めない)

というイメージから、「木の切り落とす音はするが、音のした方向を探しても倒れた木が見付からない」怪異である古杣(ふるそま)を採用しました。

なお、類似の怪異は「天狗倒し」「天狗ナメシ」「空木(からぎ)倒し」「空木(そらぎ)倒し」「天崩し」「木伐り坊」等のバリエーションがあります。

参考

JavaScript

jQueryで描画完了後に動作

jQueryでDOMの変化をキャッチして動作

JavaScriptで要素の存在判定

親要素のチェックボックスをチェックしたら子孫要素のチェックボックスもチェックする

PHP

WordPress

投稿編集画面のカスタマイズ

コード参考: Adjust Admin Categories

関数リファレンス

フィルターフック

フィルターフック一覧

wp_terms_checklist_args

Walker_Category_Checklist

admin_print_styles

hook_suffix

設定画面でチェックボックスを使用

この記事を書いた人

アバター

アルム=バンド

フロントエンド・バックエンド・サーバエンジニア。LAMPやNodeからWP、Gulpを使ってejs,Scss,JSのコーディングまで一通り。たまにRasPiで遊んだり、趣味で開発したり。