Menu da API do Wordpress / ordem do submenu


11

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

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

velhoNovo

Eu sei que você pode criar um menu (como a guia Aparência , Plug-ins , Usuários etc.) ou um submenu ( Temas , Widgets , Menus etc.), mas como eu definiria um submenu, por exemplo: do topo?

Pelo que entendi, em algum lugar existe um pedido que está sendo chamado e outras páginas adicionais dentro do functions.phparquivo são colocadas depois disso?

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.


Você tentou a função atualizada?
Adam

Obrigado por voltar para mim @userabuser. Copiei o seu script atualizado e ele parece mover os itens para cima e para baixo na lista sem substituir outros ... no entanto, com a nova atualização, ainda estou recebendo alguns erros no menu Widgets . Warning: Invalid argument supplied for foreach() in /wp-content/themes/mythemename/functions.php on line 1444 Linha 1444: foreach ($submenu[$menus] as $index => $value){ e Warning: ksort() expects parameter 1 to be array, null given in /wp-content/themes/mythemename/functions.php on line 1468 Linha 1468: ksort($submenu[$menus]);
user1752759

Se você pudesse dar uma olhada nisso, seria ótimo.
user1752759

Respostas:


3

Aqui está um exemplo;

Primeiro, para descobrir a ordem dos itens do submenu com base em sua chave de matriz, você pode fazer uma var_dumpvariável global no submenu $, que produzirá o seguinte;

(Estou usando o menu Postagens e 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 à matriz com uma chave 17 após os itens padrão.

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

É assim que se 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 isso 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 $locationigual à de uma chave existente, ela substituirá a chave pela sua, assim o item de menu desaparecerá com o item de menu em seu lugar. Aumente ou diminua o número para solicitar seu menu corretamente, se for o caso. Da mesma forma, se alguém instalar um plug-in que afeta a mesma área de menu e para o qual tem o mesmo $locationitem do submenu, o mesmo problema ocorrerá. Para contornar isso, o exemplo de Kaiser fornece algumas verificações básicas para isso.

Atualização 2:

Eu adicionei um bloco de código adicional que verifica todas as chaves existentes na matriz em relação ao desejado $locatione, se uma correspondência for encontrada, incrementaremos nosso $locationvalor 1para evitar que os itens de menu se substituam. 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 direcionar vários submenus e vários itens por submenu, definindo os parâmetros de acordo com a $target_menuvariável 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 submenu se sobrescrevam se eles tiverem a mesma tecla (posição), uma vez que percorrerá até encontrar uma chave (posição) disponível que não exista.


Obrigado pela resposta rápida userabuser, mas sou bastante novo em tudo isso, então, por favor, tenha paciência comigo. Não sei exatamente como implementar seu script / código acima e em qual arquivo ele deve ser colocado devido à forma concisa que foi escrita - por favor, elabore. No entanto, com este exemplo funcionando e emitindo o número necessário ... se o usuário instalar um plug-in mais tarde que criou um menu de nível superior adicional com alguns subníveis internos (como uma solução de comércio eletrônico), isso efetuar a chave do array e frear o que foi definido?
user1752759

1
@Rob Fez um pequeno ajuste que deve ajudar a evitar situações em que os itens do menu se anulam.
Adam

@ user1752759 O que isso tem a ver com o exposto acima? Qual é o caminho completo para o arquivo functions.php que você fornece no seu comentário acima? Qual é o código nesse arquivo? Na última conversa, isso funcionou para você. Também funciona para mim. Portanto, estou suspeitando que algo mais possa estar errado no seu código, se bem me lembro da última vez que você duplicou dois trechos de código e não tinha o aparelho correto em torno de sua função.
Adam

Obrigado por voltar para mim @userabuser. Copiei o seu script atualizado e ele parece mover os itens para cima e para baixo na lista sem substituir outros ... no entanto, com a nova atualização, ainda estou recebendo alguns erros no menu Widgets. Warning: Invalid argument supplied for foreach() in /wp-content/themes/mythemename/functions.php on line 1444 Linha 1444: foreach ($submenu[$menus] as $index => $value){ e Warning: ksort() expects parameter 1 to be array, null given in /wp-content/themes/mythemename/functions.php on line 1468 Linha 1468: ksort($submenu[$menus]);
user1752759

Se você pudesse dar uma olhada nisso, seria ótimo.
user1752759

2

O menu do administrador (e seus problemas)

Como o menu do administrador carece de ganchos e de uma API pública (que permita a movimentação dos itens), é necessário usar algumas soluções alternativas. A resposta a seguir mostra o que está esperando por você no futuro e como você pode contornar, desde que tenhamos o estado atual do núcleo.

Primeiro, devo observar que o scribu está trabalhando em um patch de menu do administrador que deve facilitar o manuseio. A estrutura atual está bastante bagunçada 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 as páginas de Opções para temas. Atualmente - existe o »Tema Customizador« para isso.

O plugin

Eu escrevi um plugin que testa isso com a página "Opções de tema" padrão 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 de administração que eu adicionei para fornecer uma 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.


2

Filtros personalizados

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

insira a descrição da imagem aqui

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

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

Não estou muito confiante no que diz respeito ao uso do PHP @kaiser, mas você possivelmente conheceria uma maneira de implementar o script acima para incluir vários itens dentro do mesmo function wpse70916_custom_submenu_order( $menu )para dizer, reordenar não apenas o Menu , mas também o Tema Opções , Widgets , Editor , etc., tornando-o bastante flexível e também para que os itens não se sobreponham? Obrigado.
user1752759

@ user1752759 O plug-in já tem essa flexibilidade. A segurança dos conflitos (evitar a substituição) é outra questão. Isso não será possível em um cenário de 100%, pois você não pode atribuir sua ação por último. Sempre há algo que pode ser executado mais tarde. De qualquer forma: abra uma nova pergunta e vincule-a.
kaiser

obrigado e vai fazer kaiser. se não for pedir demais, você poderia atualizar o script acima para mostrar como são feitos vários itens (por exemplo, o Menu e os Widgets ), que eu devo usar como guia para fazer o mesmo com outros itens? Sendo relativamente novo no PHP, acho que não estou fazendo isso corretamente, talvez por causa dos números. aplausos
user1752759

Por favor, basta fazer uma nova pergunta e vincular a esta. Obrigado.
kaiser
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.