Blog

ブログ

WordPressテーマ「Snow Monkey」に、カスタム投稿タイプで作成した、独自のコンテンツを追加する

ウェビングスタジオのサイトはWordPressテーマ「Snow Monkey」で制作していますが、投稿(ブログ)と固定ページとは別に「活動記録」という、カスタム投稿タイプで作成したコンテンツがあります。
このサイト以外で発信した投稿や技術情報を記録している、シンプルなリンク集です。

https://webbingstudio.com/activity/

WordPressの既存テーマを案件に採用するときに、一番悩むことになるのが以下の3点です。

  1. カスタム投稿タイプには対応しているのか
  2. どこまで自由にカスタマイズできるのか
  3. できる場合はどのような手順なのか

実際にテストサイトを作って検証できればよいのですが、既存テーマを使いたい案件はそのような時間もないことがほとんどです。

この「活動記録」を例として、よくあるパターンと、実装までの手順をご紹介します。functions.phpにある程度のPHPを書いたことがある、中級者であれば充分実装できる内容です。

こういうのはアドベントカレンダーに寄稿するものなんですが、年末は恐竜と冒険してました。すみませんすみません。

仕様

WordPressの大きなカスタマイズをするときは「何がしたいか=仕様」をはっきりさせてください。
活動記録は以下のとおりです。

  1. カスタム投稿タイプ「活動記録」を追加する
    • スラッグは「activity」
    • 一覧ページ=アーカイブが必要
    • 本文は必要ない
  2. 入力する項目
    • タイトル
    • 投稿した日(公開日)
    • カテゴリー(カスタムタクソノミー)
    • リンク先URL
  3. 詳細ページを作成しない
    • 投稿をクリックしたときのリンク先は、リンク先URLにする
  4. 一覧ページの1ページ目(活動記録のトップ)の上にリード文を表示する
    • リード文はウィジェットで管理する
  5. 表示件数はブログよりも多い30件

このうち、3.の「詳細ページを作成しない」が、Snow Monkeyでは本来想定していない機能で、ちょっとイレギュラーなカスタマイズになります。なので「カスタムフィールドの内容を一覧に表示する」解説を優先して、3.については記事の最後に補足として解説します。

プラグインを作成する

Snow Monkeyのカスタマイズは、テーマに設定されている「フック」を利用してPHPを書くことが多いです。それを書くためのごく簡単なプラグインを作成します。

今回の実装をするための、最低限のファイル構成は以下のとおりです。wp-content/plugins/ 以下にフォルダを作成する前提です。各PHPファイルは、とりあえず空としておいてください。

my-snow-monkey
├ my-snow-monkey.php
├ post_types.php
├ taxonomies.php
├ entry.php
└ widget.php


プラグインのコア「my-snow-monkey.php」については、ここでは割愛します。正式にテーマを購入してアカウントを取得していれば、プラグインのひな形をいつでもダウンロードできますが、WordPressのプラグインの作成はとても簡単なので調べてみてください。
my-snow-monkey.phpは、4つのファイルを呼び出しています。

カスタム投稿タイプを追加する

最初に、カスタム投稿タイプを追加します。プラグインを使用してもいいのですが、変更することはまずないので、私はPHPで書いています。
活動記録を定義している「post_types.php」については、以下のとおりです。作成したいコンテンツに応じて書き換えてください。

mysm_register_post_type_activity 関数は投稿タイプの定義、 mysm_remove_editor_activity 関数は編集画面から本文の入力欄=ブロックエディタを無効にしています。

<?php
/**
 * @package my-snow-monkey
 * @author YOUR-NAME
 * @license none
 * @version 1.0.0
 */

function mysm_register_post_type_activity() {

	$labels = [
		"name" => "活動記録",
		"singular_name" => "記録",
		"menu_name" => "活動記録",
		"all_items" => "すべての記録",
		"add_new" => "新規追加",
		"add_new_item" => "新規記録の追加",
		"edit_item" => "記録の編集",
		"new_item" => "新規記録",
		"view_item" => "記録を表示",
		"view_items" => "記録を表示",
		"search_items" => "記録を検索",
		"not_found" => "記録が見つかりません",
		"not_found_in_trash" => "ゴミ箱内に記録が見つかりません",
		"featured_image" => "アイキャッチ画像",
		"set_featured_image" => "アイキャッチ画像を設定",
		"remove_featured_image" => "アイキャッチ画像を削除",
		"use_featured_image" => "記録のアイキャッチ画像として使用",
		"archives" => "アーカイブ",
		"insert_into_item" => "記録に挿入",
		"uploaded_to_this_item" => "この記録へアップロード",
		"filter_items_list" => "活動記録を絞り込む",
		"items_list_navigation" => "活動記録ナビゲーション",
		"items_list" => "活動記録",
		"attributes" => "記録の属性",
		"name_admin_bar" => "活動記録",
	];

	$args = [
		"label" => "活動記録",
		"labels" => $labels,
		"description" => "",
		"public" => true,
		"publicly_queryable" => true,
		"show_ui" => true,
		"show_in_rest" => true,
		"rest_base" => "",
		"rest_controller_class" => "WP_REST_Posts_Controller",
		"has_archive" => true,
		"show_in_menu" => true,
		"show_in_nav_menus" => true,
		"delete_with_user" => false,
		"exclude_from_search" => false,
		"capability_type" => "post",
		"map_meta_cap" => true,
		"hierarchical" => false,
		"rewrite" => [ "slug" => "activity", "with_front" => true ],
		"query_var" => true,
		"menu_position" => 6,
		"menu_icon" => "dashicons-megaphone",
		"supports" => [ "title", "thumbnail", "custom-fields", "revisions", "author" ],
		"show_in_graphql" => false,
	];

	register_post_type( "activity", $args );
}

