Ordre du menu / sous-menu de l'API Wordpress

11

Je développe un thème enfant en utilisant Wordpress 3.4.2 et la version de développement du cadre d'options par David Price . Ceci est mon premier thème et je suis relativement nouveau dans ce domaine, j'ai donc jeté un œil au codex Wordpress et vérifié l'enregistrement des éléments dans l'API.

Sans altérer aucun fichier externe en dehors de mon thème, je me demandais s'il y avait un moyen de réorganiser l'emplacement de la page Options de thème dans la hiérarchie du menu Apparence - donc lorsque mon thème est activé, la position n'est pas comme la première image mais comme la seconde.

vieuxNouveau

Je sais que vous pouvez créer un menu (tel que l' onglet Apparence , Plugins , Utilisateurs, etc.) ou un sous-menu ( Thèmes , Widgets , Menus, etc.), mais comment pourrais-je procéder pour définir un sous-menu, disons, deuxième du haut?

D'après ce que je comprends, quelque part, une commande est appelée et toute autre page supplémentaire du functions.phpfichier est placée après celles-ci?

Dans mon fichier 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';
}

Merci.

user1752759
la source
Avez-vous essayé la fonction mise à jour?
Adam
Merci de m'avoir recontacté @userabuser. J'ai copié-collé votre script mis à jour et il semble déplacer les éléments de haut en bas de la liste sans remplacer les autres ... cependant, avec la nouvelle mise à jour, je reçois toujours quelques erreurs dans le menu Widgets . Warning: Invalid argument supplied for foreach() in /wp-content/themes/mythemename/functions.php on line 1444 Ligne 1444: foreach ($submenu[$menus] as $index => $value){ et Warning: ksort() expects parameter 1 to be array, null given in /wp-content/themes/mythemename/functions.php on line 1468 ligne 1468: ksort($submenu[$menus]);
user1752759
Si vous pouviez jeter un œil à cela, ce serait formidable.
user1752759

Réponses:

3

Voici un exemple;

Tout d'abord pour comprendre l'ordre des éléments du sous-menu en fonction de sa clé de tableau, vous pouvez faire un var_dumpsur la variable globale $ submenu qui produira ce qui suit;

(J'utilise le menu et le sous-menu Messages comme exemple)

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

Nous pouvons voir que mon élément de sous-menu est ajouté dans le tableau avec une clé de 17 après les éléments par défaut.

Si, par exemple, je veux ajouter mon élément de sous-menu, directement après l' élément de sous-menu Tous les messages , je dois le faire en définissant ma clé de tableau sur 6, 7, 8 ou 9 (n'importe quoi après 5 et avant 10 respectivement.

Voici comment vous le faites ...

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

}

Résultat,

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

... essayez-le et dites-nous comment vous allez!

Mise à jour 1:

Ajoutez ceci à votre fichier 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]);

}

Ma mise à jour comprend un moyen un peu plus simple de gérer le réglage de la position de votre menu, il vous suffit de préciser le nom de votre page de sous-menu et la position que vous souhaitez dans le menu. Cependant, si vous sélectionnez une page de sous-menu $locationégale à celle d'une clé existante, elle remplacera cette clé par la vôtre, ainsi l'élément de menu disparaîtra avec votre élément de menu à sa place. Augmentez ou décrémentez le nombre pour commander correctement votre menu si tel est le cas. De même, si quelqu'un installe un plugin qui affecte la même zone de menu et qui a le même $locationque votre élément de sous-menu, le même problème se produira. Pour contourner cela, l'exemple de Kaiser fournit une vérification de base pour cela.

Mise à jour 2:

J'ai ajouté un bloc de code supplémentaire qui vérifie toutes les clés existantes dans le tableau par rapport à nos souhaits $locationet si une correspondance est trouvée, nous augmenterons notre $locationvaleur 1afin d'éviter que les éléments de menu ne se remplacent. Ceci est le code responsable de cela,

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

Mise à jour 3: (script révisé pour permettre le tri de plusieurs éléments de sous-menu)

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;

}

Dans l'exemple ci-dessus, vous pouvez cibler plusieurs sous-menus et plusieurs éléments par sous-menu en définissant les paramètres en conséquence dans la $target_menuvariable qui contient un tableau multidimensionnel de valeurs.

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

Cette révision empêchera les éléments de sous-menu de se remplacer les uns les autres s'ils ont la même clé (position), car elle passera en revue jusqu'à ce qu'elle trouve une clé (position) disponible qui n'existe pas.

