WEBLOG
WordPress > サイト毎の設定
Create:
Update:
カスタム投稿タイプの設定。プラグインは使用しません。
functions.php には設定値のみ記載して functions_setup.php に記述しinclude。
設定定数「CUSTOM_POSTTYPE」については下部に補足とサンプルがあります。
設定定数「TINYMCE_INITS」はクラッシックエディター使用時の共通設定です。
// カスタム投稿タイプ
const CUSTOM_POSTTYPE = [
'xxx' => [
'name' => 'サンプルカスタム投稿タイプ名称',
'posts_per_page' => 10,
'editor' => [
'type' => 'classic',
'tinymce' => ['link', 'unlink'],
],
'eyecatch' => false,
'route' => [
'archive_path' => 'auto',
'single_auto_slug' => true,
'page_in_posttype' => [],
],
'sitemap' => [
'archive' => '0.5', // アーカイブがない場合は「false」
'single' => '0.6', // シングルがない場合は「false」
'add_arg' => [],
],
'columns' => [
'author' => false,
'column' => [
],
],
],
];
const TINYMCE_INITS = [
'block_formats' => '段落=p;大見出し=h4;小見出し=h5;',
'fontsize_formats' => '1.3rem 1.5rem 1.6rem 1.8rem 2.0rem 2.2rem 2.4rem 2.8rem 3.2rem',
'body_class' => 'entry_wrap',
];
include_once 'xxx/functions_setup.php';
先ず xxx にカスタム投稿タイプ slug を記載します。
カスタム投稿タイプ名
wp_query で取得される標準のアーカイブ投稿数
classic(クラッシックエディター)、gutenberg(ブロックエディター)から選択。
デフォルトは「classic」。※ advanced_custom_fields との相性が良いため
アイキャッチ投稿欄の有無
アーカイブパスやシングルスラッグのルーティング設定。
投稿タイプ内に固定ページを設置する際もここで設定。
sitemap.xmlの自動生成を行います。数値(少数)は0.1~1までのpriorityです。
管理画面一覧で表示するものの設定、カスタムフィールドの画像や値、カスタムタクソノミーのラベルなどを表示します。
上記の設定定数を元にカスタム投稿タイプを追加します。
このファイルはバージョン管理され、各サイト共通で設置しています。
※ カスタム投稿タイプの設定はDBに保存されず、ここで返される各値がマスターになります。
設定値を元にカスタム投稿タイプが追加されます。
固定ページの下層に投稿タイプを配置するなどルーティングを変更することも可能です。
ブロックエディター、クラッシックエディターの切り替えも追加時に行います。
add_action('init', function () {
global $post_type;
$check_taxonomy = [];
$check_eycatch = [];
foreach (CUSTOM_TAXONOMY_FIXED as $k => $v) {
$check_taxonomy[$v['post_type']][] = $k;
}
foreach (CUSTOM_POSTTYPE_FIXED as $k => $v) {
$args = [
'labels' => [
'name' => $v['name'],
'singular_name' => $v['name'],
'all_items' => '投稿一覧',
'menu_name' => $v['name']
],
'public' => true,
'exclude_from_search' => false,
'has_archive' => true,
'rewrite' => (isset($v['route']['archive_path']) && is_array($v['route']['archive_path'])) ? $v['route']['archive_path'] : true,
'show_in_rest' => $v['editor']['type'] === 'gutenberg',
];
if (isset($check_taxonomy[$k])) {
$args['taxonomies'] = $check_taxonomy[$k];
}
if (isset($v['eyecatch']) && $v['eyecatch']) {
$args['supports'] = ['title', 'editor', 'thumbnail', 'excerpt', 'author', 'page-attributes'];
$check_eycatch[] = $k;
}
if ($k !== 'post') {
register_post_type($k, $args);
}
}
if (in_array($post_type, $check_eycatch)) {
add_theme_support('post-thumbnails');
}
});
ルーティングはプラグインを使用せず管理しています。
foreach (CUSTOM_POSTTYPE_FIXED as $posttype => $v) {
add_rewrite_rule('^' . $posttype . '/?$', 'index.php?post_type=' . $posttype . '', 'top');
add_rewrite_rule('^' . $posttype . '/page/([0-9]{1,})/?$', 'index.php?post_type=' . $posttype . '&paged=$matches[1]', 'top');
add_rewrite_rule('^' . $posttype . '/([0-9]{4})/([0-9]{1,2})/page/?([0-9]{1,})/?$', 'index.php?year=$matches[1]&monthnum=$matches[2]&paged=$matches[3]&post_type=' . $posttype . '', 'top');
add_rewrite_rule('^' . $posttype . '/([0-9]{4})/([0-9]{1,2})/?$', 'index.php?year=$matches[1]&monthnum=$matches[2]&post_type=' . $posttype . '', 'top');
add_rewrite_rule('^' . $posttype . '/([0-9]{4})/page/?([0-9]{1,})/?$', 'index.php?year=$matches[1]&paged=$matches[2]&post_type=' . $posttype . '', 'top');
add_rewrite_rule('^' . $posttype . '/([0-9]{4})/?$', 'index.php?year=$matches[1]&post_type=' . $posttype . '', 'top');
add_rewrite_rule('^' . $posttype . '/author/([^/]+)/page/?([0-9]{1,})/?$', 'index.php?author_name=$matches[1]&paged=$matches[2]&post_type=' . $posttype . '', 'top');
add_rewrite_rule('^' . $posttype . '/author/([^/]+)/?$', 'index.php?author_name=$matches[1]&post_type=' . $posttype . '', 'top');
}
一部、カスタムタクソノミーの設定値によるタクソノミーアーカイブの設定も同時に行っています。
add_action('pre_get_posts', function ($query) {
if (is_admin() || !$query->is_main_query()) {
return;
}
$is_category_archive = true;
foreach (CUSTOM_POSTTYPE_FIXED as $k => $v) {
if (is_post_type_archive($k)) {
$query->set('posts_per_page', $v['posts_per_page']);
$is_category_archive = false;
break;
}
}
if ($is_category_archive) {
foreach (CUSTOM_TAXONOMY_FIXED as $k => $v) {
if (is_tax($k)) {
$query->set('posts_per_page', $v['posts_per_page']);
break;
}
}
}
});
実際には、固定ページの設定と重複するためここには記載せず、固定ページの処理と一緒に記載しています。
add_filter('use_block_editor_for_post', function ($use_block_editor, $this_post) {
global $post_type;
if (in_array($post_type, array_keys(CUSTOM_POSTTYPE_FIXED))) {
if (isset(CUSTOM_POSTTYPE_FIXED[$post_type]['editor']['type']) && CUSTOM_POSTTYPE_FIXED[$post_type]['editor']['type'] === 'gutenberg') {
return $use_block_editor;
}
} else {
return false;
}
}, 10, 2);
//tinymce ボタン1行目
add_filter('mce_buttons', function ($buttons) {
global $post, $post_type;
if ($post_type === 'page') {
if (in_array($post->ID, array_keys(PAGES_SETTING_FIXED)) && isset(PAGES_SETTING_FIXED[$post->ID]['editor']['tinymce'])) {
$buttons = PAGES_SETTING_FIXED[$post->ID]['editor']['tinymce'];
}
} else {
if (in_array($post_type, array_keys(CUSTOM_POSTTYPE_FIXED)) && isset(CUSTOM_POSTTYPE_FIXED[$post_type]['editor']['tinymce'])) {
$buttons = CUSTOM_POSTTYPE_FIXED[$post_type]['editor']['tinymce'];
}
}
return $buttons;
}, 1);
//tinymce ボタン2行目(共通)
add_filter('mce_buttons_2', function ($buttons) {
return [];
}, 1);
//段落・見出し要素、フォントサイズの設定(共通)
add_filter('tiny_mce_before_init', function ($inits) {
if (defined('TINYMCE_INITS')) {
$inits['block_formats'] = TINYMCE_INITS['block_formats'] ?? $inits['block_formats'];
$inits['fontsize_formats'] = TINYMCE_INITS['fontsize_formats'] ?? $inits['fontsize_formats'];
$inits['body_class'] = TINYMCE_INITS['body_class'] ?? $inits['body_class'];
}
return $inits;
});
//tinymce 表(テーブル)
add_filter('mce_external_plugins', function ($plugins) {
$plugins['table'] = home_url() . '/wp/wp-content/themes/base/xxx/asset/tinymce_table_plugin.min.js';
return $plugins;
});
tinymce の tableに関するJavaScriptはCDNで読み込んでいましたが、ある日突然切れてしまいました。今は、ダウンロードして読み込んでいます。途中の「xxx(ディレクトリ名)」は、ご自由に。
このスラッグは、wp-posts テーブルの「postname」としてDB保存され、URLの一部としても使用されます。理由はいくつかありますが、弊社では日本語ではなく、英語に変換するようにしています。
add_filter('wp_unique_post_slug', function ($slug, $post_id, $post_status, $post_type) {
foreach (CUSTOM_POSTTYPE_FIXED as $k => $v) {
if ($k === $post_type && $v['route']['single_auto_slug']) {
if ($post_id && preg_match('/(%[0-9a-f]{2})+/', $slug)) {
$slug = 'post' . $post_id;
}
}
}
return $slug;
}, 10, 4);
add_action('init', function () {
foreach (CUSTOM_POSTTYPE_FIXED as $k => $v) {
if (isset($v['add_page']) && is_array($v['add_page']) && count($v['add_page'])) {
foreach ($v['add_page'] as $vv) {
if (isset($vv['name']) && isset($vv['pade_id'])) {
add_rewrite_rule('^' . $k . '/' . $vv['name'] . '/?$', 'index.php?page_id=' . $vv['pade_id'], 'top');
}
}
}
}
});
管理画面内の投稿一覧にカスタムフィールド(wp_pos_meta)の情報やカスタムタクソノミーの値などを表示します。
各投稿画面を開かず確認したい情報や並べ替えの基準になる情報を表示することで、管理画面がとても使いやすくなります。
弊社では下記のデータをすぐに表示できるよう準備しています。
add_filter('manage_posts_columns', function ($columns) {
$this_post_type = get_query_var('post_type');
/* common : remove default feild */
unset($columns['tags'] , $columns['comments']); // タグ&カスタムフィールド
/* post_type */
$add_columns = [];
foreach (CUSTOM_POSTTYPE_FIXED as $k => $v) {
if ($this_post_type === $k) {
$count = 0;
foreach ($v['columns']['column'] as $vv) {
$add_columns['column' . $count] = $vv['name'];
$count++;
}
if (!$v['columns']['author']) {
unset($columns['author']);
}
break;
}
}
wp_oo_array_insert($columns, 2, $add_columns);
return $columns;
});
add_action('manage_posts_custom_column', function ($column, $post_id) {
$post_type = get_query_var('post_type');
$arr = [];
foreach (CUSTOM_POSTTYPE_FIXED as $k => $v) {
if ($k === $post_type) {
$arr = $v['columns']['column'] ?? [];
$count = 0;
foreach ($arr as $vv) {
if ($column === 'column' . $count) {
res_column($vv['type'], $vv['arg'], $post_id);
break;
}
$count++;
}
break;
}
}
}, 10, 2);
// 一覧での表示項目
function res_column($type, $arg, $post_id)
{
switch ($type) {
case 'debug':
$val = get_field($arg, $post_id);
var_dump($val);
break;
case 'normal':
$val = get_field($arg, $post_id);
echo $val ? $val : '--';
break;
case 'image':
$img_arr = get_field($arg, $post_id);
echo isset($img_arr['sizes']['thumbnail']) ? '<img src="' . $img_arr['sizes']['thumbnail'] . '" width="90">' : '--';
break;
case 'date':
$date = get_field($arg, $post_id);
echo $date ? date_i18n('Y-m-d', $date) : '--';
break;
case 'time':
$date = get_field($arg, $post_id);
echo $date ? date_i18n('H:i', $date) : '--';
break;
case 'radio_select':
$both = get_field($arg, $post_id); // 返り値:arr
echo isset($both['label']) ? $both['label'] : '--';
break;
case 'file':
$file = get_field($arg, $post_id);
if ($file) {
echo '<a href="' . $file . '" target="_blank">PDFファイル</a>';
} else {
echo '--';
}
break;
case 'checkbox':
$boths = get_field($arg, $post_id); // 返り値:arr
$boths = is_array($boths) ? $boths : [];
$arr = [];
foreach ($boths as $both) {
$arr[] = $both['label'];
}
echo $arr ? join(' , ', $arr) : '--';
break;
case 'taxonomy':
$terms = is_array(get_the_terms($post_id, $arg)) ? get_the_terms($post_id, $arg) : [];
$arr = [];
foreach ($terms as $term) {
// カテゴリー3階層まで取得
$temp = '';
if ($term->parent != 0) {
$temp_parent = get_term($term->parent, $arg);
if ($temp_parent->parent != 0) {
$temp .= get_term($temp_parent->parent, $arg)->name . ' > ';
}
$temp .= $temp_parent->name . ' > ';
}
$temp .= $term->name;
$arr[] = $temp ;
}
echo $arr ? join(' / ', $arr) : '--';
break;
case 'relation':
$relations = is_array(get_field($arg, $post_id)) ? get_field($arg, $post_id) : [];
$arr = [];
foreach ($relations as $post_id) {
$arr[] = get_the_title($post_id);
}
echo $arr ? join('/', $arr) : '--';
break;
case 'post_object':
$temp_post_id = get_field($arg, $post_id) ? get_field($arg, $post_id) : false;
if ($temp_post_id) {
echo get_the_title($temp_post_id);
} else {
echo '--';
}
break;
case 'newmark':
$date_compare = date_i18n('Ymd', strtotime(date_i18n('Y-m-d') . '-1 month'));
$temp_date = get_the_date('Ymd', $post_id);
if ($temp_date > $date_compare) {
echo '○:初回投稿日より1カ月以内';
} else {
echo '✕:初回投稿日より1カ月経過';
}
break;
case 'replace':
$acf_val = get_field($arg['acf_key'], $post_id);
echo isset($arg['acf_key'][$acf_val]) ? $arg['acf_key'][$acf_val] : $acf_val;
break;
case 'supple':
echo $arg;
break;
case 'linktype':
$arr = get_field($arg, $post_id) ;
if ($arr['type']['value'] === 'type_nolink') {
echo 'リンクなし';
} elseif ($arr['type']['value'] === 'type_url') {
echo 'リンク-URL';
} elseif ($arr['type']['value'] === 'type_detail') {
echo 'リンク-詳細ページ';
} elseif ($arr['type']['value'] === 'type_pdf') {
echo 'リンク-PDFファイル';
} else {
echo 'リンク設定なし';
}
break;
case 'func':
$func = $arg['func_name'];
echo $func($post_id, $arg);
break;
default:
echo '-';
}
}
上記の設定定数をサンプルとコード内コメントで補足しています。
const CUSTOM_POSTTYPE = [
'xxx' => [
'name' => 'カスタム投稿タイプ名称',
'posts_per_page' => 10,
// エディタ
'editor' => [
'type' => 'classic', // classic || gutenberg
'tinymce' => [
'link',
'unlink',
'|',
'formatselect',
'bullist',
'numlist',
'|', // 区切り線
'formatselect', // 見出し、段落の設定
'bullist', // ul li
'numlist', // ol li
'|', // 区切り線
'link', // リンク
'unlink', // リンク解除
'|', // 区切り線
'forecolor', // テキストカラー
'table', // 表
'fontsizeselect', // フォントサイズ
'bold', // フォントサイズ
'italic', // フォントサイズ
'styleselect ', // テキストスタイル、見出し、ブロックなど
'alignleft',
'aligncenter',
'alignright',
'alignjustify',
'outdent', // padding -40px
'indent', // padding +40px
],
],
'eyecatch' => false,
// routing
'route' => [
'archive_path' => 'auto', // 特定のディレクトリ(zzz)内にアーカイブする場合は右記の配列を記述 [ 'slug' => 'zzz/addposttypename' ]
'single_auto_slug' => true, // slugの自動生成 * 'post' . $this_post_id
'page_in_posttype' => [
[
'name' => 'pageneme', // リンクURL: /xxx/pageneme/
'pade_id' => '3' // 固定ページのID
]
],
],
// sitemap_xml
'sitemap' => [
'archive' => '0.5', // アーカイブがない場合は「false」
'single' => '0.6', // シングルがない場合は「false」
'add_arg' => []
],
// 一覧での表示項目
'columns' => [
'author' => false,
'column' => [
[
'name' => '一覧表示項目',
'type' => 'normal',
'arg' => 'acf_xx' // acf
],
[
'name' => '画像',
'type' => 'image',
'arg' => 'acf_xx' // acf
],
[
'name' => '日付',
'type' => 'date',
'arg' => 'acf_xx' // acf
],
[
'name' => 'ラジオボタン or SELECT',
'type' => 'radio_select',
'arg' => 'acf_xx' // acf
],
[
'name' => 'チェックボックス',
'type' => 'checkbox',
'arg' => 'acf_xx' // acf
],
[
'name' => 'ファイル',
'type' => 'file',
'arg' => 'acf_xx' // acf
],
[
'name' => 'カスタムタクソノミー',
'type' => 'taxonomy',
'arg' => 'cat_xxx' // taxonomy
],
[
'name' => '関連',
'type' => 'relation',
'arg' => 'acf_xx' // acf
],
[
'name' => 'NEWマーク',
'type' => 'newmark',
'arg' => '-1 month' // option
],
[
'name' => '文字列変換',
'type' => 'replace',
'arg' => [
'acf_key' => 'acf_xx', // acf : 返り値の文字列を変更
'replace' => [
'show' => '表示',
'hide' => '非表示'
]
]
],
[
'name' => '注釈',
'type' => 'supple',
'arg' => '*注釈文面' // acf
],
[
'name' => '独自関数設定',
'type' => 'func',
'arg' => [
'acf_key' => 'acf_xx',
'func_name' => 'create_column_loop_xxx'
],
],
],
]
],
];
ルーティングとは、リクエストされたパスから「テンプレート選択」「DBの値を取得」などを行い、特定のページを表示することです。こちらを標準表示を変更します。
変更した後に「WordPress管理画面 > 設定 > パーマリンク設定」からフラッシュ(設定保存)することで、DBが更新されます。
コメントで「// acf」と記載のある箇所には、advanced_custom_fields で設定したカスタムフィールドのkeyを記載します。
独自関数設定する場合は、arg は配列で 関数名をfuncname に設定します。
function create_column_loop_xxx($this_post_id, $arg)
{
$acf_loop = get_field($arg['acf_key'], $this_post_id) ?? [];
$res_arr = [];
foreach ($acf_loop as $v) {
$res_arr[] = '<a href="' . $v['aaa'] . '" target="_blank">' . $v['bbb'] . '</a>';
}
return join(' / ', $res_arr);
}