Ordem dos menus / submenus da API do Wordpress

11

Estou desenvolvendo um tema filho usando Wordpress 3.4.2 e a versão de desenvolvimento do Options Framework por David Price . Este é meu primeiro tema e eu sou relativamente novo nisso, então eu dei uma olhada no Wordpress Codex e verifiquei o registro de itens na API.

Sem adulterar nenhum arquivo externo fora do meu tema, fiquei me perguntando se havia uma maneira de reorganizar onde a página Opções de Tema está localizada na hierarquia da Aparência menu - assim, quando meu tema é ativado, a posição não é como a primeira imagem, mas como a segunda.

Eu sei que você pode criar um menu (como a aba Aparência , Plugins , Usuários etc.) ou um submenu ( Temas , Widgets , Menus etc.), mas como eu poderia definir um submenu, segundo do topo?

Pelo que eu entendi, em algum lugar há um pedido sendo chamado e quaisquer outras páginas adicionais dentro do arquivo functions.php são colocadas depois delas?

No meu arquivo functions.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';
}

Obrigado.

    
por user1752759 30.10.2012 / 07:18

3 respostas

3

Aqui está um exemplo;

Primeiro, para descobrir a ordem dos itens do sub-menu com base em sua chave de matriz, você pode fazer um var_dump na variável global $ submenu, que produzirá o seguinte;

(Estou usando o menu Posts e o submenu como exemplo)

  //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"
    }
  }

Podemos ver que meu item de submenu é adicionado ao array com uma chave de 17 após os itens padrão.

Se, por exemplo, eu quiser adicionar meu item de submenu, diretamente após o item do submenu Todas as postagens , preciso definir minha chave de matriz como 6, 7, 8 ou 9 ( qualquer coisa depois de 5 e antes de 10, respectivamente.

É assim que você faz ...

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']);

}

Resultado,

  ["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"
    }
  }

... experimente e deixe-nos saber como você vai!

Atualização 1:

Adicione isto ao seu arquivo functions.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]);

}

Minha atualização inclui uma maneira um pouco mais fácil de lidar com a configuração da posição do menu, você só precisa estipular o nome da página do submenu e a posição desejada no menu. No entanto, se você selecionar uma página de submenu $location igual à de uma chave existente, ela será substituída pela chave, portanto, o item de menu desaparecerá com o item de menu em seu lugar. Incrementar ou decrementar o número para ordenar corretamente o seu menu, se for esse o caso. Similar, se alguém instala um plugin que afeta a mesma área de menu, e para o qual tem o mesmo $location do seu submenu, o mesmo problema ocorrerá. Para contornar isso, o exemplo da Kaiser fornece algum verificação básica para isso.

Atualização 2:

Adicionei um bloco de código adicional que verifica todas as chaves existentes na matriz em relação ao $location desejado e, se uma correspondência for encontrada, incrementaremos nosso $location em 1 para evitar itens de menu substituindo um ao outro. Este é o código responsável por isso,

   //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;

Atualização 3: (script revisado para permitir a classificação de vários itens do submenu)

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;

}

No exemplo acima, você pode segmentar vários submenus e vários itens por submenu, definindo os parâmetros de acordo com a variável $target_menu , que contém uma matriz multidimensional de valores.

$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....
);

Esta revisão impedirá que os itens do sub-menu se sobreponham mutuamente se tiverem a mesma chave (posição), enquanto percorrerão até encontrar uma chave (posição) disponível que não exista.

    
por userabuser 30.10.2012 / 13:07
2

O menu admin (e seus problemas)

Como o menu admin carece seriamente de ganchos e uma API pública (que permite mover os itens), você tem que usar algumas soluções alternativas. A resposta a seguir mostra o que está esperando por você no futuro e como você pode trabalhar contanto que tenhamos o estado atual do núcleo.

Primeiramente, devo observar que o scribu está trabalhando em um patch do menu de administração que deve tornar o tratamento muito Mais fácil. A estrutura atual é bastante confusa e eu escrevi um artigo sobre isso que em breve estará desatualizado . Espere que o WP 3.6 mude completamente as coisas.

Depois, há também o ponto, que você não deve mais usar páginas de opções para temas. Há - hoje em dia - o »Theme Customizer« por isso.

O plugin

Eu escrevi um plugin que testa isso com a página padrão "Opções de Tema" para a página de opções TwentyEleven / Ten. Como você pode ver, não existe uma API real que permita qualquer posição. Então temos que interceptar o global.

Resumindo: basta seguir os comentários e dar uma olhada nos avisos do admin, que adicionei para dar a você alguma saída de depuração.

<?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

Boa sorte e divirta-se.

    
por kaiser 30.10.2012 / 14:16
2

Filtros personalizados

Existe outra possibilidade para conseguir isso. Não me pergunte por que não pensei antes sobre isso. De qualquer forma, há um filtro dedicado a uma ordem de menu personalizada. Basta configurá-lo para true para permitir um pedido personalizado. Então você tem um segundo gancho para encomendar os itens do menu principal. Lá, apenas interceptamos o global $submenu e alternamos os itens do submenu.

  

Este exemplo move o item Menus acima do item Widgets para demonstrar sua funcionalidade. Você pode ajustá-lo ao que você gosta.

<?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;
}
    
por kaiser 02.02.2013 / 15:51