Wordpress API Menu / Submenu Order

11

Tworzę motyw potomny za pomocą Wordpress 3.4.2 i wersji programistycznej Options Framework autorstwa David Price . To jest mój pierwszy motyw i jestem stosunkowo nowy, więc zapoznałem się z Kodeksem Wordpress i sprawdziłem rejestrację elementów w API.

Bez ingerencji w jakiekolwiek pliki zewnętrzne poza moim motywem zastanawiałem się, czy istnieje sposób, aby zmienić położenie strony Opcje motywu w hierarchii menu Wygląd - więc kiedy mój motyw jest aktywowany, pozycja nie jest podobna pierwszy obraz, ale jak drugi.

staryNowy

Wiem, że możesz utworzyć menu (takie jak karta Wygląd , wtyczki , użytkownicy itp.) Lub podmenu ( motywy , widżety , menu itp.), Ale jak bym poszedł o ustawianiu podmenu, powiedz, drugi z góry?

Z tego, co zbieram, gdzieś jest wywołane zamówienie i inne dodatkowe strony w functions.php po nim umieszczane są pliku?

W moim pliku 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';
}

Dzięki.

użytkownik1752759
źródło
Czy wypróbowałeś zaktualizowaną funkcję?
Adam
Dzięki, że wróciłeś do mnie @userabuser. Skopiowałem twój zaktualizowany skrypt i wydaje się, że przesuwa elementy w górę i w dół listy bez przesłonięcia innych ... jednak w nowej aktualizacji wciąż pojawia się kilka błędów w menu Widżetów . Warning: Invalid argument supplied for foreach() in /wp-content/themes/mythemename/functions.php on line 1444 Linia 1444: foreach ($submenu[$menus] as $index => $value){ i Warning: ksort() expects parameter 1 to be array, null given in /wp-content/themes/mythemename/functions.php on line 1468 Linia 1468: ksort($submenu[$menus]);
użytkownik1752759
Gdybyś mógł to rzucić okiem, byłoby świetnie.
user1752759,

Odpowiedzi:

3

Oto przykład;

Najpierw ustal kolejność elementów podmenu na podstawie klucza tablicy, którą możesz wykonać var_dump globalnej zmiennej podmenu $, która wyświetli następujące;

(Korzystam z menu Postów i podmenu jako przykładu)

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

Widzimy, że mój element podmenu jest dodawany do tablicy za pomocą klucza 17 po elementach domyślnych.

Jeśli na przykład chcę dodać element podmenu, bezpośrednio po Wszystkich postach elemencie podmenu muszę to zrobić, ustawiając klawisz tablicy na 6, 7, 8 lub 9 (odpowiednio po 5 i przed 10).

Tak to się robi...

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

}

Wynik,

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

... spróbuj i daj nam znać, jak idziesz!

Aktualizacja 1:

Dodaj to do pliku 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]);

}

Moja aktualizacja zawiera nieco łatwiejszy sposób obsługi ustawień pozycji menu, wystarczy podać nazwę strony podmenu i żądaną pozycję w menu. Jeśli jednak wybierzesz stronę podmenu $locationrówną stronie istniejącego klucza, zastąpi on ten klucz twoją, dlatego element menu zniknie, a element menu zostanie zastąpiony. W takim przypadku zwiększ lub zmniejsz numer, aby poprawnie zamówić menu. Podobnie, jeśli ktoś zainstaluje wtyczkę, która działa na ten sam obszar menu i dla którego ma to samo, $locationco element podmenu, wystąpi ten sam problem. Aby to obejść, przykład Kaisera zapewnia podstawowe sprawdzenie tego.

Aktualizacja 2:

Dodałem dodatkowy blok kodu, który sprawdza wszystkie istniejące klucze w tablicy względem naszych pożądanych, $locationa jeśli zostanie znalezione dopasowanie, zwiększymy naszą $locationwartość 1, aby uniknąć wzajemnego zastępowania się elementów menu. To jest kod odpowiedzialny za to,

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

Aktualizacja 3: (poprawiono skrypt, aby umożliwić sortowanie wielu pozycji podmenu)

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;

}

W powyższym przykładzie możesz kierować reklamy na wiele podmenu i wiele pozycji na podmenu, ustawiając odpowiednio parametry w $target_menuzmiennej, która zawiera wielowymiarową tablicę wartości.

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

Ta poprawka zapobiegnie wzajemnemu nadpisywaniu się elementów podmenu, jeśli mają one ten sam klucz (pozycję), ponieważ będzie on przechodził, aż znajdzie dostępny klucz (pozycja), który nie istnieje.