add_action( 'init', 'mysm_register_post_type_activity' );

function mysm_remove_editor_activity( $use_block_editor, $post ){
	if( $post->post_type === 'activity' ){
		remove_post_type_support( 'activity', 'editor' );
		return false;
	}
	return $use_block_editor;
}
// add_filter( 'use_block_editor_for_post', 'mysm_remove_editor_activity', 10, 2 );

カスタムタクソノミーを追加する

カスタムタクソノミーを追加します。こちらもプラグインを使用してもいいのですが、PHPで書いています。
カテゴリーを定義している「taxonomies.php」については、以下のとおりです。作成したいコンテンツに応じて書き換えてください。

mysm_register_taxonomy_activity 関数のみですが、重要な設定が一箇所あります。
Snow Monkeyは、設定値の配列の "hierarchical" (階層)が true であれば「カテゴリー」、 false であれば「タグ」として表示します。このため、hierarchicalをfalseにしていると、一覧ページにカテゴリー名を表示することが非常に難しくなります。こだわりがなければtrueにしてください。

<?php
/**
 * @package my-snow-monkey
 * @author YOUR-NAME
 * @license none
 * @version 1.0.0
 */

function mysm_register_taxonomy_activity() {

	$labels_actcategory = [
		"name" => "カテゴリー",
		"singular_name" => "カテゴリー",
	];

	$args_actcategory = [
		"label" => "カテゴリー",
		"labels" => $labels_actcategory,
		"public" => true,
		"publicly_queryable" => true,
		"hierarchical" => true,
		"show_ui" => true,
		"show_in_menu" => true,
		"show_in_nav_menus" => true,
		"query_var" => true,
		"rewrite" => [ 'slug' => 'actcategory', 'with_front' => true, ],
		"show_admin_column" => true,
		"show_in_rest" => true,
		"show_tagcloud" => true,
		"rest_base" => "actcategory",
		"rest_controller_class" => "WP_REST_Terms_Controller",
		"show_in_quick_edit" => false,
		"show_in_graphql" => false,
	];
	register_taxonomy( "actcategory", [ "activity" ], $args_actcategory );

}
add_action( 'init', 'mysm_register_taxonomy_activity' );

hierarchicalを変更できない場合

階層構造を変更できない場合は、Snow Monkeyのフックを利用して加工することになります。Qiitaで以前書いた、詳細ページのメタ情報を操作するTIPSを参考にしてください(一覧ページについては未検証です。すみません)。

https://qiita.com/webbingstudio@github/items/330cab44e10e7db8573f#%E3%82%BF%E3%82%AF%E3%82%BD%E3%83%8E%E3%83%9F%E3%83%BC%E3%81%AE%E8%A1%A8%E7%A4%BA%E4%BD%8D%E7%BD%AE%E3%82%92%E5%A4%89%E3%81%88%E3%82%8B

ウィジェットエリアを作成する

Snow Monkeyでセットされているものとは別の、独自のウィジェット領域=「一覧ページの1ページ目(活動記録のトップ)の上」を追加します。これもPHPで書いています。
ウィジェットを定義している「widget.php」については、以下のとおりです。作成したいコンテンツに応じて書き換えてください。

mysm_widgets_init 関数でウィジェット領域の追加、 mysm_add_activity_widget 関数で、本文の上にウィジェットを表示するよう定義しています。

snow_monkey_prepend_main はSnow Monkey専用のアクションフックで、本文の上に何らかのHTMLを挿入します。このフックだけでは、すべての画面に挿入されてしまうので「活動記録の一覧ページの1ページ目のとき」という条件分岐を挟んでいます。

!is_paged() で、1ページ目を判定できます。

<?php
/**
 * @package my-snow-monkey
 * @author YOUR-NAME
 * @license none
 * @version 1.0.0
 */

