WordPress API菜单/子菜单顺序

时间:2012-10-30 作者:user1752759

我正在使用Wordpress 3.4.2和David Price开发的选项框架开发版本开发一个儿童主题。这是我的第一个主题,我对这个主题还比较陌生,所以我查看了Wordpress Codex,并检查了将项目注册到API中的情况。

在不篡改主题之外的任何外部文件的情况下,我想知道是否有办法重新安排主题选项页面在外观菜单层次结构中的位置-因此,当我的主题被激活时,位置与第一个图像不同,而与第二个图像相似。

oldnew

我知道您可以创建菜单(例如外观选项卡、插件、用户等)或子菜单(主题、小部件、菜单等),但我如何设置子菜单,比如从顶部算起的第二个?

据我所知,在某个地方有一个订单正在被调用,并且在functions.php 文件放在这些之后?

在我的功能中。php文件:

// Add our "Theme Options" page to the Wordpress API admin menu.
if ( !function_exists( \'optionsframework_init\' ) ) {
    define( \'OPTIONS_FRAMEWORK_DIRECTORY\', get_template_directory_uri() . \'/inc/\' );
    require_once dirname( __FILE__ ) . \'/inc/options-framework.php\';
}
谢谢。

3 个回复
SO网友:Adam

这里有一个例子;

首先,要根据子菜单项的数组键确定子菜单项的顺序,可以执行以下操作var_dump 在$子菜单上,全局变量将输出以下内容:;

(我以Posts菜单和sub菜单为例)

  //shortened for brevity....

  ["edit.php"]=>
  array(6) {
    [5]=>
    array(3) {
      [0]=> string(9) "All Posts"
      [1]=> string(10) "edit_posts"
      [2]=> string(8) "edit.php"
    }
    [10]=>
    array(3) {
      [0]=> string(7) "Add New"
      [1]=> string(10) "edit_posts"
      [2]=> string(12) "post-new.php"
    }
    [15]=>
    array(3) {
      [0]=> string(10) "Categories"
      [1]=> string(17) "manage_categories"
      [2]=> string(31) "edit-tags.php?taxonomy=category"
    }
    [17]=>
    array(3) {
      [0]=> string(14) "Sub Menu Title"
      [1]=> string(10) "edit_posts"
      [2]=> string(17) "sub_menu_page.php"
    }
  }
我们可以看到,我的子菜单项被添加到数组中,在默认项之后有一个键17。

例如,如果我想添加子菜单项,请直接在All Posts 子菜单项我需要通过将数组键设置为6、7、8或9(分别为5之后和10之前的任何值)来执行此操作。

你就是这样做的。。。

function change_submenu_order() {

    global $menu;
    global $submenu;

     //set our new key
    $new_key[\'edit.php\'][6] = $submenu[\'edit.php\'][17];

    //unset the old key
    unset($submenu[\'edit.php\'][17]);

    //get our new key back into the array
    $submenu[\'edit.php\'][6] = $new_key[\'edit.php\'][6];


    //sort the array - important! If you don\'t the key will be appended
    //to the end of $submenu[\'edit.php\'] array. We don\'t want that, we
    //our keys to be in descending order
    ksort($submenu[\'edit.php\']);

}
结果,

  ["edit.php"]=>
  array(6) {
    [5]=>
    array(3) {
      [0]=> string(9) "All Posts"
      [1]=> string(10) "edit_posts"
      [2]=> string(8) "edit.php"
    }
    [6]=>
    array(3) {
      [0]=> string(14) "Sub Menu Title"
      [1]=> string(10) "edit_posts"
      [2]=> string(17) "sub_menu_page.php"
    }
    [10]=>
    array(3) {
      [0]=> string(7) "Add New"
      [1]=> string(10) "edit_posts"
      [2]=> string(12) "post-new.php"
    }
    [15]=>
    array(3) {
      [0]=> string(10) "Categories"
      [1]=> string(17) "manage_categories"
      [2]=> string(31) "edit-tags.php?taxonomy=category"
    }
  }
。。。试试看,让我们知道你的进展如何!

更新1:将其添加到函数中。php文件;

function change_post_menu_label() {

    global $menu;
    global $submenu;

    $my_menu  = \'example_page\'; //set submenu page via its ID
    $location = 1; //set the position (1 = first item etc)
    $target_menu = \'edit.php\'; //the menu we are adding our item to

    /* ----- do not edit below this line ----- */


    //check if our desired location is already used by another submenu item
    //if TRUE add 1 to our value so menu items don\'t clash and override each other
    $existing_key = array_keys( $submenu[$target_menu] );
    if ($existing_key = $location)
    $location = $location + 1;

    $key = false;
    foreach ( $submenu[$target_menu] as $index => $values ){

        $key = array_search( $my_menu, $values );

        if ( false !== $key ){
            $key = $index;
            break;
        }
    }

     $new[\'edit.php\'][$location] = $submenu[$target_menu][$key];
     unset($submenu[$target_menu][$key]);
     $submenu[$target_menu][$location] = $new[$target_menu][$location];

    ksort($submenu[$target_menu]);

}
我的更新提供了一种更简单的方式来处理菜单位置的设置,您只需规定子菜单页面的名称和您想要在菜单中的位置<但是,如果选择子菜单页,请点击$location 与现有键相同,它将用您的键覆盖该键,因此菜单项将随您的菜单项消失。如果出现这种情况,则递增或递减数字以正确排序菜单。类似的,如果有人安装了一个影响相同菜单区域的插件,并且该插件具有相同的$location 作为子菜单项,同样的问题也会发生为了避免这种情况,Kaiser的例子提供了一些基本的检查方法。

更新2:

我添加了一个额外的代码块,根据所需的$location 如果找到匹配项,我们将增加$location 价值依据1 以避免菜单项相互覆盖。这是负责的代码,

   //excerpted snippet only for example purposes (found in original code above)
   $existing_key = array_keys( $submenu[$target_menu] );
   if ($existing_key = $location)
   $location = $location + 1;
更新3:(修改脚本以允许对多个子菜单项进行排序)
add_action(\'admin_init\', \'move_theme_options_label\', 999);

function move_theme_options_label() {
    global $menu;
    global $submenu;

$target_menu = array(
    \'themes.php\' => array(
        array(\'id\' => \'optionsframework\', \'pos\' => 2),
        array(\'id\' => \'bp-tpack-options\', \'pos\' => 4),
        array(\'id\' => \'multiple_sidebars\', \'pos\' => 3),
        )
);

$key = false;

foreach ( $target_menu as $menus => $atts ){

    foreach ($atts as $att){

        foreach ($submenu[$menus] as $index => $value){

        $current = $index;  

        if(array_search( $att[\'id\'], $value)){ 
        $key = $current;
        }

            while (array_key_exists($att[\'pos\'], $submenu[$menus]))
                $att[\'pos\'] = $att[\'pos\'] + 1;

            if ( false !== $key ){

                if (array_key_exists($key, $submenu[$menus])){
                    $new[$menus][$key] = $submenu[$menus][$key];
                    unset($submenu[$menus][$key]);
                    $submenu[$menus][$att[\'pos\']] = $new[$menus][$key];

                } 
            }
        }
    }
}

ksort($submenu[$menus]);
return $submenu;

}
在上面的示例中,通过在$target_menu 保存多维值数组的变量。

$target_menu = array(
//menu to target (e.g. appearance menu)
\'themes.php\' => array(
    //id of menu item you want to target followed by the position you want in sub menu
    array(\'id\' => \'optionsframework\', \'pos\' => 2),
    //id of menu item you want to target followed by the position you want in sub menu
    array(\'id\' => \'bp-tpack-options\', \'pos\' => 3),
    //id of menu item you want to target followed by the position you want in sub menu
    array(\'id\' => \'multiple_sidebars\', \'pos\' => 4),
    )
 //etc....
);
如果子菜单项具有相同的键(位置),此修订将防止子菜单项相互过度写入,因为它将循环使用,直到找到不存在的可用键(位置)。

SO网友:kaiser

管理菜单(及其问题)

由于管理菜单严重缺乏任何挂钩和公共API(允许移动项目),因此必须使用一些变通方法。下面的答案向您展示了未来等待您的是什么,以及只要我们拥有当前的核心状态,您可以如何解决这些问题。

首先我要注意的是scribu is working on an admin menu patch 这应该会使操作更加容易。目前的结构相当混乱I have written an article about it 这很快就会过时。希望WP 3.6能彻底改变现状。

还有一点,你不应该再对主题使用选项页了。如今»Theme Customizer« 为此。

这个插件我编写了一个插件,用TwentyEleven/Ten选项页面的默认“主题选项”页面来测试这一点。正如你所见,没有真正的API允许任何位置。所以我们必须拦截全球卫星。

简而言之:只需遵循注释并查看管理通知,我添加这些通知是为了给您一些调试输出。

<?php
/** Plugin Name: (#70916) Move Submenu item */

add_action( \'plugins_loaded\', array( \'wpse70916_admin_submenu_items\', \'init\' ) );

class wpse70916_admin_submenu_items
{
    protected static $instance;

    public $msg;

    public static function init()
    {
        is_null( self :: $instance ) AND self :: $instance = new self;
        return self :: $instance;
    }

    public function __construct()
    {
        add_action( \'admin_notices\', array( $this, \'add_msg\' ) );

        add_filter( \'parent_file\', array( $this, \'move_submenu_items\' ) );
    }

    public function move_submenu_items( $parent_file )
    {
        global $submenu;
        $parent = $submenu[\'themes.php\'];

        $search_for = \'theme_options\';

        // Find current position
        $found = false;
        foreach ( $parent as $pos => $item )
        {
            $found = array_search( $search_for, $item );
            if ( false !== $found )
            {
                $found = $pos;
                break;
            }
        }
        // DEBUG: Tell if we didn\'t find it.
        if ( empty( $found ) )
            return $this->msg = \'That search did not work out...\';

        // Now we need to determine the first and second item position
        $temp = array_keys( $parent );
        $first_item  = array_shift( $temp );
        $second_item = array_shift( $temp );

        // DEBUG: Check if it the item fits between the first two items:
        $distance = ( $second_item - $first_item );
        if ( 1 >= $distance )
            return $this->msg = \'We do not have enough space for your item\';

        // Temporary container for our item data
        $target_data = $parent[ $found ];

        // Now we can savely remove the current options page
        if ( false === remove_submenu_page( \'themes.php\', $search_for ) )
            return $this->msg = \'Failed to remove the item\';

        // Shuffle items (insert options page)
        $submenu[\'themes.php\'][ $first_item + 1 ] = $target_data;
        // Need to resort the items by their index/key
        ksort( $submenu[\'themes.php\'] );
    }

    // DEBUG Messages
    public function add_msg()
    {
        return print sprintf(
             \'<div class="update-nag">%s</div>\'
            ,$this->msg
        );
    }
} // END Class wpse70916_admin_submenu_items
祝你好运,玩得开心。

SO网友:kaiser

自定义过滤器也可以实现这一点。不要问我为什么没有早一点考虑这件事。无论如何,有一个过滤器专门用于自定义菜单顺序。只需将其设置为true 允许自定义订单。然后你有第二个钩子来点主菜单项。在那里我们只是拦截global $submenu 并切换我们的子菜单项。

enter image description here

此示例移动Menus item 以上Widgets item 演示其功能。你可以根据自己的喜好进行调整。

<?php
defined( \'ABSPATH\' ) OR exit;
/**
 * Plugin Name: (#70916) Custom Menu Order
 * Description: Changes the menu order of a submenu item.
 */

// Allow a custom order
add_filter( \'custom_menu_order\', \'__return_true\' );
add_filter( \'menu_order\', \'wpse70916_custom_submenu_order\' );
function wpse70916_custom_submenu_order( $menu )
{
    // Get the original position/index
    $old_index = 10;
    // Define a new position/index
    $new_index = 6;

    // We directly interact with the global
    $submenu = &$GLOBALS[\'submenu\'];
    // Assign our item at the new position/index
    $submenu[\'themes.php\'][ $new_index ] = $submenu[\'themes.php\'][ $old_index ];
    // Get rid of the old item
    unset( $submenu[\'themes.php\'][ $old_index ] );
    // Restore the order
    ksort( $submenu[\'themes.php\'] );

    return $menu;
}

结束