WordPressでカスタム投稿タイプを追加してプラグイン(ACF)でカラムを管理画面から管理できるようにして表示する
課題
テーブル風のデータグループにひもづいたデータを取り回しつつ、管理画面からクライアントがデータを管理できるようにするのがむずかしかった。プラグインの使用は最小に抑えたいし、functions.php
への関数記述も最小に抑えたい。
概要(手続き)
- カスタム投稿タイプを増やす
- プラグイン「ACF(アドバンスカスタムフィールド)」を導入
- ACF側からカラムを設定
- 選択肢を動的に表示する
- フロントで表示する
ACF(アドバンスカスタムフィールド)
もともとWordPressには、本文やタイトル以外にデータが必要なとき「カスタムフィールド」という追加カラムをつけたす機能があります。update_post_meta()
メソッドや、get_post_custom(get_the_ID())
メソッド、add_meta_box()
メソッドなどを駆使すると複雑な構想も可能です。
ただ、今回は管理画面からクライアントが自由に設定できるようにしたく、かなりハードなのでGUIプラグイン(ACF)を導入しました。
このプラグインは非常に有名ですが、このあいだまでひと悶着ありました。Gigazineに経緯があります。記事執筆現在は元通りになっています。
ACFのリポジトリはこちら。
カスタム投稿タイプを増やす
たとえば、companies
というカスタム投稿タイプをつくります。これさえもプラグインからできますが、今回は開発要件に入っているため、functions.php
に入れておきます。
// カスタム投稿タイプ(会社 - companies)
register_post_type('companies', [
'labels' => [
'name' => '会社',
'singular_name' => '会社',
],
'public' => true,
'has_archive' => true,
'supports' => ['title', 'editor', 'thumbnail', 'id'],
'rewrite' => [
'slug' => 'companies', // URLのベース部分(/companies/)
'with_front' => false // パーマリンク設定の「Front base」を無視
],
]);
プラグイン「ACF(アドバンスカスタムフィールド)」を導入
手順は割愛。
ACF側からカラムを設定
プラグインを導入して、ACFからカラムを設定します。投稿タイプが「会社」に「等しい」になっていることが大事です。
選択肢を動的に表示する
たとえば会社データには「関連会社」をひもづけたいことがあります。そのとき、ACFで「関連会社」というカラムを付け足すわけですが、名前だと同名会社があったり社名変更があったりして困ります。当然ですが、こういうときはユニークな「ID」でひもづけするものです。
会社一覧から会社IDを選択したいのですが、なにもしないとすべて手作業で、会社データが増えるたびにID選択肢を手入力することになるので、functions.php
で毎回最新の会社一覧を事前入力できるようにします。
カスタム投稿タイプが増えてもいいように、処理を関数にしておきます。
/**
* 動的に選択肢を生成する共通関数
*
* @param array $field ACFフィールド配列
* @param string $post_type 対象の投稿タイプ
* @return array 変更後のACFフィールド配列
*/
function generate_dynamic_acf_choices($field, $post_type)
{
$field['choices'] = array();
$posts = get_posts(array(
'post_type' => $post_type,
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC'
));
foreach ($posts as $post) {
$field['choices'][$post->ID] = $post->post_title;
}
return $field;
}
// 会社IDの選択肢
add_filter('acf/load_field/name=company_id', function ($field) {
return generate_dynamic_acf_choices($field, 'companies');
});
フロントで表示する
$wpdb
オブジェクトを使用して、カスタム投稿タイプのテーブルからデータを取得します。global $wpdb;
でオブジェクトを使い回す必要があります。
カスタムフィールドのデータは、このテーブルではなくwp_options
テーブルに入っているため、$company_list
オブジェクトのなかには入っていません。
<?php
global $wpdb;
$company_list = $wpdb->get_results(
$wpdb->prepare(
"SELECT * FROM {$wpdb->posts}
WHERE post_type = %s
AND post_status = %s
ORDER BY post_date ASC",
'companies',
'publish'
)
);
// カスタムフィールドのデータ(会社IDを引数に渡して、関連会社IDを取得する)
$related_company_id = get_field('related_company_id', $company->ID);
?>
まとめ
ほんとうにきれいにつくりたかったら、リレーショナルなデータ構造にすべきですが、責任者やクライアントがWordPressを提案(指定)するということは、WordPressの利点(操作性の慣れ・管理画面・開発スピードなど)を最大化して、データベースやデータの理想像の優先順位を捨てよう、ということだと思っています。
WordPressの構築案件がありましたら、ぜひお声がけいただければさいわいです!
Discussion