Menú API de Wordpress / Orden de submenú

11

Estoy desarrollando un tema secundario con Wordpress 3.4.2 y la versión de desarrollo del Marco de opciones de David Price . Este es mi primer tema y soy relativamente nuevo en esto, así que he echado un vistazo al Codex de Wordpress y he verificado el registro de elementos en la API.

Sin alterar ningún archivo externo fuera de mi tema, me preguntaba si había una forma de reorganizar la ubicación de la página Opciones de tema dentro de la jerarquía del menú Apariencia , por lo que cuando mi tema está activado, la posición no es como la primera imagen pero como la segunda.

antiguonuevo

Sé que puede crear un menú (como la pestaña Apariencia , Complementos , Usuarios , etc.) o un submenú ( Temas , Widgets , Menús , etc.), pero ¿cómo haría para configurar un submenú? ¿desde la parte superior?

Por lo que deduzco, ¿en algún lugar se llama un pedido y functions.phpse colocan otras páginas adicionales dentro del archivo después de esas?

En mi archivo 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';
}

Gracias.

usuario1752759
fuente
¿Probaste la función actualizada?
Adam
Gracias por contactarme @userabuser. He copiado y pegado su script actualizado y parece mover los elementos hacia arriba y hacia abajo de la lista sin anular ningún otro ... sin embargo, con la nueva actualización, sigo recibiendo algunos errores en el menú Widgets . Warning: Invalid argument supplied for foreach() in /wp-content/themes/mythemename/functions.php on line 1444 Línea 1444: foreach ($submenu[$menus] as $index => $value){ y la Warning: ksort() expects parameter 1 to be array, null given in /wp-content/themes/mythemename/functions.php on line 1468 línea de 1468: ksort($submenu[$menus]);
user1752759
Si pudieras echarle un vistazo a esto, sería genial.
user1752759

Respuestas:

3

Aquí hay un ejemplo;

Primero, para determinar el orden de los elementos del submenú en función de su clave de matriz, puede hacer un var_dumpen la variable global $ submenu que generará lo siguiente;

(Estoy usando el menú Publicaciones y el submenú como ejemplo)

  //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 mi elemento del submenú se agrega a la matriz con una clave de 17 después de los elementos predeterminados.

Si, por ejemplo, deseo agregar mi elemento del submenú, directamente después del elemento del submenú Todas las publicaciones , debo hacerlo configurando mi clave de matriz en 6, 7, 8 o 9 (cualquier cosa después de 5 y antes de 10 respectivamente.

Así es como lo haces ...

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

... pruébalo y cuéntanos cómo te va.

Actualización 1:

Agregue esto a su archivo 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]);

}

Mi actualización incluye una forma un poco más fácil de manejar la configuración de la posición de su menú, solo necesita estipular el nombre de su página de submenú y la posición que desea dentro del menú. Sin embargo, si selecciona una página de submenú $locationigual a la de una tecla existente, anulará esa tecla con la suya, por lo que el elemento de menú desaparecerá con su elemento de menú en su lugar. Aumente o disminuya el número para ordenar correctamente su menú si ese es el caso. De manera similar, si alguien instala un complemento que afecta esa misma área de menú, y para el que tiene el mismo elemento $locationque su submenú, se producirá el mismo problema. Para evitar eso, el ejemplo de Kaiser proporciona algunas comprobaciones básicas para eso.

Actualización 2:

He agregado un bloque de código adicional que verifica todas las claves existentes en la matriz con respecto a nuestra deseada $locationy, si se encuentra una coincidencia, incrementaremos nuestro $locationvalor 1para evitar que los elementos del menú se anulen entre sí. Este es el código responsable de eso,

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

Actualización 3: (secuencia de comandos revisada para permitir la clasificación de múltiples elementos del submenú)

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;

}

En el ejemplo anterior, puede seleccionar múltiples submenús y múltiples elementos por submenú configurando los parámetros en consecuencia dentro de la $target_menuvariable que contiene una 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 revisión evitará que los elementos del submenú se sobrescriban entre sí si tienen la misma clave (posición), ya que se desplazará hasta encontrar una clave disponible (posición) que no existe.

