管理画面の投稿一覧・投稿編集画面でカテゴリの一覧の表示を少なくするプラグインを作りました。
経緯
カテゴリを大量に使用している WordPress サイトがあるのですが、投稿編集画面や投稿一覧画面でカテゴリを選択使用とした際にどこにあるのかスクロールバーを右往左往させることが多いのが悩みでした。
サイトの用途として
- フロント側:
- カテゴリで記事を辿ることがままある (検索的な用途)
- カテゴリの一覧としては残しておきたい
- 「カテゴリを削除・整理する」のは今回の用途では不適
- カテゴリの一覧としては残しておきたい
- カテゴリで記事を辿ることがままある (検索的な用途)
- 管理画面:
- カテゴリの新規追加はそこそこある
- 過去記事もカテゴリを付け直すことがある (上述の検索用途のため)
- ただし、一度追加した既存のカテゴリはホットな時期が終われば以降はほぼ再利用しない
- カテゴリの新規追加はそこそこある
という状態です。端的に言えば「追加するだけ追加するけど、一定の期間を終えたらそのカテゴリを使用することはほぼない」「検索用途として使用するため、カテゴリの削除は基本しない」という運用です。
そうなると、冒頭のように「(編集の際に)大量のカテゴリのチェックボックスからスクロールしまくって目的のカテゴリを探す」羽目になるわけです。
これをどうにかしたい。
機能
この悩みを解決するために、以下のような機能を考えました。
- 設定画面:
- カテゴリの一覧から非表示にするカテゴリを選択する
- カテゴリを選択した際に子孫カテゴリがいる場合は、これも一括で非表示にする
- カテゴリの一覧から非表示にするカテゴリを選択する
- 投稿一覧画面:
- 設定画面で選択したカテゴリを非表示
- 新規投稿画面・投稿編集画面:
- 設定画面で選択したカテゴリを非表示
- フロント画面:
- 記事のカテゴリ一覧の出力やカテゴリアーカイブのウィジェット等、カテゴリの表示は上述の設定に依らず通常通り全てのカテゴリを表示する
プラグイン
できたものがこちらになります。
動作デモ(キャプチャ画像)
1. カテゴリのサンプル
まずは準備。適当な WordPress サイトを Docker 等で建てて上述のようなサンプルのカテゴリを作成します。
- test
- テスト子供1
- テスト孫1
- テストひ孫1
- テスト孫1
- テスト子供2
- テスト子供1
- サンプル
- サンプル子供
- 未分類 (デフォルト)
これで試験します。
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」「サンプル子供」のカテゴリに所属していることを確認しておきます。
続いてプラグインを有効化し、以下のように非表示設定をします。
- test
- ✅テスト子供1
- ✅テスト孫1
- ✅テストひ孫1
- ✅テスト孫1
- テスト子供2
- ✅テスト子供1
- サンプル
- ✅サンプル子供
- 未分類 (デフォルト)
先ほどの投稿では、上述の通り「テスト子供2」は残りますが、「テスト孫1」「サンプル子供」の2つは非表示になります。
投稿編集画面で「テスト孫1」「サンプル子供」が非表示になっていることを確認。「テスト子供2」だけ表示上残っています。
この状態で「未分類」カテゴリにも所属するようにチェックを付けて「更新」します。
投稿一覧画面で元々チェックが付いていて表示されていた「テスト子供2」、新規で追加した「未分類」はもちろん、非表示になっている「テスト孫1」「サンプル子供」も依然として所属していることが確認できました(原案時点、 display: none;
で全くの非表示にした場合は「テスト孫1」「サンプル子供」のチェックが外れてしまったので、若干の工夫が必要でした)。
なお、投稿編集画面のカテゴリは以下の操作を行う度にメニューの中が再描画されるため、最初の編集画面表示時以外のタイミングでも非表示にするように JavaScript の調整が必要でした。
- ⚙ボタンを押してメニューの表示・非表示を切り替える
- タブで「ブロック」を表示させた後、「文書」タブに戻る
4. 投稿一覧画面
続いて投稿一覧画面。
いったん先ほどのテスト投稿のカテゴリを「テスト子供2」「テスト孫1」「サンプル子供」の3つに戻しておきます。
この状態で「クイック編集」をクリックし、カテゴリの一覧を表示させます。先ほどと同様、「テスト孫1」「サンプル子供」の2つは非表示になっています。
この状態で「更新」。
投稿一覧画面に戻り、依然「テスト子供2」「テスト孫1」「サンプル子供」の3つに所属し続けています。
躓いたポイント
- カテゴリの一覧を親子関係を保持したまま表示させるために
Walker_Category_Checklist
クラス をカスタマイズした- 設定画面だけでなく、投稿一覧画面で項目を非表示にする際も同様の手法を採用
- 投稿編集画面で JavaScript 側で非表示の制御をかけた点(結局 jQuery で頑張ることに)
- 上述したように、「⚙ボタンを押す」「ブロック→文書に戻る」などのタイミングで再描画が走ってしまうため、再度非表示にする処理が走るように調整
- 投稿編集画面、投稿一覧画面共に非表示の項目を
display: none;
で潰してしまうと、保存時にチェックが外れてしまうので 1x1px でposition: absolute;
して……など、「見た目上は非表示に見えるが要素としては存在している」状態にした wp_terms_checklist_args
は投稿編集画面、投稿一覧画面以外でもフックが発火するので、「管理画面内」全体でアクションフックを掛けると動作に不具合が出るため、アクションフック発火前に別個でページ判定を実施し、意図した部分だけアクションフックが掛かるように制限した点- 独自 css や JavaScript を読み込むアクションフックについてはそこまでシビアではないので、メソッド内で
$hook_suffix
で判定して回避可能
- 独自 css や JavaScript を読み込むアクションフックについてはそこまでシビアではないので、メソッド内で
- 上述したように、非表示の処理の際にカテゴリの階層が深くなってしまうと探索が難しいので、設定画面で親カテゴリにチェックを付けたら子孫カテゴリ全てに連動してチェックを付けるように処理を追加
他、WordPress の head タグの中を整理するプラグイン (設定画面付き) の自作に類する点。
連続でプラグインを作ったことで、ある程度知見を貯めることはできたのではないかと個人的には思います。
備考
今回は
- カテゴリの兄弟や子孫(一本の木の中の枝、森の中の木)を非表示(切る)にする
- 非表示にする(見えない)
- あくまで非表示にするだけで、削除などの実際のデータに影響を及ぼすわけではない(気配はあるが、証拠が掴めない)
というイメージから、「木の切り落とす音はするが、音のした方向を探しても倒れた木が見付からない」怪異である古杣(ふるそま)を採用しました。
なお、類似の怪異は「天狗倒し」「天狗ナメシ」「空木(からぎ)倒し」「空木(そらぎ)倒し」「天崩し」「木伐り坊」等のバリエーションがあります。
参考
JavaScript
jQueryで描画完了後に動作
jQueryでDOMの変化をキャッチして動作
JavaScriptで要素の存在判定
親要素のチェックボックスをチェックしたら子孫要素のチェックボックスもチェックする
PHP
in_array
json_encode
htmlspecialchars
parse_url
mb_strpos
- 文字列展開(恒等関数)
WordPress
投稿編集画面のカスタマイズ
コード参考: Adjust Admin Categories
関数リファレンス
- 関数リファレンス/wp enqueue style – WordPress Codex 日本語版
- 関数リファレンス/plugins url – WordPress Codex 日本語版
- checked – WordPress私的マニュアル
- get_option – WordPress私的マニュアル
- maybe_unserialize – WordPress私的マニュアル
- get_term – WordPress私的マニュアル
フィルターフック
フィルターフック一覧
- 【WordPress 入門】WordPress で使えるアクション・フィルターフックの呼び出し元をまとめてみた | 滋賀/京都/大阪でホームページ制作ならYUKiYURi WEB
- プラグイン API/フィルターフック一覧 – WordPress Codex 日本語版
wp_terms_checklist_args
- 関数リファレンス/wp terms checklist – WordPress Codex 日本語版
- 解決!WordPress投稿画面のカテゴリーをカスタマイズする方法 | 東京のWeb制作会社LIG
- カテゴリー選択チェックボックスを表示するwp_category_checklistの使い方 ? Fantastech(ファンタステック)
- WordPress/class-walker-category-checklist.php at master ・ WordPress/WordPress
- 関数リファレンス/get post types – WordPress Codex 日本語版
- 関数リファレンス/get object taxonomies – WordPress Codex 日本語版
- 関数リファレンス/is taxonomy hierarchical – WordPress Codex 日本語版
- 関数リファレンス/get terms – WordPress Codex 日本語版