サポート » 使い方全般 » サブメニューが1つもないときのカスタム投稿タイプの管理画面表示

  • 解決済 Yuichiro ABE

    (@yuichiro-abe)


    サブメニューが1つもないときのカスタム投稿タイプの管理画面表示について、
    色々調べているのですがいい方法が見つからなくて、ご意見いただければと存じます。

    カスタム投稿タイプitemがセットされているとします。
    権限周りを整理して、この投稿タイプの閲覧のみのユーザーを作りたかったので
    ‘capability_type’ => ‘item’,
    “capabilities” => array(“create_posts” => “create_items”),
    をregister_post_typeの時にセットして、新規投稿と投稿の編集の権限を分離します。

    ここで、権限を絞って、あるユーザーに対しては、購読者のアクセス権に
    edite_items
    read_item
    read
    権限のみをセットした場合、メニュー上には
    ダッシュボード
    item
    プロフィール
    の3つだけになるわけですが、この場合、サブメニューがどれにも表示されなくなります。

    この状態で
    itemをクリック(edit.php?post_type=item)すると
    「このページにアクセスするための十分なアクセス権がありません。」となってページが表示できません。

    ソースを読み進んでみると
    user_can_access_admin_page()
    という関数で、管理画面へのアクセスの可否を判別しているようです。

    サブメニューがある場合は、中で呼ばれているget_admin_page_parent()関数が
    カスタム投稿の一覧画面もサブメニューとして判別して、親を返してくれるので
    上手くカスタム投稿タイプも判別してくれるのですが
    サブメニューがひとつもない場合get_admin_page_parent()関数がemptyを返すため
    このままだと、投稿タイプの一覧画面(edit.php?post_type=item)が表示できません。

    いろいろ考えたのですが、この関数自体が違っているのか、$pagenowを生成している箇所が
    違っているのではないかと思うのですが、とりあえず苦肉の策で

    diff --git a/htdocs/wp-admin/includes/plugin.php b/htdocs/wp-admin/includes/plugin.php
    index 08adef8..1b6f9e1 100644
    --- a/htdocs/wp-admin/includes/plugin.php
    +++ b/htdocs/wp-admin/includes/plugin.php
    @@ -1642,10 +1642,13 @@ function user_can_access_admin_page() {
            global $_wp_submenu_nopriv;
            global $plugin_page;
            global $_registered_pages;
    +       global $typenow;
    +
    +       $pagenow_with_type = empty($typenow) ? $pagenow : "$pagenow?post_type=$typenow";
    
            $parent = get_admin_page_parent();
    
    -       if ( !isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$parent][$pagenow] ) )
    +       if ( !isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$parent][$pagenow_with_type] ) )
                    return false;
    
            if ( isset( $plugin_page ) ) {
    @@ -1659,16 +1662,16 @@ function user_can_access_admin_page() {
            }
    
            if ( empty( $parent) ) {
    -               if ( isset( $_wp_menu_nopriv[$pagenow] ) )
    +               if ( isset( $_wp_menu_nopriv[$pagenow_with_type] ) )
                            return false;
    -               if ( isset( $_wp_submenu_nopriv[$pagenow][$pagenow] ) )
    +               if ( isset( $_wp_submenu_nopriv[$pagenow_with_type][$pagenow_with_type] ) )
                            return false;
    -               if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$pagenow][$plugin_page] ) )
    +               if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$pagenow_with_type][$plugin_page] ) )
                            return false;
                    if ( isset( $plugin_page ) && isset( $_wp_menu_nopriv[$plugin_page] ) )
                            return false;
                    foreach (array_keys( $_wp_submenu_nopriv ) as $key ) {
    -                       if ( isset( $_wp_submenu_nopriv[$key][$pagenow] ) )
    +                       if ( isset( $_wp_submenu_nopriv[$key][$pagenow_with_type] ) )
                                    return false;
                            if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$key][$plugin_page] ) )
                            return false;
    @@ -1686,7 +1689,7 @@ function user_can_access_admin_page() {
                                            return true;
                                    else
                                            return false;
    -                       } else if ( $submenu_array[2] == $pagenow ) {
    +                       } else if ( $submenu_array[2] == $pagenow_with_type ) {
                                    if ( current_user_can( $submenu_array[1] ))
                                            return true;
                                    else

    こんな対応で逃げているのですが、できればWordPress本体は触りたくないのですが、
    どなたかお分かりになる方ご意見いただけますでしょうか。

2件の返信を表示中 - 1 - 2件目 (全2件中)
  • だいぶ以前の質問なので解決済みかもしれませんが返信します。

    #29714 (user_can_access_admin_page() returning false for edit.php?post_type=CPT) – WordPress Trac
    ならびに、
    WordPress capabilities: How to restrict Add New while allowing Edit – herb miller
    で解決法が提示されているようです。

    僕は別の方法で下記のようにしています。

    add_action( 'admin_menu', 'fix_for_no_submenus', 99 );
    
    function fix_for_no_submenus() {
    	global $pagenow, $submenu;
    	if ( $pagenow !== 'edit.php' || ! $post_type = filter_input( \INPUT_GET, 'post_type' ) )
    		return;
    	if ( ! current_user_can( 'read', $post_type ) )
    		return;
    
    	$page = 'edit.php?post_type=' . $post_type;
    	if ( ! isset( $submenu[$page] ) || count( $submenu[$page] ) > 1 )
    		return;
    
    	$submenu[$page][] = [ '', '', '' ];
    }

    サブメニューに空の配列を追加してます。

    不要な配列がグローバル変数に入っていることが嫌ならば adminmenu フックで削除するのもいいかもしれませんね。

    トピック投稿者 Yuichiro ABE

    (@yuichiro-abe)

    ありがとうございます。この方法の方がフックで対応でいい感じですね。
    環境が5.4以上ではなかったため、配列の記述方法だけ変更して使わせていただきました。

    function fix_for_no_submenus() {
    		global $pagenow, $submenu;
    		if ( $pagenow !== 'edit.php' || ! $post_type = filter_input( \INPUT_GET, 'post_type' ) )
    			return;
    		if ( ! current_user_can( 'read', $post_type ) )
    			return;
    
    		$page = 'edit.php?post_type=' . $post_type;
    		if ( ! isset( $submenu[$page] ) || count( $submenu[$page] ) > 1 )
    			return;
    
    		$submenu[$page][] = array( '', '', '' );
    	}
2件の返信を表示中 - 1 - 2件目 (全2件中)
  • トピック「サブメニューが1つもないときのカスタム投稿タイプの管理画面表示」には新たに返信することはできません。