カスタマイズ 2023.09.09 2024.06.27
カスタム投稿タイプをadd_menu_pageで追加したメニューのサブメニューとして表示させる
目次
はじめに
この記事を書くきっかけとなったのは、WordPress で複数のカスタム投稿タイプを作成した際、1 つのメニューのサブメニューとしてまとめるため、カスタム投稿タイプをサブメニューに表示する手段を調べたことです。
その際、投稿や固定ページといったデフォルトのメニューのサブメニューとして表示させる場合と、add_menu_page で作成したメニューのサブメニューとして表示させる場合で、値の書き方が少し異なることを知りました。
今回の記事では、その書き方と、値が異なる理由についてを書こうと思います。
カスタム投稿とメインメニューの作成
カスタム投稿タイプを register_post_type で作成する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function create_custom_post() { $labels = array( 'name' => 'Article', 'menu_name' => 'Article', ); $args = array( 'labels' => $labels, 'public' => true, 'show_ui' => true, 'show_in_nav_menus' => true, 'show_in_menu' => true, 'show_in_admin_bar' => true, 'menu_icon' => 'dashicons-media-code', ); register_post_type('article', $args); } add_action('init', create_custom_post(...)); |
メインメニューを add_menu_page で作成する。 3 4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function add_custom_menu() { add_menu_page( '投稿タイプ一覧画面', 'すべてのカスタム投稿', 'manage_options', 'all_post', 'create_custom_menu_content', 'dashicons-menu-alt3', 3 ); }; function create_custom_menu_content() { include(__DIR__.'/inc/CustomMenuContent.php'); }; add_action('admin_menu',add_custom_menu(...), 9); |
そうすると、メニューバーはこのように表示されます。
これで前提となるカスタム投稿タイプとメインメニューが作成出来ました。
続いて、カスタム投稿タイプをサブメニューとして表示します。
カスタム投稿をサブメニューとして表示する
デフォルトのメニューのサブメニューとして表示する場合
まずは、デフォルトの投稿ページのサブメニューとして表示してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function create_custom_post() { $labels = array( 'name' => 'Article', 'menu_name' => 'Article', ); $args = array( 'labels' => $labels, 'public' => true, 'show_ui' => true, 'show_in_nav_menus' => true, 'show_in_menu' => 'edit.php', 'show_in_admin_bar' => true, 'menu_icon' => 'dashicons-media-code', ); register_post_type( 'article' , $args ); } add_action('init', 'create_custom_post'); |
show_in_menu の値を edit.php に書き換えます。edit.php は投稿ページのファイル名です。
すると、投稿メニューのサブメニューとしてカスタム投稿タイプが表示されます。
add_menu_page で作成したメニューのサブメニューとして表示する場合
次に、先ほど作成したメニューのサブメニューとして表示してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function create_custom_post() { $labels = array( 'name' => 'Article', 'menu_name' => 'Article', ); $args = array( 'labels' => $labels, 'public' => true, 'show_ui' => true, 'show_in_nav_menus' => true, 'show_in_menu' => 'all_post', 'show_in_admin_bar' => true, 'menu_icon' => 'dashicons-media-code', ); register_post_type( 'article' , $args ); } add_action('init', 'create_custom_post'); |
show_in_menu の値を変更するのですが、デフォルトと同じように書くのであれば、投稿ページであれば’edit.php’、固定ページであれば’edit.php?post_type=page’というように、カスタムメニューのファイル名とスラグ名を合わせた’admin.php?page=all_post’と書くはずです。
しかし、この場合は’all_post’と、add_menu_page のときに指定したスラグ名のみを書きます。
そうすると、カスタムメニューのサブメニューとして表示できます。
なぜ値の書き方が異なるのか?
これで、デフォルトのメニューとカスタムのメニューの両方でカスタム投稿タイプをサブメニューとして表示させる方法はわかりました。
しかし、なぜこのような違いがあるのでしょうか?謎を解くため、WordPress のコードを読んでみます。すると、_add_post_type_submenus という関数がありました。
_add_post_type_submenus
1 2 3 4 5 6 7 8 9 10 |
function _add_post_type_submenus() { foreach ( get_post_types( array( 'show_ui' => true ) ) as $ptype ) { $ptype_obj = get_post_type_object( $ptype ); // Sub-menus only. if ( ! $ptype_obj->show_in_menu || true === $ptype_obj->show_in_menu ) { continue; } add_submenu_page( $ptype_obj->show_in_menu, $ptype_obj->labels->name, $ptype_obj->labels->all_items, $ptype_obj->cap->edit_posts, "edit.php?post_type=$ptype" ); } } |
この関数では、投稿タイプを全てとってきて、投稿タイプの show_in_menu の値が bool 型でなければ、add_submenu_page を呼び出すようになっています。
この時、show_in_menu の値は第 1 引数として入ります。
次に、add_submenu_page を見てみます。
この関数では、投稿タイプを全てとってきて、投稿タイプの show_in_menu の値が bool 型でなければ、add_submenu_page を呼び出すようになっています。
この時、show_in_menu の値は第 1 引数として入ります。
次に、add_submenu_page を見てみます。
add_submenu_page 5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $callback = '', $position = null ) { global $submenu, $menu, $_wp_real_parent_file, $_wp_submenu_nopriv, $_registered_pages, $_parent_pages; $menu_slug = plugin_basename( $menu_slug ); $parent_slug = plugin_basename( $parent_slug ); if ( ! isset( $submenu[ $parent_slug ] ) && $menu_slug !== $parent_slug ) { foreach ( (array) $menu as $parent_menu ) { if ( $parent_menu[2] === $parent_slug && current_user_can( $parent_menu[1] ) ) { $submenu[ $parent_slug ][] = array_slice( $parent_menu, 0, 4 ); } } } $new_sub_menu = array( $menu_title, $capability, $menu_slug, $page_title ); } |
関数の中身は長いので、関係があるところだけ抜き出して説明します。
まず、show_in_menu の値は$parent_slugに入ります。
そして、いくつかグローバル変数をよびだしていますが、この中の$submenu の値を見てみます。
1 2 |
global $submenu; var_dump($submenu); |
var_dump の結果として、
array(10) { [“index.php”]=> array(2) { [0]=> array(3) { [0]=> string(9) “ホーム” [1]=> string(4) “read” [2]=> string(9) “index.php” } [10]=> array(3) { [0]=> string(86) “更新 3” [1]=> string(11) “update_core” [2]=> string(15) “update-core.php” } } [“upload.php”]=> array(2) { [5]=> array(3) { [0]=> string(15) “ライブラリ” [1]=> string(12) “upload_files” [2]=> string(10) “upload.php” } [10]=> array(3) { [0]=> string(12) “新規追加” [1]=> string(12) “upload_files” [2]=> string(13) “media-new.php” } } ……}
といった配列が帰ってきました。
この配列の中で投稿ページとカスタムメニューページの部分を抜き出してみます。
投稿ページ
[“edit.php”]=> array(4) { [5]=> array(3) { [0]=> string(12) “投稿一覧” [1]=> string(10) “edit_posts” [2]=> string(8) “edit.php” } [10]=> array(3) { [0]=> string(12) “新規追加” [1]=> string(10) “edit_posts” [2]=> string(12) “post-new.php” } [15]=> array(3) { [0]=> string(15) “カテゴリー” [1]=> string(17) “manage_categories” [2]=> string(31) “edit-tags.php?taxonomy=category” } [16]=> array(3) { [0]=> string(6) “タグ” [1]=> string(16) “manage_post_tags” [2]=> string(31) “edit-tags.php?taxonomy=post_tag” }}
カスタムメニュー
[“all_post”]=> array(3) { [0]=> array(4) { [0]=> string(30) “すべてのカスタム投稿” [1]=> string(14) “manage_options” [2]=> string(8) “all_post” [3]=> string(27) “投稿タイプ一覧画面” } [1]=> array(4) { [0]=> string(10) “News 一覧” [1]=> string(10) “edit_posts” [2]=> string(23) “edit.php?post_type=news” [3]=> string(4) “News” } [2]=> array(4) { [0]=> string(7) “Article” [1]=> string(10) “edit_posts” [2]=> string(26) “edit.php?post_type=article” [3]=> string(7) “Article” } }
$submenu[$parent_slug]はこの場合、$submenu[‘edit.php’]と、$submenu[‘all_post’]です。
つまり add_submenu_page の第 1 引数は、$submenu のキーということになります。
同じように$menu も抜き出します。
1 2 |
global $menu; var_dump($menu); |
var_dump の結果として、
array(13) { [2]=> array(7) { [0]=> string(21) “ダッシュボード” [1]=> string(4) “read” [2]=> string(9) “index.php” [3]=> string(0) “” [4]=> string(43) “menu-top menu-top-first menu-icon-dashboard” [5]=> string(14) “menu-dashboard” [6]=> string(19) “dashicons-dashboard” } ……}
といった配列が帰ってきました。
この配列の中でも投稿ページとカスタムメニューページの部分を抜き出してみます。
投稿ページ
[5]=> array(7) { [0]=> string(6) “投稿” [1]=> string(10) “edit_posts” [2]=> string(8) “edit.php” [3]=> string(0) “” [4]=> string(52) “menu-top menu-icon-post open-if-no-js menu-top-first” [5]=> string(10) “menu-posts” [6]=> string(20) “dashicons-admin-post” }
カスタムメニュー
[3]=> array(7) { [0]=> string(30) “すべてのカスタム投稿” [1]=> string(14) “manage_options” [2]=> string(8) “all_post” [3]=> string(27) “投稿タイプ一覧画面” [4]=> string(45) “menu-top toplevel_page_all_post menu-top-last” [5]=> string(22) “toplevel_page_all_post” [6]=> string(19) “dashicons-menu-alt3” }
投稿ページでは[2]=> string(8) “edit.php”、カスタムメニューでは[2]=> string(8) “all_post”と、投稿ページではファイル名が、カスタムメニューではスラグ名が入っています。
$menu[2]の値にファイル名ではなくスラグ名が入っているのはなぜでしょうか?
add_menu_page を調べてみます。
add_menu_page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $callback = '', $icon_url = '', $position = null ) { global $menu, $admin_page_hooks, $_registered_pages, $_parent_pages; $new_menu = array( $menu_title, $capability, $menu_slug, $page_title, 'menu-top ' . $icon_class . $hookname, $hookname, $icon_url ); if ( null === $position || ! is_numeric( $position ) ) { $menu[] = $new_menu; } elseif ( isset( $menu[ (string) $position ] ) ) { $collision_avoider = base_convert( substr( md5( $menu_slug . $menu_title ), -4 ), 16, 10 ) * 0.00001; $position = (string) ( $position + $collision_avoider ); $menu[ $position ] = $new_menu; } else { $position = (string) $position; $menu[ $position ] = $new_menu; |
この関数も関係している部分を抜き出します。$new_menuという配列に引数を入れていますね。
2番目は$menu_slug、つまりスラグ名です。
そして$new_menuを$menu に入れています。
これが2番目にスラグ名が入っていた理由です。
$submenuと$menu の中身がわかったので、この2つを使用している部分を確認します。
サブメニューの登録
1 2 3 4 5 6 7 8 |
if ( ! isset( $submenu[ $parent_slug ] ) && $menu_slug !== $parent_slug ) { foreach ( (array) $menu as $parent_menu ) { if ( $parent_menu[2] === $parent_slug && current_user_can( $parent_menu[1] ) ) { $submenu[ $parent_slug ][] = array_slice( $parent_menu, 0, 4 ); } } } $new_sub_menu = array( $menu_title, $capability, $menu_slug, $page_title ); |
この if 文では、サブメニューが一切存在しないかをチェックしています。
存在しなかった場合、$menuの2番目、つまりスラグ名が$parent_slug の値と同じかどうかと、$menuの1番目、権限がtrueであるかをチェックし、trueなら$submenu に配列を追加します。
最後に、メニューを表示するコードを調べます。
menu.php
1 2 3 4 5 6 7 8 |
foreach ( $menu as $id => $data ) { if ( empty( $submenu[ $data[2] ] ) ) { continue; } $subs = $submenu[ $data[2] ]; $first_sub = reset( $subs ); $old_parent = $data[2]; $new_parent = $first_sub[2]; |
$menuの2番目を取り出して$submenu のキーに入れています。つまり、投稿ページであれば’edit.php’、今回作成したカスタムメニューであれば’all_post’です。
まとめ
- サブメニューとして表示されるものは$submenu[$menu[2]]。
- add_submenu_page では、初めてサブメニューを登録する際、第 1 引数である$parent_slugがキーとなり、$submenu[$parent_slug]に登録される。show_in_menu を文字列にすると、show_in_menu を$parent_slug の値とした add_submenu_page が呼び出される。
- add_menu_page では、スラグ名として指定した値が$menu[2]に入る。デフォルトのメニューでは、$menu[2]にはファイル名が入っている。
つまり、$menu[2]に入った値の差が、show_in_menu の書き方の違いを生んだということになります。
今回は show_in_menu の値の違いについて紹介しました。皆さんの疑問の解消になれば幸いです。
また何か新しい学びがあれば、紹介したいと思います。
参考記事
Footnotes
- 関数リファレンス/register post type(※参考にした日本語版WordPressCodex記事が削除されたためリンク解除)
- register_post_type
WordPressサイト制作・カスタマイズなら「wp.make」にお任せ!
WordPressでのサイト制作やリニューアルを検討する時、以下のようなお悩みはありませんか?
- WordPressに詳しい制作会社に依頼したいが、どこがいいかわからない…
- セキュリティ対策をしっかりしたいが、社内にノウハウがないのでプロに任せたい…
- WordPressに最適なサーバーの選定や構築から依頼したい…
- SEO対策や高速化も考慮したサイト構築を行なってほしい…
- 制作後の保守・運用についてもサポートしてほしい…
- 今のサイトを簡単に運用できるようにしてほしい…
「wp.make」は、WordPressのプロフェッショナル集団によるWordPressサイト制作・カスタマイズサービスです。
サイトの制作だけでなく、WordPressに最適なサーバーの選定や構築といったインフラ面の支援から、SEO対策や表示スピードの高速化、高度なセキュリティ対策や制作後の保守・運用サポートまで、WordPressに関わることならあらゆるお悩みを解消いたします。
既存のお客さまからも
「コミュニケーションが取りやすく、クオリティが高い」
「WordPressのプロとして信頼感がある」
と大変ご好評をいただいています。
WordPressサイトの制作・カスタマイズをご検討されているなら、ぜひ以下からお気軽にご相談ください。
WordPress開発・カスタマイズなら 『wp.make』
全案件WordPressのみ!
株式会社e2eの『wp.make』はWordPress専門のWeb制作サービスです。
WordPress案件だけを扱っているから、技術・ノウハウ・対応力が圧倒的!
【WordPressサイト制作でよくあるお悩み】
・運用シーンが想定されておらず、更新しづらかった…
・打ち合わせで専門用語が多くてわかりづらい…
・制作後の保守には対応してくれなかった…
こんな事態になる前に、ぜひ一度、ご相談ください!
WordPressサイトを作るなら、一番WordPressに詳しいところへ!