経緯
WordPress で、「ある投稿タイプの記事と別の投稿タイプの記事を紐付け」たくなりました。
しかし、そのままでは紐付けはできないので、次のように考えました。
- カスタム投稿タイプ「SourcePost」、カスタム投稿タイプ「LinkedPost」、LinkedPostに紐付くカスタムタクソノミー「TaxSP」を予め作成しておく (Custom Post Type UIを利用等)
- SourcePostの記事を公開・削除等した際にアクションフックで自動的にTaxSPに「名前: SourcePostの記事タイトル」「スラッグ: プレフィックス+SourcePostの記事の投稿ID+SourcePostの記事のスラッグ」という形でタームを生成・削除することでSourcePostとTaxSPの項目名・数を常に同期させる
- LinkedPostでTaxSPの項目を選択、紐付けることで、TaxSPのスラッグからSourcePostの記事の情報を取得できるようにする
- これにより、LinkedPostの記事からSourcePostの記事の情報(タイトルやリンク)を得て、リンクジャンプさせることができる
この仕様を実装するプラグインを作成しました。
成果物
プラグイン内でやっていること
- 設定画面: SoucePostとTaxSPを紐付けする(両方ともラジオボタンでの選択)。また、他のタームとスラッグがバッティングすることを避けるためにプレフィックスも設定できるようにした
- 投稿タイプ(Radio): SourcePostを選択
- タクソノミー(Radio): TaxSPを選択
- プレフィックス(Text): 各タームに付けられるプレフィックス
- 一括生成画面:
- SourcePostに既にある記事からTaxSP内にタームを一括生成するプログラム。主にテスト用の想定。そのため、制約を厳しめにしている。
- 制約:
- ソースとなる投稿タイプに記事が1つもないとエラー
- 同期先のタクソノミーに1つでもタームが存在するとエラー
- 処理: SourcePostの記事に変更がかかると、TaxSP内にタームを追加・更新・削除していく
- SourcePostで記事を「公開(新規追加)」: TaxSPにタームを追加
- SourcePostで記事を「更新」: TaxSP内に対応するタームが存在するか探し出し(スラッグで判定)、存在すればタームの情報を記事の更新内容で上書きする
- SourcePostで記事を「ゴミ箱へ移動」: TaxSP内に対応するタームが存在するか探し出し(スラッグで判定)、タームが1つでもタクソノミーの属する先の投稿タイプの記事で使用されている(チェックが入っている)場合は何もしない。もし使用されていなければ、対応するタームを削除する
利用した機能は主に「メニュー(設定)画面」「サブメニュー画面」「アクションフック」。
挙動のサンプル
カスタム投稿とカスタムタクソノミーを紐付けと、各タームにつけるプレフィックスの設定
サンプル投稿がこうあったとして。
一括生成画面でチェックを付けて実行すると
紐付けたタクソノミーにタームが生成される。
嵌まった部分
サブメニュー画面にPOSTリクエストを投げる
一括生成画面では「POSTリクエストでシグナルを送り、シグナルが送られていたら処理を実行する」ということをやりたかったのですが、POSTリクエストの内容をデータベースに保存するわけではありません。
そのため、通常の設定画面でパラメータを wp_options
テーブル に保存する
<form method="post" action="options.php">
の action
の値が異なるものに設定する必要がありました。
<form method="post" action="admin.php?page=<?= esc_attr( '<PLUGIN_SUBMENU_SETTINGS_PAGE>' ); ?>">
と、URLバーに表示されている自身のURL(GETパラメータも含む)を指定することで解決できました。
サブメニュー画面にPOSTリクエストを投げた際にアクションフックを発動させる
上述と同じつもりでアクションフックを設定しようとしました。
function hoge()
{
echo "HOGEEEEEEEE";
}
add_action( 'admin_head-admin.php?page=PLUGIN_SUBMENU_SETTINGS_PAGE', 'hoge' );
……が、動かず。
アクションフックに指定する際はまた別のルールで定められている文字列を指定する必要がありました。
プラグインのアクションフックから外部クラスのメソッドを呼ぶ
プラグインの内部で処理ごとにクラスを分けて作成していたのですが、メインクラス→サブクラスのメソッドを呼ぶ必要が出てきました。
同じクラス内のメソッドをアクションフックから呼ぶときは
public funtion fuga () {
}
// 略
public funtion __construct (){
add_action( 'before_post_content', [ $this, 'fuga' ] );
}
こういう形で良いですが、別クラスの場合は
// Hoge.php
public funtion fuga () {
}
// main.php
public funtion __construct (){
add_action( 'before_post_content', [ new Hoge(), 'fuga' ] );
}
こんなイメージ。クラスの指定を自身 ($this
) から他クラスのインスタンスに書き換えているだけですね。
タームを生成する
タームの生成は テンプレートタグwp_insert_term()
を使用する。タクソノミー内にタームがなければ生成、ある場合は既存のタームの情報を返す、とのことなので更新は別途処理 (wp_update_term()
) が必要。
スラッグ
スラッグに日本語が混じっているとサニタイズ(パーセントエンコード)される。これに対応するために sanitize_title()
を使用。
タームをスラッグから取得する
今回、タームを生成した後にそのタームのIDは全く関知していないので、 get_term()
は利用できない。
更新・削除の際は「このタームを操作したい」と指定する必要があるので、他の方法でタームの情報を取得する必要がある。
そこで、 get_term_by()
を利用した。
get_post(), get_term_by() 等の戻り値の型を指定
get_post()
や get_term_by()
等で得られる記事やタームの情報の戻り値の型を指定するために、 WordPress 側で定数が用意されている。 OBJECT
, ARRAY_A
, ARRAY_N
。
var_dump() の内容を文字列として出力したい
デバッグ中に実際に get_posts()
で得られる記事オブジェクトの配列の中身を知りたくなったのですが、そのままだとHTMLタグが出力されてしまうので、そのまま表示させると画面の表示が崩れてしまいます。
それを回避するためにバッファリングを使用しました。
var_dump() の内容をログファイルとして出力
今度は記事を公開・更新した際のアクションフックがきちんと発動しているか確認するために get_posts()
で得られる記事オブジェクトの配列や get_term_by()
で得られるタームオブジェクトの配列の中身を知りたくなったのですが、ブロックエディタで var_dump()
したらより表示がひどいことになりそうだったのでログファイルに逃がすことにしました。
記事更新時のアクションフック
公開されている記事を更新すると publish_<POST_TYPE>
のアクションフックも発動するので、わざわざ <POST_TYPE>_updated
のアクションフックを設定する必要はない (下書きなどの状態も含めるならば必要そうですが)。
記事削除とゴミ箱に入れるアクションフック
delete_<POST_TYPE>
は記事を本当に削除するときに発動する。ゴミ箱は trash_<POST_TYPE>
。
ゴミ箱に入れた記事のスラッグ
ゴミ箱に入れると記事のスラッグの末尾に __trashed
と付く。「ゴミ箱に入れたら、その記事のスラッグと同じタームを削除」という判定を書いていても、 __trashed
の有無で不一致を起こす。
$term = get_term_by(
'slug',
preg_replace('/(__trashed)$/i', '', sanitize_title($prefix . '-' . $post_ID . '-' . $post->post_name)),
$taxonomy,
OBJECT
);
例えばこんな形で __trashed
を除去してからマッチングさせること。
explode() の制限
PHPの explode()
は第三引数で区切り文字による分割の回数を制限できる。
$termStrs = explode('-', $term->slug, 3); // - で区切るのは3個まで
例えばスラッグで prefix-42-hoge-piyo-fuga
のようなスラッグが設定されていた場合、 prefix
, 42
, hoge-piyo-fuga
という風に分けたい。
そこで、第三引数に3つまで、ということで3
を指定することでこの挙動を実現した。
wp-env のデータベースコンテナの情報
Host: 127.0.0.1
Username: root
Database: wordpress
Password: password
DB周りの情報はこうなっている模様。なお、DBコンテナのポート番号は起動の度に変わる。
参考
Dashicon
アクションフック一覧
記事関係のアクションフック
- {$new_status}_{$post->post_type} | Hook | WordPress Developer Resources
- 投稿ステータスの遷移 – WordPress Codex 日本語版
- カスタム投稿タイプで publish_post のアクションフックを使用したいとき – 女神山の麓より
post_updated
- post_updated | Hook | WordPress Developer Resources
- WP関数『wp_insert_post』に含まれるアクションフック5つ |
- Nuxt.js + WP REST API のサイトで記事を保存したら、GitHub Actions経由で自動デプロイされるように設定する | 12px.com
- [Wordpress] 記事更新前後の内容を取得したい – KayaMemo
trash_post
サブメニューを作る
- add_submenu_page() | Function | WordPress Developer Resources
- WordPress メニュー・管理画面・オプション・設定等のメモ。 – Qiita
add_options_page
はデフォルトの「設定」メニューのサブメニューとして作成する。
投稿タイプを取得
- get_post_types() | Function | WordPress Developer Resources
- WP_Post_Type | Class | WordPress Developer Resources
応用
タクソノミーを取得
- get_object_taxonomies() | Function | WordPress Developer Resources
- WP_Taxonomy | Class | WordPress Developer Resources
options.php
- 【WordPress】知ってる?『options.php』でいろんな設定ができるんだって | 125naroom / デザインするところ(会社)です。
- WordPressプラグインの設定画面で保存後にメッセージを出すには、POSTではなくGETのパラメータをチェックすればよかった | そんなにGeekじゃないエンジニアブログ
スラッグ
小文字の半角英数字とハイフン。
__trashed のスラッグ
- WordPressでゴミ箱の機能を無効にする方法 ? ネコでもわかるWebのメモ帳
- __trashedというURLがサイトマップで送信されてしまい、GoogleConsoleでエラーになる件 | アフィリエイトロード【副業から始める正しいアフィリエイト】
- __trashedというURLでWordPressの記事が表示される原因と対処法 | SSAITSのブログ
wp-env
DBポート
DB情報
- コードによるコントリビューション入門 – Japanese Team – WordPress.org
- @wordpress/env(wp-env)を使ったWordPress開発環境構築 | CodeCode
mappings
開発中のプラグインのプロジェクトディレクトリをWPイメージ内にマッピングすることは可能
通知バーのクラス
updated
で更新、処理完了。 error
でエラー。
投稿タイプ
get_posts
- get_posts() | Function | WordPress Developer Resources
- get_posts – WordPress私的マニュアル
- WP_Post | Class | WordPress Developer Resources
- テンプレートタグ/get posts – WordPress Codex 日本語版
get_post
Term オブジェクトとプロパティ
- WP_Term_Query::__construct() | Method | WordPress Developer Resources
- WordPressのタクソノミーとタームをマスターする | 滋賀/京都/大阪でホームページ制作ならYUKiYURi WEB
- WordPress タクソノミーのターム一覧の表示方法 – by Takumi Hirashima
タームの使用件数
$term->count
タクソノミーにタームを追加
- wp_insert_term() | Function | WordPress Developer Resources
- 関数リファレンス/wp insert term – WordPress Codex 日本語版
wp_insert_term と wp_create_term と wp_insert_category
- WordPress | PHPからタグを新規作成・追加する方法 | ONE NOTES
- 関数リファレンス/wp insert category – WordPress Codex 日本語版
- 賢者の漬け物石: WordPress関数でのカテゴリ追加
近い役割のものたち。
wp_insert_term()
: タクソノミー全般、新規作成が可能 (既に指定タームが存在する場合は既存タームの情報を返す)wp_create_term()
: タクソノミー全般、新規作成のみ可能 (更新は不可)wp_insert_category()
: カテゴリー専用、新規作成が可能
という違いということでOK?
wp_update_term
wp_delete_term
- wp_delete_term() | Function | WordPress Developer Resources
- 関数リファレンス/wp delete term – WordPress Codex 日本語版
未使用
CSV Importer
- CSV Importerで階層のあるカスタムタクソノミーをインポートする ? モンキーレンチ
- csv_importer.php in csv-importer/trunk ? WordPress Plugin Repository