Adán
fuente
Gracias por la rápida respuesta userabuser, pero soy bastante nuevo en todo esto, así que por favor tengan paciencia conmigo. No estoy exactamente seguro de cómo implementar su script / código anterior y en qué archivo debe colocarse debido a lo conciso que se ha escrito, por favor explique. Sin embargo, con este ejemplo funcionando y generando el número necesario ... si el usuario fuera a instalar un complemento más tarde que creara un menú de nivel superior adicional con algunos subniveles dentro (como una solución de comercio electrónico), esto efectuar la clave de matriz y frenar lo que se ha establecido para hacer?
user1752759
1
@Rob hizo un pequeño ajuste que debería ayudar a evitar situaciones en las que los elementos del menú se anulan entre sí.
Adam
@ user1752759 ¿Qué tiene esto que ver con lo anterior? ¿Cuál es la ruta completa al archivo functions.php que proporciona en su comentario anterior? ¿Cuál es el código dentro de ese archivo? En la última conversación esto funcionó para ti. También me funciona. Por lo tanto, sospecho que aquí podría faltar algo más en su código, si no recuerdo mal la última vez que duplicó dos fragmentos de código y no tenía las llaves correctas alrededor de su función.
Adam
Gracias por contactarme @userabuser. He copiado y pegado su script actualizado y parece mover los elementos hacia arriba y hacia abajo de la lista sin anular ningún otro ... sin embargo, con la nueva actualización, todavía recibo algunos errores en el menú Widgets. Warning: Invalid argument supplied for foreach() in /wp-content/themes/mythemename/functions.php on line 1444 Línea 1444: foreach ($submenu[$menus] as $index => $value){ y Warning: ksort() expects parameter 1 to be array, null given in /wp-content/themes/mythemename/functions.php on line 1468 Línea 1468: ksort($submenu[$menus]);
user1752759
Si pudieras echarle un vistazo a esto, sería genial.
user1752759
2

El menú de administración (y sus problemas)

Como el menú de administración carece de ganchos y una API pública (que permite mover los elementos), debe usar algunas soluciones. La siguiente respuesta le muestra lo que le espera en el futuro y cómo puede solucionarlo siempre que tengamos el estado actual del núcleo.

Primero tengo que tener en cuenta que scribu está trabajando en un parche del menú de administración que debería facilitar mucho el manejo. La estructura actual está bastante desordenada y he escrito un artículo al respecto que pronto quedará desactualizado. Espere que WP 3.6 cambie las cosas por completo.

Luego también está el punto, que ya no deberías usar páginas de Opciones para temas. Existe, hoy en día, el »Personalizador de temas« para eso.

El complemento

Escribí un complemento que prueba esto con la página predeterminada "Opciones de tema" para la página de opciones TwentyEleven / Ten. Como puede ver, no hay una API real que permita ninguna posición. Entonces tenemos que interceptar lo global.

En resumen: solo siga los comentarios y eche un vistazo a los avisos de administrador, que agregué para darle algunos resultados de depuración.

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

Buena suerte y diviertete.

emperador
fuente
2

Filtros personalizados

Hay otra posibilidad de lograr esto. No me preguntes por qué no lo había pensado antes. De todos modos, hay un filtro dedicado a un orden de menú personalizado. Simplemente configúrelo truepara permitir un pedido personalizado. Luego tienes un segundo gancho para ordenar los elementos del menú principal. Allí solo interceptamos global $submenuy cambiamos los elementos de nuestro submenú.

ingrese la descripción de la imagen aquí

Este ejemplo mueve el elemento Menús sobre el elemento Widgets para demostrar su funcionalidad. Puedes ajustarlo a lo que quieras.

<?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;
}
emperador
fuente
No estoy muy seguro cuando se trata de usar PHP @kaiser, pero ¿podrías conocer una manera de implementar el script anterior para incluir múltiples elementos dentro del mismo function wpse70916_custom_submenu_order( $menu )para decir, reordenar no solo el Menú , sino también el Tema ¿Opciones , widgets , editor , etc., lo que lo hace bastante flexible y también para que los elementos no se anulen entre sí? Gracias.
user1752759
@ user1752759 El complemento ya tiene esta flexibilidad. La seguridad de los conflictos (evitar anular) es otro problema. Esto no será posible en un escenario de 100%, ya que no puede asignar su acción al final. Siempre hay algo que puede ejecutarse más tarde. De todos modos: abra una nueva pregunta y enlace a esta.
Kaiser
gracias y haré kaiser. Si no es mucho pedir, ¿podría actualizar el script anterior para mostrar cómo se realizan varios elementos (por ejemplo, el Menú y los Widgets ), que debería poder usar como guía para hacer lo mismo con otros elementos? Siendo bastante nuevo en PHP, no creo que lo esté haciendo correctamente, quizás debido a los números. aplausos
user1752759
Por favor, solo haga una nueva pregunta y enlace a esta. Gracias.
kaiser