Ordine menu / sottomenu API Wordpress


11

Sto sviluppando un tema figlio usando Wordpress 3.4.2 e la versione di sviluppo del Framework opzioni di David Price . Questo è il mio primo tema e sono relativamente nuovo, quindi ho dato un'occhiata al codice Wordpress e ho verificato la registrazione degli elementi nell'API.

Senza manomettere i file esterni al di fuori del mio tema, mi chiedevo se ci fosse un modo per riorganizzare la posizione della pagina Opzioni del tema all'interno della gerarchia del menu Aspetto , quindi quando il mio tema è attivato, la posizione non è come la prima immagine ma come la seconda.

vecchionuovo

So che puoi creare un menu (come la scheda Aspetto , Plugin , Utenti ecc.) O un sottomenu ( Temi , Widget , Menu ecc.), Ma come farei per impostare un sottomenu dire, secondo dall'alto?

Da quello che raccolgo, da qualche parte viene chiamato un ordine e altre pagine all'interno del functions.phpfile vengono inserite dopo quelle?

Nel mio file 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';
}

Grazie.


Hai provato la funzione aggiornata?
Adam

Grazie per essere tornato da me @userabuser. Ho copiato e incollato il tuo script aggiornato e sembra spostare gli elementi su e giù nell'elenco senza sovrascrivere altri ... tuttavia, con il nuovo aggiornamento, sto ancora ricevendo alcuni errori dal menu Widget . Warning: Invalid argument supplied for foreach() in /wp-content/themes/mythemename/functions.php on line 1444 Linea 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 linea 1468: ksort($submenu[$menus]);
user1752759

Se potessi dare un'occhiata a questo, sarebbe fantastico.
user1752759

Risposte:


3

Ecco un esempio;

Per prima cosa, per capire l'ordine delle voci del sottomenu in base alla sua chiave di matrice, è possibile eseguire una var_dumpvariabile globale del sottomenu $ che genererà quanto segue;

(Sto usando il menu Messaggi e il sottomenu come esempio)

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

Possiamo vedere che la mia voce di sottomenu viene aggiunta alla matrice con una chiave di 17 dopo le voci predefinite.

Se ad esempio voglio aggiungere la mia voce di sottomenu, subito dopo la voce di sottomenu Tutti i messaggi, devo farlo impostando la mia chiave di array su 6, 7, 8 o 9 (rispettivamente dopo 5 e prima di 10.

Ecco come lo fai ...

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

}

Risultato,

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

... provalo e facci sapere come vai!

Aggiornamento 1:

Aggiungi questo al tuo file 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]);

}

Il mio aggiornamento include un modo leggermente più semplice per gestire l'impostazione della posizione del menu, è necessario solo specificare il nome della pagina del sottomenu e la posizione desiderata all'interno del menu. Tuttavia, se si seleziona una pagina del sottomenu $locationuguale a quella di una chiave esistente, sostituirà quella chiave con la propria, quindi la voce di menu scomparirà con la voce di menu al suo posto. Incrementa o decrementa il numero per ordinare correttamente il tuo menu, se questo è il caso. Allo stesso modo, se qualcuno installa un plugin che ha effetto sulla stessa area di menu e per il quale ha lo stesso $locationelemento del sottomenu, si verificherà lo stesso problema. Per aggirare ciò, l'esempio di Kaiser fornisce alcuni controlli di base per questo.

Aggiornamento 2:

Ho aggiunto un ulteriore blocco di codice che controlla tutte le chiavi esistenti nell'array rispetto alle nostre desiderate $locatione se viene trovata una corrispondenza, aumenteremo il nostro $locationvalore 1per evitare che le voci di menu si sovrappongano. Questo è il codice responsabile di ciò,

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

Aggiornamento 3: (script rivisto per consentire l'ordinamento di più voci di sottomenu)

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;

}

Nell'esempio sopra puoi scegliere come target più sottomenu e più voci per sottomenu impostando i parametri di conseguenza all'interno della $target_menuvariabile che contiene un array multidimensionale di valori.

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

Questa revisione eviterà che le voci dei sottomenu si sovrascrivano reciprocamente se hanno la stessa chiave (posizione), poiché scorrerà fino a trovare una chiave (posizione) disponibile che non esiste.


Grazie per la risposta rapida userabuser, ma sono abbastanza nuovo per tutto questo, quindi per favore abbi pazienza con me. Non sono esattamente sicuro su come implementare il tuo script / codice sopra e su quale file debba essere inserito a causa di quanto sia stato scritto in modo conciso - per favore, elaboralo. Con questo esempio funzionante però e in uscita il numero necessario ... se in seguito l'utente dovesse installare un plugin che creava un menu di livello superiore aggiuntivo con alcuni sotto-livelli interni (come una soluzione di e-commerce), sarà questo effettuare il tasto array e frenare cosa si è prefissato di fare?
user1752759

