WordPressでACFを使用したお手軽?SEO機能を実装してみたの巻(上)

Date:

Share post:

最近は AEO(Answer Engine Optimization)という言葉をよく聞くようになりました。検索結果だけでなく、AI による回答への最適化も意識する流れです。ただ、その土台になるのはいまも SEO です。title / description / OGP といった基本情報をきちんと出せる状態は、サイト公開の前提としてやはり大事だと思います。

先日、久しぶりに WordPress の案件対応を行ったのですが、「meta タグや description を、どう機能追加して設定できるようにするか」をいつも考えてしまいます。

    • プラグイン?
    • 自前でカスタマイズ?

プラグインはご存知のとおり機能が盛りだくさんですが、案件によってはそこまで必要ないことも多いです。一方で、自前カスタマイズもやり出すときりがありません。だからこそ、ほどよい折衷案がないかといつも思っています。

そこで今回は、ACF(無料版)を使いました。完全自前でメタボックスや保存処理まで書くと実装が膨らむ一方、SEO専用プラグインほど多機能にもしたくない。ACF なら入力画面を短時間で用意でき、出力側だけテーマで制御できるので、自前実装を簡略化しつつ、プラグインほど機能を増やさない構成にできます。今回は、基本的なSEO設定(description / OGP)を管理画面から入れられるような機能実装をしたので、その手順をまとめておこうと思います。

1)WordPressインストール直後の状態とソース構成

今回はドキュメントルート直下に WordPress のソースを置いた状態でインストールを行いました。(DBのことは今回は特に触れませんが、環境作成時に用意してください。)

サイトのTOPページは固定ページを登録して、それを表示させるように設定を行いました。

独自テーマのファイルを用意して、そのテーマを有効化しました。この時点でのテーマファイル構成は以下のとおり(最低限の状態)です。

テーマディレクトリ/
    ├── 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' );

実装を行った後に管理画面を確認します。

左メニューに実装したカスタム投稿タイプが表示されています。

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 定義を行う

確認すると、タームが表示されています。

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

画面での登録結果表示です。

ちょっと長くなってきてしまったので、今回はここまでにしたいと思います。次回はいよいよSEO機能の実装を行いたいと思います。

Related articles