function mysm_widgets_init() {

	register_sidebar( array(
		'name' => '活動記録: 本文上',
		'id' => 'my-widget-activity-main-top',
		'before_widget' => '<div id="%1$s" class="c-widget widget_block">',
		'after_widget' => '</div>',
	) );

}
add_action( 'widgets_init', 'mysm_widgets_init', 10 );

function mysm_add_activity_widget() {
	if ( ( is_post_type_archive( 'activity' ) ) && ( !is_paged() ) && ( is_active_sidebar( 'my-widget-activity-main-top' ) ) ) {
		echo '<div class="l-archive-top-widget-area" data-is-slim-widget-area="false" data-is-content-widget-area="false">';
		dynamic_sidebar( 'ws-widget-activity-main-top' );
		echo '</div>';
	}
}
add_action( 'snow_monkey_prepend_main', 'mysm_add_activity_widget', 10 );

サンプルコードはGistでも公開しています。

カスタムフィールドを作成する

このコンテンツではカスタムフィールドは「リンク先URL」のひとつだけです。カスタムフィールドに関してはインターフェースのデザインや仕様変更の影響があり難しいので、プラグイン「Advanced Custom Fields」を使用しています。

コンテンツを入力する

表示確認用の活動記録を数件投稿します。カテゴリーも忘れずに。

このコンテンツは各記事を公開した日付を表示するので、公開日が「現在の日付」とは限りません。WordPressの基本の投稿画面だとテキストフィールドで日付を書き換えなければならず、面倒くさいので、カレンダーから公開日を入力できる「Schedule Posts Calendar」プラグインを利用しています。

「外観>ウィジェット」画面で、本文上のリード文を入力します。Snow Monkeyの場合、PHPで追加したウィジェットは「外観>カスタマイズ」画面では入力できないようです。
プラグイン「Snow Monkey Blocks」で、テーマ専用ブロック「メディアとテキスト」を使って書いています。

一覧ページのカスタマイズ

ここまで作業したら、ログインしている状態で、作成した投稿タイプの一覧ページへ移動します。画面の上の横並びの管理バーに「カスタマイズ」があるのでクリックして、投稿タイプ専用のカスタマイズ画面を表示します。

一覧ページを表示している状態でなければ、以下で説明する画面にはならないので注意してください。

「デザイン」をクリックします。

するとこれまではなかった「(投稿タイプ名)アーカイブページ設定」という項目が増えているのでクリックします。

一覧ページの表示の詳細設定画面となります。1カラム・2カラムの変更もここで設定できますが、2カラムだとサイドバーの内容など考慮することが急激に増えるので1カラムが無難です。

「記事一覧レイアウト」の選択肢が重要になります。こだわりがなければ、ブログやトップページの新着で使用していないレイアウトを選んでください。後述の投稿の繰り返し部分のカスタマイズが難しくなります。
ここでは一番シンプルな「テキスト2(text2)」を選択した前提で進めます。

ここまで設定したら「公開」ボタンを押してカスタマイズを終了します。

一覧の表示件数を変更する

ふたたびプラグインの方に戻ります。何も書いていなかった「entry.php」に投稿関係のカスタマイズ用のコードを書いていきます。

一覧を、活動記録だけ30件に増やすカスタマイズは、以下のとおりです。公式のフック pre_get_posts に「活動記録に関するページ(アーカイブ、カスタムタクソノミー)のときだけ件数を変える」処理を追加します。

function mysm_change_posts_per_page( $query ) {
	if( is_admin() || ! $query->is_main_query() ){
			return;
	}

	if( ( get_post_type() === 'activity' ) || ( is_post_type_archive( 'activity' ) ) || ( is_tax( 'actcategory' ) ) ) {
		$query->set( 'posts_per_page', 30 );
		return;
	}

}
add_action(
	'pre_get_posts',
	'mysm_change_posts_per_page'
);

管理画面の件数を変えてしまわないよう、管理画面であれば処理を中断するようにしています。詳しくは下記のブログを参考にしてください。

カスタムフィールドの内容を一覧に表示する

ウェビングスタジオの「活動記録」では、カスタムフィールドを一覧ページの投稿の繰り返しに表示していません。ですが実際の案件では、カスタムフィールドの値を表示したいケースが多いと思います。

どこに表示するかで、無数のパターンが考えられるので説明が難しいのですが、一番わかりやすいパターンを紹介します。

「メタ情報」の日付やカテゴリーを削除し、カスタムフィールド「test」の値に差し替える