1
@Rob Ha apportato una leggera regolazione che dovrebbe aiutare a evitare situazioni in cui le voci di menu si sovrappongono.
Adam,

@ user1752759 Cosa c'entra questo con quanto sopra? Qual è il percorso completo del file Functions.php che fornisci nel tuo commento sopra? Qual è il codice all'interno di quel file? Finalmente la conversazione ha funzionato per te. Funziona anche per me. Quindi sospetto che qualcos'altro qui potrebbe essere un errore nel tuo codice, se ricordo l'ultima volta che hai duplicato due frammenti di codice e non hai le parentesi graffe corrette attorno alla tua funzione.
Adam,

Grazie per essere tornato da me @userabuser. Ho copiato e incollato il tuo script aggiornato e sembra spostare gli elementi su e giù nell'elenco senza sovrascrivere altri ... tuttavia, con il nuovo aggiornamento, sto ancora ricevendo alcuni errori nel menu Widget. Warning: Invalid argument supplied for foreach() in /wp-content/themes/mythemename/functions.php on line 1444 Linea 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 linea 1468: ksort($submenu[$menus]);
user1752759

Se potessi dare un'occhiata a questo, sarebbe fantastico.
user1752759

2

Il menu di amministrazione (e i suoi problemi)

Poiché il menu di amministrazione è gravemente privo di hook e di un'API pubblica (che consente di spostare gli elementi), è necessario utilizzare alcune soluzioni alternative. La seguente risposta mostra cosa ti sta aspettando in futuro e come puoi aggirare fintanto che abbiamo lo stato attuale del nucleo.

Per prima cosa devo notare che scribu sta lavorando a una patch del menu di amministrazione che dovrebbe rendere la gestione molto più semplice. L'attuale struttura è piuttosto incasinata e ho scritto un articolo a riguardo che presto sarà obsoleto. Aspettatevi che WP 3.6 cambi completamente le cose.

Quindi c'è anche il punto, che non dovresti più usare le pagine Opzioni per i temi. C'è - al giorno d'oggi - il "Customizer tema" per questo.

Il plugin

Ho scritto un plugin che lo verifica con la pagina "Opzioni tema" predefinita per la pagina delle opzioni TwentyEleven / Ten. Come puoi vedere, non esiste un'API reale che consenta qualsiasi posizione. Quindi dobbiamo intercettare il globale.

In breve: basta seguire i commenti e dare un'occhiata agli avvisi di amministrazione, che ho aggiunto per darti un risultato di debug.

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

Buona fortuna e buon divertimento.


2

Filtri personalizzati

C'è un'altra possibilità per raggiungere questo obiettivo. Non chiedermi perché non ci ho pensato prima. Ad ogni modo, c'è un filtro dedicato a un ordine di menu personalizzato. Basta impostarlo su trueper consentire un ordine personalizzato. Quindi hai un secondo gancio per ordinare le voci del menu principale. Qui intercettiamo global $submenue cambiamo le voci del nostro sottomenu.

inserisci qui la descrizione dell'immagine

Questo esempio sposta l' elemento Menu sopra l' elemento Widget per dimostrarne la funzionalità. Puoi adattarlo a quello che ti piace.

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

Non sono molto fiducioso quando si tratta di utilizzare PHP @kaiser, ma potresti conoscere un modo per implementare lo script sopra per includere più elementi all'interno dello stesso function wpse70916_custom_submenu_order( $menu )da dire, riordinare non solo il menu , ma anche il tema Opzioni , Widget , Editor ecc. Che lo rendono abbastanza flessibile e anche in modo che gli elementi non si sovrappongano? Grazie.
user1752759

@ user1752759 Il plug-in ha già questa flessibilità. La sicurezza dei conflitti (evitare l'override) è un altro problema. Ciò non sarà possibile in uno scenario del 100% in quanto non è possibile assegnare l'ultima azione. C'è sempre qualcosa che può essere eseguito in seguito. Comunque: per favore, apri una nuova domanda e link a questo.
Kaiser

grazie e farà Kaiser. se non è chiedere troppo, potresti aggiornare lo script sopra per mostrare come vengono fatti più elementi (ad es. il menu e i widget ), che dovrei essere in grado di utilizzare come guida per fare lo stesso con altri elementi? Essendo abbastanza nuovo in PHP, non penso di farlo correttamente, forse a causa dei numeri. salute
user1752759

Per favore, fai una nuova domanda e link a questo. Grazie.
Kaiser
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.