Adam
źródło
Dzięki za szybką odpowiedź userabuser, ale jestem całkiem nowy w tym wszystkim, więc proszę o wyrozumiałość. Nie jestem do końca pewien, jak zaimplementować powyższy skrypt / kod i w którym pliku należy go umieścić ze względu na zwięzłość jego napisania - proszę o rozwinięcie. Ten przykład działa i wyświetla wymaganą liczbę ... jeśli użytkownik miałby później zainstalować wtyczkę, która utworzyła dodatkowe menu najwyższego poziomu z kilkoma poziomami wewnętrznymi (np. Rozwiązaniem e-commerce), czy to wpłynąć na klawisz tablicy i zahamować, co zostało określone?
user1752759,
1
@Rob Wprowadzono niewielką korektę, która powinna pomóc w sytuacjach, w których elementy menu się zastępują.
Adam
@ user1752759 Co to ma wspólnego z powyższym? Jaką pełną ścieżkę do pliku functions.php podajesz w powyższym komentarzu? Jaki jest kod w tym pliku? W ostatniej rozmowie to zadziałało. To też działa dla mnie. Podejrzewam więc, że coś innego może być brakiem w twoim kodzie, jeśli dobrze pamiętam, kiedy ostatni raz zduplikowałeś dwa fragmenty kodu i nie posiadałeś odpowiednich nawiasów klamrowych wokół twojej funkcji.
Adam,
Dzięki, że wróciłeś do mnie @userabuser. Skopiowałem twój zaktualizowany skrypt i wydaje się, że przesuwa elementy w górę i w dół listy bez przesłonięcia innych ... jednak w nowej aktualizacji wciąż pojawia się kilka błędów w menu Widżetów. Warning: Invalid argument supplied for foreach() in /wp-content/themes/mythemename/functions.php on line 1444 Linia 1444: foreach ($submenu[$menus] as $index => $value){ i Warning: ksort() expects parameter 1 to be array, null given in /wp-content/themes/mythemename/functions.php on line 1468 Linia 1468: ksort($submenu[$menus]);
użytkownik1752759
Gdybyś mógł to rzucić okiem, byłoby świetnie.
user1752759,
2

Menu administratora (i jego problemy)

Ponieważ w menu administratora poważnie brakuje jakichkolwiek haczyków i publicznego interfejsu API (które umożliwiają przenoszenie elementów), musisz skorzystać z kilku obejść. Poniższa odpowiedź pokazuje, co czeka na Ciebie w przyszłości i jak możesz się obejść, o ile mamy obecny stan podstawowy.

Najpierw muszę zauważyć, że scribu pracuje nad łatką do menu administratora, która powinna znacznie ułatwić obsługę. Obecna struktura jest dość popsuta i napisałem o niej artykuł, który wkrótce będzie przestarzały. Spodziewaj się, że WP 3.6 całkowicie zmieni rzeczy.

Jest też kwestia, że ​​nie powinieneś już używać stron Opcje do motywów. Do tego celu służy obecnie „Theme Customizer” .

Wtyczka

Napisałem wtyczkę, która testuje to z domyślną stroną „Opcje motywu” dla strony TwentyEleven / Ten options. Jak widać, nie ma prawdziwego interfejsu API, który pozwalałby na dowolne pozycje. Musimy więc przechwycić globalne.

W skrócie: wystarczy postępować zgodnie z komentarzami i rzucić okiem na powiadomienia administratora, które dodałem, aby dać ci jakieś wyniki debugowania.

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

Powodzenia i miłej zabawy.

kajzer
źródło
2

Niestandardowe filtry

Istnieje inna możliwość osiągnięcia tego. Nie pytaj mnie, dlaczego wcześniej o tym nie myślałem. W każdym razie istnieje filtr dedykowany do niestandardowej kolejności menu. Po prostu ustaw, trueaby zezwolić na niestandardowe zamówienie. Następnie masz drugi hak, aby zamówić pozycje w menu głównym. Tam po prostu przechwytujemy global $submenui przełączamy nasze pozycje podmenu.

wprowadź opis zdjęcia tutaj

Przykład ten przesuwa element dietetyczne powyżej te widgety pozycji wykazać jego funkcjonalność. Możesz dostosować to, co chcesz.

<?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;
}
kajzer
źródło
Nie jestem zbyt pewny, jeśli chodzi o użycie PHP @kaiser, ale czy mógłbyś wiedzieć o sposobie implementacji powyższego skryptu, aby uwzględnić wiele elementów w tym samym function wpse70916_custom_submenu_order( $menu )powiedzeniu, zmienić kolejność nie tylko Menu , ale także Motywu Opcje , widżety , edytor itp. Czynią go dość elastycznym, a także, aby elementy się nie zastępowały? Dziękuję Ci.
user1752759,
@ user1752759 Wtyczka ma już tę elastyczność. Kolejnym problemem jest bezpieczeństwo konfliktów (unikanie nadpisywania). Nie będzie to możliwe w scenariuszu 100%, ponieważ nie możesz przypisać swojej akcji na końcu. Zawsze jest coś, co można uruchomić później. W każdym razie: Proszę otworzyć nowe pytanie i link do tego.
kaiser
dziękuję i zrobię kaiser. jeśli nie ma zbyt wiele pytań, czy możesz zaktualizować powyższy skrypt, aby pokazać, w jaki sposób wykonuje się wiele elementów (np. menu i widżety ), których powinienem być w stanie użyć jako przewodnika, aby zrobić to samo z innymi elementami? Będąc dość nowym w PHP, nie sądzę, że robię to poprawnie, być może z powodu liczb. na zdrowie
użytkownik1752759
Proszę tylko zadać nowe pytanie i link do tego. Dzięki.
kaiser