最近は AEO(Answer Engine Optimization)という言葉をよく聞くようになりました。検索結果だけでなく、AI による回答への最適化も意識する流れです。ただ、その土台になるのはいまも SEO です。title / description / OGP といった基本情報をきちんと出せる状態は、サイト公開の前提としてやはり大事だと思います。
先日、久しぶりに WordPress の案件対応を行ったのですが、「meta タグや description を、どう機能追加して設定できるようにするか」をいつも考えてしまいます。
-
- プラグイン?
- 自前でカスタマイズ?
プラグインはご存知のとおり機能が盛りだくさんですが、案件によってはそこまで必要ないことも多いです。一方で、自前カスタマイズもやり出すときりがありません。だからこそ、ほどよい折衷案がないかといつも思っています。
そこで今回は、ACF(無料版)を使いました。完全自前でメタボックスや保存処理まで書くと実装が膨らむ一方、SEO専用プラグインほど多機能にもしたくない。ACF なら入力画面を短時間で用意でき、出力側だけテーマで制御できるので、自前実装を簡略化しつつ、プラグインほど機能を増やさない構成にできます。今回は、基本的なSEO設定(description / OGP)を管理画面から入れられるような機能実装をしたので、その手順をまとめておこうと思います。
1)WordPressインストール直後の状態とソース構成
Wordpressインストール直後-1024x475.png)
今回はドキュメントルート直下に WordPress のソースを置いた状態でインストールを行いました。(DBのことは今回は特に触れませんが、環境作成時に用意してください。)
固定ページでTOPページ登録-1024x475.png)
表示設定変更-1024x474.png)
サイトのTOPページは固定ページを登録して、それを表示させるように設定を行いました。
独自テーマ-1024x476.png)
独自テーマのファイルを用意して、そのテーマを有効化しました。この時点でのテーマファイル構成は以下のとおり(最低限の状態)です。
テーマディレクトリ/
├── style.css
├── functions.php
├── header.php
├── footer.php
├── index.php
├── front-page.php
├── singular.php
└── archive.php
2)カスタム投稿タイプの追加
今回は、通常の投稿ではなく、カスタム投稿タイプを定義してSEO適用をしていきたいと思います。まずはカスタム投稿タイプの定義からです。以下のようなカスタム投稿タイプを作成します。
- お知らせ
- 店舗
- イベント
- コラム
ソース構成は以下のとおりです。
テーマディレクトリ/
├── style.css
├── functions.php
├── header.php
├── footer.php
├── index.php
├── front-page.php
├── singular.php
├── archive.php
└── inc/
└── cpt.php ← CPT 登録を行う
実装したソースは以下になります。
inc/cpt.php
<?php
/**
* カスタム投稿タイプ定義・登録.
*
* CPT定義を1か所にまとめ、ループで register_post_type する形にしています。
* 後続の SEO 実装でも、この定義一覧を参照してアーカイブ用フィールドを自動生成します。
*
* @package Alma_Demo
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* CPT 定義一覧.
*
* @return array<string, array<string, mixed>>
*/
function alma_demo_get_cpt_definitions() {
return array(
'news' => array(
'label' => 'お知らせ',
'menu_icon' => 'dashicons-megaphone',
'menu_pos' => 5,
'has_archive' => true,
'rewrite' => array(
'slug' => 'news',
'with_front' => false,
),
'supports' => array( 'title', 'editor', 'excerpt', 'thumbnail', 'revisions' ),
),
'store' => array(
'label' => '店舗',
'menu_icon' => 'dashicons-store',
'menu_pos' => 6,
'has_archive' => true,
'rewrite' => array(
'slug' => 'store',
'with_front' => false,
),
'supports' => array( 'title', 'editor', 'thumbnail', 'revisions' ),
),
'event' => array(
'label' => 'イベント',
'menu_icon' => 'dashicons-calendar-alt',
'menu_pos' => 7,
'has_archive' => true,
'rewrite' => array(
'slug' => 'event',
'with_front' => false,
),
'supports' => array( 'title', 'editor', 'excerpt', 'thumbnail', 'revisions' ),
),
'column' => array(
'label' => 'コラム',
'menu_icon' => 'dashicons-edit-large',
'menu_pos' => 8,
'has_archive' => true,
'rewrite' => array(
'slug' => 'column',
'with_front' => false,
),
'supports' => array( 'title', 'editor', 'excerpt', 'thumbnail', 'revisions' ),
),
);
}
/**
* 投稿タイプのラベルを生成する.
*
* @param string $singular 単数ラベル.
* @return array<string, string>
*/
function alma_demo_get_post_type_labels( $singular ) {
return array(
'name' => $singular,
'singular_name' => $singular,
'add_new' => '新規追加',
'add_new_item' => $singular . 'を追加',
'edit_item' => $singular . 'を編集',
'new_item' => '新しい' . $singular,
'view_item' => $singular . 'を表示',
'search_items' => $singular . 'を検索',
'not_found' => $singular . 'が見つかりませんでした',
'not_found_in_trash' => 'ゴミ箱に' . $singular . 'はありません',
'all_items' => $singular . '一覧',
'menu_name' => $singular,
);
}
/**
* カスタム投稿タイプを登録する.
*/
function alma_demo_register_post_types() {
foreach ( alma_demo_get_cpt_definitions() as $post_type => $config ) {
register_post_type(
$post_type,
array(
'labels' => alma_demo_get_post_type_labels( $config['label'] ),
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'menu_position' => $config['menu_pos'],
'menu_icon' => $config['menu_icon'],
'show_in_rest' => true,
'has_archive' => $config['has_archive'],
'rewrite' => $config['rewrite'],
'capability_type' => 'post',
'map_meta_cap' => true,
'hierarchical' => false,
'supports' => $config['supports'],
)
);
}
}
add_action( 'init', 'alma_demo_register_post_types' );
実装を行った後に管理画面を確認します。
カスタム投稿タイプ登録-1024x474.png)
左メニューに実装したカスタム投稿タイプが表示されています。
3)タクソノミーの定義とタームの登録
カスタム投稿タイプ用の独自タクソノミーの定義とタームの登録を行います。今回は以下のように実装しました。
inc/taxonomy.php
<?php
/**
* 独自タクソノミー定義・登録.
*
* 標準の category は使わず、CPT ごとに独自タクソノミーを用意します.
*
* @package Alma_Demo
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* タクソノミー定義一覧.
*
* @return array<string, array<string, mixed>>
*/
function alma_demo_get_taxonomy_definitions() {
return array(
'news_category' => array(
'label' => 'お知らせカテゴリ',
'post_types' => array( 'news' ),
'rewrite' => array(
'slug' => 'news/category',
'with_front' => false,
),
),
'store_category' => array(
'label' => '店舗エリア',
'post_types' => array( 'store' ),
'rewrite' => array(
'slug' => 'store/category',
'with_front' => false,
),
),
'event_category' => array(
'label' => 'イベントカテゴリ',
'post_types' => array( 'event' ),
'rewrite' => array(
'slug' => 'event/category',
'with_front' => false,
),
),
'column_category' => array(
'label' => 'コラムカテゴリ',
'post_types' => array( 'column' ),
'rewrite' => array(
'slug' => 'column/category',
'with_front' => false,
),
),
);
}
/**
* タクソノミーのラベルを生成する.
*
* @param string $singular 単数ラベル.
* @return array<string, string>
*/
function alma_demo_get_taxonomy_labels( $singular ) {
return array(
'name' => $singular,
'singular_name' => $singular,
'search_items' => $singular . 'を検索',
'all_items' => $singular . '一覧',
'edit_item' => $singular . 'を編集',
'update_item' => $singular . 'を更新',
'add_new_item' => $singular . 'を追加',
'new_item_name' => '新しい' . $singular,
'menu_name' => $singular,
);
}
/**
* 独自タクソノミーを登録する.
*/
function alma_demo_register_taxonomies() {
foreach ( alma_demo_get_taxonomy_definitions() as $taxonomy => $config ) {
register_taxonomy(
$taxonomy,
$config['post_types'],
array(
'labels' => alma_demo_get_taxonomy_labels( $config['label'] ),
'public' => true,
'show_ui' => true,
'show_admin_column' => true,
'show_in_rest' => true,
'hierarchical' => true,
'rewrite' => $config['rewrite'],
)
);
}
}
add_action( 'init', 'alma_demo_register_taxonomies' );
/**
* デモ用のデフォルトタームを登録する.
*/
function alma_demo_register_default_terms() {
$default_terms = array(
'news_category' => array(
'新着' => 'new',
'キャンペーン' => 'campaign',
'重要' => 'important',
),
'store_category' => array(
'関東' => 'kanto',
'中部' => 'chubu',
'関西' => 'kansai',
),
'event_category' => array(
'キャンペーン' => 'campaign',
'ワークショップ' => 'workshop',
'季節の話題' => 'season',
),
'column_category' => array(
'お役立ち' => 'tips',
'季節の話題' => 'season',
'FAQ' => 'faq',
),
);
foreach ( $default_terms as $taxonomy => $terms ) {
foreach ( $terms as $name => $slug ) {
if ( ! term_exists( $slug, $taxonomy ) ) {
wp_insert_term(
$name,
$taxonomy,
array(
'slug' => $slug,
)
);
}
}
}
}
add_action( 'init', 'alma_demo_register_default_terms', 30 );
テーマファイルのソース構成は以下のようになりました。
テーマディレクトリ/
├── style.css
├── functions.php
├── header.php
├── footer.php
├── index.php
├── front-page.php
├── singular.php
├── archive.php
└── inc/
├── cpt.php ← CPT 登録を行う
└── taxonomy.php ← taxonomy 定義を行う
確認すると、タームが表示されています。
登録したカテゴリ一覧-1024x475.png)
4)WP-CLIを使用したダミー投稿の登録
カスタム投稿タイプとタクソノミー・タームの登録までができた状態なので、表示確認用に投稿を登録したいと思います。管理画面で1件ずつ登録してもいいですが、ダミーということと、複数件登録するために今回は WP-CLI を使用してコマンド実行で投稿の登録をしていきます。
WP-CLI はコマンドラインからWordPressサイトにかかるいろいろな操作(プラグインインストール、投稿の登録など)が行えるツールです。WP-CLIを使用するために、今回のテスト環境では以下のように導入しました。
$(サーバ環境に入って、実行アカウントに変更)
$ curl -sS -o wp-cli.phar https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
$ su root
# chmod +x wp-cli.phar
# mv wp-cli.phar /usr/local/bin/wp
# exit
$ wp --version
WP-CLI 2.12.0
コマンド実行の最後の方ですが、バージョン表示まで行われていますので正常に導入ができています。
では実際にダミー投稿を登録していきます。
# お知らせ
$ ID=$(wp post create --post_type=news --post_status=publish \
--post_title='サイトをリニューアルしました' \
--post_content='<p>ホームページをリニューアルしました。店舗情報やイベント情報を見やすくしています。</p>' \
--porcelain)
$ wp post term set "$ID" news_category new
$ ID=$(wp post create --post_type=news --post_status=publish \
--post_title='春のキャンペーンのお知らせ' \
--post_content='<p>春のキャンペーンを開催します。期間中は特典をご用意しています。</p>' \
--porcelain)
$ wp post term set "$ID" news_category campaign new
$ ID=$(wp post create --post_type=news --post_status=publish \
--post_title='営業時間変更のご案内' \
--post_content='<p>一部店舗の営業時間を変更します。詳細は店舗ページをご確認ください。</p>' \
--porcelain)
$ wp post term set "$ID" news_category new
# 店舗
$ ID=$(wp post create --post_type=store --post_status=publish \
--post_title='東京本店' \
--post_content='<p>東京本店の紹介です。アクセス良好な立地で、スタッフ一同お待ちしています。</p>' \
--porcelain)
$ wp post term set "$ID" store_category kanto
$ ID=$(wp post create --post_type=store --post_status=publish \
--post_title='横浜店' \
--post_content='<p>横浜店の紹介です。週末もご利用いただきやすい店舗です。</p>' \
--porcelain)
$ wp post term set "$ID" store_category kanto
$ ID=$(wp post create --post_type=store --post_status=publish \
--post_title='名古屋店' \
--post_content='<p>名古屋店の紹介です。駐車場完備でご来店しやすい環境です。</p>' \
--porcelain)
$ wp post term set "$ID" store_category chubu
# イベント
$ ID=$(wp post create --post_type=event --post_status=publish \
--post_title='週末オープニングイベント' \
--post_content='<p>週末にオープニングイベントを開催します。来場特典もあります。</p>' \
--porcelain)
$ wp post term set "$ID" event_category campaign
$ ID=$(wp post create --post_type=event --post_status=publish \
--post_title='夏休みワークショップ' \
--post_content='<p>夏休み向けのワークショップを開催します。事前予約制です。</p>' \
--porcelain)
$ wp post term set "$ID" event_category workshop season
$ ID=$(wp post create --post_type=event --post_status=publish \
--post_title='秋の感謝デー' \
--post_content='<p>日頃の感謝を込めて秋の感謝デーを実施します。</p>' \
--porcelain)
$ wp post term set "$ID" event_category campaign
# コラム
$ ID=$(wp post create --post_type=column --post_status=publish \
--post_title='初めての方向けガイド' \
--post_content='<p>初めてご利用になる方向けに、基本的な流れをまとめました。</p>' \
--porcelain)
$ wp post term set "$ID" column_category tips
$ ID=$(wp post create --post_type=column --post_status=publish \
--post_title='季節のメンテナンスのコツ' \
--post_content='<p>季節の変わり目に気をつけたいメンテナンスのポイントです。</p>' \
--porcelain)
$ wp post term set "$ID" column_category tips season
$ ID=$(wp post create --post_type=column --post_status=publish \
--post_title='よくある質問まとめ' \
--post_content='<p>お問い合わせの多い質問をまとめました。</p>' \
--porcelain)
$ wp post term set "$ID" column_category faq
画面での登録結果表示です。
登録した記事一覧-1024x476.png)
ちょっと長くなってきてしまったので、今回はここまでにしたいと思います。次回はいよいよSEO機能の実装を行いたいと思います。