function mysm_render_meta( $html, $name, $vars ) {
  if( ( get_post_type() === 'activity' ) || ( is_post_type_archive( 'activity' ) ) ) {

    $html = <<< EOL
<div class="c-entry-summary__meta">
  <ul class="c-meta">
    <li class="c-meta__item c-meta__item--sample">
EOL;

    $html .= get_field('test');

    $html .= <<< EOL
    </li>
  </ul>
</div>
EOL;
  }
  return $html;
}
add_filter(
  'snow_monkey_template_part_render_template-parts/loop/entry-summary/meta/meta',
  'mysm_render_meta',
  10,
  3
);

snow_monkey_template_part_render_template-parts/loop/entry-summary/meta/meta

という長い名前のフックが目に入ります。これは「snow_monkey_template_part_render_」よりも後ろがSnow Monkeyのテーマ内のファイルの相対パスになっていて「相対パスで指定したテンプレートの内容を、フックで実行したPHPの出力と入れ替える」という意味になります。

ここでは「template-parts/loop/entry-summary/meta/meta」なので、エントリーの繰り返しのメタ情報となります。

このテンプレートはすべての投稿タイプで共有しているので、このままではブログの記事一覧からカテゴリーが消えてしまいます。このため「活動記録のとき」という条件分岐を追加しています。

サンプルコードはGistでも公開しています。

日付やカテゴリーを残し、カスタムフィールドの値を追加する場合

メタ情報全体を囲んでいる要素、 div.c-entry-summary__meta後ろに新しい要素を追加する場合は、先ほどのコードの派生となります。変数 $html の本来の値に追加をします。

ここでは仮に p.c-entry-summary__test としました。CSSで見た目を調整してください。

function mysm_render_meta( $html, $name, $vars ) {
  if( ( get_post_type() === 'activity' ) || ( is_post_type_archive( 'activity' ) ) ) {

    $html .= '<p class="c-entry-summary__test">';
    $html .= get_field('test');
    $html .= '</p>';

  }
  return $html;
}
add_filter(
  'snow_monkey_template_part_render_template-parts/loop/entry-summary/meta/meta',
  'mysm_render_meta',
  10,
  3
);

最近はCSSで高度なレイアウトができるので、HTMLの親子や順番を気にしなくても良くなりました。なので先ほどの追加で十分対応できると思いますが、何らかの事情で ul.c-meta 内にli要素として挿入しなければならない場合は、ちょっと強引な手段になります。

PHPの正規表現置換を利用するので、バージョンアップの影響を受ける可能性があります。
Qiitaに書いたこちらのTIPSを参考にしてください。

https://qiita.com/webbingstudio@github/items/330cab44e10e7db8573f#%E4%B8%80%E8%A6%A7%E3%83%9A%E3%83%BC%E3%82%B8%E3%81%AE%E3%83%A1%E3%82%BF%E3%82%92%E6%93%8D%E4%BD%9C%E3%81%99%E3%82%8B

補足:詳細ページを表示しない

解説は以上です。
補足として、活動記録のちょっとイレギュラーなカスタマイズをご紹介します。

ウェビングスタジオの活動記録では、詳細ページへ移動させないようにしています。
Snow Monkeyの投稿一覧は、現時点の仕様では詳細ページへのリンクを削除することができないようです ※。このため、以下のいずれかの対策が必要になります。

  • JavaScriptでDOMを操作してリンクを除去する
  • 公式フック the_permalink でパーマリンクを「#」等に変更し、CSSかJavaScriptでクリックを無効にする

※カスタム投稿タイプの作成時に、 has_archives をfalseにした場合の挙動は確認していません

活動記録では、クリックしたときのリンク先をカスタムフィールドの内容にする必要があったので、後者のカスタマイズをしています。パーマリンクに「/activity/」が含まれていたら書き換えをします。

function mysm_change_permalink( $permalink, $post ) {
	if( preg_match( '/\/activity\//', $permalink ) ) {
		return get_field('url') ? get_field('url') : '#';
	} else {
		return $permalink;
	}
}
add_action(
	'the_permalink',
	'mysm_change_permalink',
	10,
	2
);

Snow Monkeyは、既存テーマを採用しない理由の大半を解決する

自分以外の人が公開しているテーマを、案件で採用しにくい理由として、以下のような事情があります。

  • どこまでカスタマイズできるのかわからない
    • カスタム投稿タイプは?
    • カスタムフィールドは?
    • HTMLの操作は?
  • バージョンアップしたときに崩れるのが怖い
  • いつまでサポートされるのかわからない
  • クライアントが自社以外とサブスク契約をすることに難色を示す

最後の「サブスク嫌!」はどうにもならないのですが(ウッキー!)、Snow Monkeyはそれ以外の問題を、高度なカスタマイズ画面、細やかなフィルターフック、豊富なドキュメントの提供などで解決しています。

休日の一日を使って試してみる価値はありますので、ぜひ過去の案件のカスタマイズを試してみてください。

関連記事