Adam
la source
Merci pour la réponse rapide de userabuser, mais je suis relativement nouveau dans tout cela, alors s'il vous plaît, soyez indulgent avec moi. Je ne sais pas exactement comment implémenter votre script / code ci-dessus et dans quel fichier il doit être placé en raison de la concision de son écriture - veuillez élaborer. Avec cet exemple fonctionnant bien et produisant le nombre nécessaire ... si l'utilisateur devait installer un plugin plus tard qui a créé un menu de niveau supérieur supplémentaire avec quelques sous-niveaux à l'intérieur (comme une solution de commerce électronique), est-ce que cela effectuer la clé du tableau et freiner ce qu'il a été prévu de faire?
user1752759
1
@Rob A effectué un léger ajustement qui devrait aider à éviter les situations où les éléments de menu se remplacent.
Adam
@ user1752759 Qu'est-ce que cela a à voir avec ce qui précède? Quel est le chemin d'accès complet au fichier functions.php que vous fournissez dans votre commentaire ci-dessus? Quel est le code dans ce fichier? À la dernière conversation, cela a fonctionné pour vous. Ça marche aussi pour moi. Donc, je soupçonne que quelque chose d'autre peut manquer dans votre code, si je me souviens bien la dernière fois que vous avez dupliqué deux extraits de code et que vous n'aviez pas les accolades correctes autour de votre fonction.
Adam
Merci de m'avoir recontacté @userabuser. J'ai copié-collé votre script mis à jour et il semble déplacer les éléments vers le haut et vers le bas de la liste sans remplacer les autres ... cependant, avec la nouvelle mise à jour, je reçois toujours quelques erreurs dans le menu Widgets. Warning: Invalid argument supplied for foreach() in /wp-content/themes/mythemename/functions.php on line 1444 Ligne 1444: foreach ($submenu[$menus] as $index => $value){ et Warning: ksort() expects parameter 1 to be array, null given in /wp-content/themes/mythemename/functions.php on line 1468 ligne 1468: ksort($submenu[$menus]);
user1752759
Si vous pouviez jeter un œil à cela, ce serait formidable.
user1752759
2

Le menu admin (et ses problèmes)

Comme le menu d'administration manque sérieusement de crochets et d'une API publique (qui permet de déplacer les éléments), vous devez utiliser certaines solutions de contournement. La réponse suivante vous montre ce qui vous attend dans le futur et comment vous pouvez contourner tant que nous avons l'état de base actuel.

Je dois d'abord noter que scribu travaille sur un correctif du menu d'administration qui devrait faciliter la manipulation. La structure actuelle est assez foirée et j'ai écrit un article à ce sujet qui sera bientôt dépassé. Attendez-vous à ce que WP 3.6 change complètement les choses.

Ensuite, il y a aussi le point, que vous ne devriez plus utiliser les pages Options pour les thèmes. Il y a - de nos jours - le »Theme Customizer« pour ça.

Le plugin

J'ai écrit un plugin qui teste cela avec la page "Options de thème" par défaut pour la page d'options TwentyEleven / Ten. Comme vous pouvez le voir, il n'y a pas de véritable API qui autorise n'importe quelle position. Nous devons donc intercepter le global.

En bref: suivez simplement les commentaires et jetez un œil aux avis de l'administrateur, que j'ai ajoutés pour vous donner une sortie de débogage.

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

Bonne chance et amusez-vous bien.

kaiser
la source
2

Filtres personnalisés

Il existe une autre possibilité d'y parvenir. Ne me demandez pas pourquoi je n'y ai pas pensé plus tôt. Quoi qu'il en soit, il existe un filtre dédié à un ordre de menu personnalisé. Réglez-le simplement sur truepour autoriser une commande personnalisée. Ensuite, vous avez obtenu un deuxième crochet pour commander les éléments du menu principal. Là-bas, nous interceptons simplement global $submenuet basculons autour de nos éléments de sous-menu.

entrez la description de l'image ici

Cet exemple déplace l' élément Menus au - dessus de l' élément Widgets pour montrer sa fonctionnalité. Vous pouvez l'adapter à ce que vous aimez.

<?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;
}
kaiser
la source
Je ne suis pas très confiant en ce qui concerne l'utilisation de PHP @kaiser, mais sauriez-vous peut-être un moyen d'implémenter le script ci-dessus pour inclure plusieurs éléments dans le même function wpse70916_custom_submenu_order( $menu )pour dire, réorganiser non seulement le menu , mais aussi le thème Options , widgets , éditeur, etc., ce qui le rend assez flexible et aussi pour que les éléments ne se remplacent pas? Je vous remercie.
user1752759
@ user1752759 Le plugin a déjà cette flexibilité. La sécurité des conflits (éviter de passer outre) est un autre problème. Cela ne sera pas possible dans un scénario à 100% car vous ne pouvez pas attribuer votre action en dernier. Il y a toujours quelque chose qui peut fonctionner plus tard. Quoi qu'il en soit: veuillez ouvrir une nouvelle question et créer un lien vers celle-ci.
kaiser
merci et fera kaiser. si ce n'est pas trop demander, pourriez-vous mettre à jour le script ci-dessus pour montrer comment plusieurs éléments sont effectués (par exemple, le menu et les widgets ), que je devrais pouvoir utiliser comme guide pour faire la même chose avec d'autres éléments? Étant assez nouveau en PHP, je ne pense pas que je le fais correctement, peut-être à cause des chiffres. cheers
user1752759
Veuillez simplement poser une nouvelle question et créer un lien vers celle-ci. Merci.
kaiser