Wielkie wyzwanie menu administracyjnego WordPress z stycznia 2011 r. (Inaczej Jak rozwiązać niektóre problemy podczas modyfikowania systemu menu administracyjnego WordPress?)

14

To pytanie jest nieco wyjątkowe.

Jest to po części „wyzwanie”, które wysyłam do zespołu WordPress ( lub kogokolwiek innego ) związanego z biletami trac: # 16048 , # 16050 i # 16204 .

Cel

Celem jest obejście trzech (3) problemów przedstawionych na poniższym zrzucie ekranu podczas próby modyfikacji sekcji menu WordPress Admin:

  1. Uzyskaj stronę podmenu „Microsite”, która zostanie podświetlona podczas edytowania adwokata (w tym celu musimy jakoś móc zastosować „prąd” do pozycji podmenu, _ i niektóre zaczepy w funkcji _wp_menu_output () zapewniłyby to, co jest potrzebne tutaj) ,

  2. Uzyskaj link do strony menu adwokata, do którego prowadzi link /wp-admin/edit.php?post_type=attorneypodczas edytowania adwokata (i te same potrzebne zaczepy w funkcji _wp_menu_output () mogłyby to obsłużyć) , i

  3. Uzyskaj link „Mikrostrona”, aby nie powodować błędu „Nie masz wystarczających uprawnień, aby uzyskać dostęp do tej strony” * (jest to najgorszy sposób na rozwiązanie, a haczyk na wartości zwrotnejuser_can_access_admin_page() może poradzić sobie z tym problemem).

Zrzut ekranu przedstawiający Wielkie Wyzwanie menu administracyjnego WordPress z stycznia 2011 r
(źródło: mikeschinkel.com )

Więcej niż mój przypadek użycia

Te trzy (3) problemy dotyczą mojego przypadku użycia, ale są symboliczne dla problemów związanych z konfiguracją menu administratora w WordPress.

Kilku członków zespołu WordPress stwierdziło, że jest to łatwe i sugerowało, że coś pominąłem (co może być słuszne), ale patrzyłem na ten problem od tygodni i nie zastanawiałem się, jak go obejść, więc utworzyłem wtyczkę, którą widzisz poniżej ( również do pobrania z Gist ) jako najprostszy przykładowy przykład problemów. Wprowadzony kod admin_menu2()jest dość hackerski, ale to prawie wszystko, co jest wymagane do zmodyfikowania menu administratora w WordPress.

Pamiętaj, że nie próbowałem korzystać z nowych remove_menu_page()ani nowych remove_submenu_page()funkcji w wersji 3.1, ponieważ utworzenie wtyczki zajęłoby więcej czasu - miałem już kod admin_menu2()z istniejącego projektu - i nie sądzę, aby rozwiązały problem problem i tak.

Czego potrzebuję?

Potrzebuję jednej z dwóch (2) rzeczy:

  1. Rozwiązanie problemów, które ujawniam za pomocą tej wtyczki i wyjaśnię w tym pytaniu oraz na zrzucie ekranu (BTW, zdyskwalifikuję twoje rozwiązanie, jeśli użyjesz buforowania wyjścia PHP do rozwiązania dowolnej części tego) , lub

  2. Aby zespół WordPress rozpoznał, że rzeczywiście istnieje potrzeba tych haków i skłonić ich do ponownego rozważenia swojej pozycji na biletach.

Jak podejmujesz wyzwanie?

  1. Pobierz i zainstaluj nieskazitelną nową kopię WordPress 3.1 (prawdopodobnie będzie to jakakolwiek wersja) ,

  2. Pobierz, zainstaluj i aktywuj poniższą wtyczkę „The Great WordPress Admin Menu Challenge of Jan 2011” (lub pobierz wtyczkę z Gist ) , a następnie

  3. Postępuj zgodnie z instrukcjami wyświetlanymi na stronie wtyczki dla tej wtyczki (zobacz poniższy zrzut ekranu), ale w zasadzie załaduj zrzut ekranu, który widzisz powyżej, a następnie spróbuj dowiedzieć się o trzech (3) opisanych problemach:

Zrzut ekranu instrukcji wtyczki „The Great WordPress Admin Menu Challenge of Jan 2011”
(źródło: mikeschinkel.com )

One Ray of Hope

Na szczęście Andrew Nacin z zespołu WordPress zaoferował, że przyjrzy się temu, gdy go koduję , więc przede wszystkim piszę tutaj, aby mógł recenzować i komentować, a także mieć innych do komentowania. Wiem, że jest zajęty, ale mam nadzieję, że on (lub nawet ty) może poświęcić trochę czasu na zainstalowanie tej wtyczki na nieskazitelnej instalacji wersji 3.1 i sprawdzić, czy uda mu się rozwiązać problem.

Jeśli się zgodzisz, wyzwanie jest niemożliwe?

Jeśli po wypróbowaniu tego wyzwania dojdziesz do tego samego wniosku co ja i jeśli chcesz, aby menu administratora WordPress było bardziej konfigurowalne, skomentuj bilety trac ( # 16048 - # 16050 - # 16204 ) i głosuj na to pytanie poprzeć to.

Z przyjemnością przyznam, że coś mi umknęło

Oczywiście jest możliwe, że mógłbym być w tym całkowicie martwy i ktoś mógłby dokładnie wskazać, jak to zrobić. Naprawdę mam nadzieję, że tak się stanie; Wolę się mylić i sprawić, by to działało, a nie odwrotnie.

A oto wtyczka

Możesz także pobrać, jeśli z Gist :

<?php
/*
Plugin Name: The Great WordPress Admin Menu Challenge of Jan 2011
Description: <em>"The Great WordPress Admin Menu Challenge of Jan 2011"</em> was inspired by the WordPress team's apparent lack of understanding of the problems addressed by trac tickets <a href="http://core.trac.wordpress.org/ticket/16048">#16048</a> and <a href="http://core.trac.wordpress.org/ticket/16050">#16050</a> <em>(See also: <a href="http://core.trac.wordpress.org/ticket/16204">#16204</a>)</em> and suggestion that the <a href="http://wordpress.org/extend/plugins/admin-menu-editor/>Admin Menu Editor</a> plugin handles the use-cases that the tickets address. Debate spilled over onto Twitter with participation from <a href="http://twitter.com/nacin">@nacin</a>, <a href="http://twitter.com/aaronjorbin">@aaronjorbin</a>, <a href="http://twitter.com/petemall">@petemall</a>, <a href="http://twitter.com/westi">@westi</a>, <a href="http://twitter.com/janeforshort">@janeforshort</a>, <a href="http://twitter.com/PatchesWelcome">@PatchesWelcome</a>; supportive comments from <a href="http://twitter.com/ramsey">@ramsey</a>, <a href="http://twitter.com/brianlayman">@brianlayman</a>, <a href="http://twitter.com/TheLeggett">@TheLeggett</a>, a retweeting of @nacin's simple yet <em>(AFAICT)</em> insufficient solution by <a href="http://twitter.com/vbakaitis">@vbakaitis</a>, <a href="http://twitter.com/Viper007Bond">@Viper007Bond</a>, <a href="http://twitter.com/nickopris">@nickopris</a>, <a href="http://twitter.com/Trademark">@Trademark</a>, <a href="http://twitter.com/favstar_pop">@favstar_pop</a>, <a href="http://twitter.com/designsimply">@designsimply</a>, <a href="http://twitter.com/darylkoop">@darylkoop</a>, <a href="http://twitter.com/iamjohnford">@iamjohnford</a>, <a href="http://twitter.com/markjaquith">@markjaquith</a>, <a href="http://twitter.com/JohnJamesJacoby">@JohnJamesJacoby</a> and <a href="http://twitter.com/dd32">@dd32</a>. Also see <a href="http://andrewnacin.com/2010/12/20/better-admin-menu-controls-custom-post-types-wordpress-3-1/#comment-6360">comments</a> on @nacin's blog post entitled "<em>Better admin menu handling for post types in WordPress 3.1</em>." <strong>The desired goal of the <em>"challenge"</em></strong> is to simply either to find a solution that has eluded me or, to get those who are dismissing it as solvable without added hooks in WordPress to have a tangible example to explore in hopes they will recognize that there is indeed a need for at least some of the requested hooks. <strong>There are three (3) steps to the challenge:</strong> 1.) Get the "Microsite" submenu page to be highlighted when editing an Attorney, 2.) Get the Attorney Menu Page link to link <a href="/wordpress//wp-admin/edit.php?post_type=attorney">here</a>  when editing an Attorney, and 3.) Get the "Microsite" link not to trigger a "You do not have sufficient permissions to access this page" error.  Here is <a href="https://mikeschinkel.com/websnaps/skitched-20110114-235302.png" target="_blank"><strong>a screenshot</strong> that attempts to illustrate the callenge</a>. The code can be found on gist <a href="https://gist.github.com/780709"><strong>here</strong></a>. Activate it as a plugin in a WordPress 3.1 install and go <a href="/wordpress//wp-admin/post.php?post=10&action=edit"><strong>here</strong></a> to see what the screenshot illustrates. <strong>Be sure to load the <a href="https://mikeschinkel.com/websnaps/skitched-20110114-235302.png" target="_blank">screenshot</a> in another browser tab or window first</strong>.
Author:      Mike Schinkel
Author URI:  http://about.me/mikeschinkel
Plugin URI:  https://gist.github.com/780709
*/
if (!class_exists('TheGreatWordPressAdminMenuChallenge')) {
  class TheGreatWordPressAdminMenuChallenge {
    static function on_load() {
      add_action('init',array(__CLASS__,'init'));
      add_action('admin_menu',array(__CLASS__,'admin_menu1'));      // Simulates generic "Microsite" plugin
      add_action('admin_menu',array(__CLASS__,'admin_menu2'),100);  // Simulates website-specific plugin
      add_action('post_row_actions',array(__CLASS__,'post_row_actions'),10,2);
    }
    static function post_row_actions($actions,$post) {
      $url = admin_url(self::this_microsite_url($post->ID));
      $actions = array_merge(array('microsite'=>"<a href=\"{$url}\" title=\"Manage this Microsite\">Microsite</a>"),$actions);
      return $actions;
    }
    static function the_microsite_editor() {
      echo "We are in the Microsite Editor for " . self::post_title();
    }
    static function admin_menu1() {
      if (self::this_post_id() && in_array(self::this_post_type(),array('attorney','practice_area'))) {
        add_submenu_page(
          self::this_parent_slug(),
          self::microsite_page_title(),
          self::microsite_page_title(),
          $capability = 'edit_posts',
          'microsite',
          array($microsite,'the_microsite_editor')
        );
        global $wp_post_types;
        $parent_type_meta = $wp_post_types[self::this_post_type()];
        global $menu;
        $slug = false;
        foreach($menu as $index => $menu_page)
          if ($menu_page[0]===$parent_type_meta->label) {
            $slug = $menu_page[2];
            break;
          }
        if ($slug) {
          global $pagenow;
          global $submenu;
          // Setting this makes gives the link to the microsite in the menu the highlight for "current" menu option
          global $submenu_file;
          $submenu_file = self::this_microsite_url();
          $index = end(array_keys($submenu[$slug]));
          $submenu[$slug][$index][12] = $submenu_file;
        }
      }
    }
    static function this_parent_slug() {
      return "edit.php?post_type=" . self::this_post_type();
    }
    static function post_title() {
      $post_id = self::this_post_id();
      return ($post_id ? get_post($post_id)->post_title : false);
    }
    static function microsite_page_title() {
      return 'Microsite for ' . self::post_title();
    }
    static function this_post_type($get_post=true) {
      $post_type = (isset($_GET['post_type']) ? $_GET['post_type'] : false);
      if (!$post_type && $get_post) {
        $post_id = self::this_post_id();
        $post_type = get_post($post_id)->post_type;
      }
      return $post_type;
    }
    static function this_post_id() {
      $post_id = false;
      $post_type = self::this_post_type(false);
      if (isset($_GET[$post_type]))
        $post_id = intval($_GET[$post_type]);
      else if (isset($_GET['post']))
        $post_id = intval($_GET['post']);
      return $post_id;
    }
    static function this_microsite_url($post_id=false) {
      $post_type = self::this_post_type();
      $post_id = $post_id ? intval($post_id) : self::this_post_id();
      return "edit.php?post_type={$post_type}&page=microsite&attorney={$post_id}";
    }
    static function admin_menu2() {
      // The code required for this is super, nasty, ugly and shouldn't be, but at least it *is* doable
      global $menu;
      global $submenu;
      global $microsite;

      $parent_type = self::this_post_type();
      foreach(array('attorney','practice_area') as $post_type) {
        $slug = "edit.php?post_type={$post_type}";
        if ($post_type==$parent_type) {  // If a microsite remove everything except the microsite editor
          $microsite_url = self::this_microsite_url();
          foreach($submenu[$slug] as $submenu_index => $submenu_page) {
            if ($submenu_page[2]!=$microsite_url) {
              unset($submenu[$slug][$submenu_index]);
            }
          }
        } else {
          $submenu[$slug] = array();
        }
      }

       // Remove the Submenus for each menu
      unset($submenu['index.php']);
      unset($submenu['edit.php?post_type=article']);
      unset($submenu['edit.php?post_type=event']);
      unset($submenu['edit.php?post_type=case_study']);
      unset($submenu['edit.php?post_type=news_item']);
      unset($submenu['edit.php?post_type=transaction']);
      unset($submenu['edit.php?post_type=page']);
      unset($submenu['upload.php']);

      unset($submenu['users.php'][13]); // Removed the "Add New"

      $remove = array_flip(array(
        'edit.php',
        'link-manager.php',
        'edit-comments.php',
        'edit.php?post_type=microsite-page',
      ));
      if (!current_user_can('manage_tools'))
        $remove['tools.php'] = count($remove);

      foreach($menu as $index => $menu_page) {
        if (isset($remove[$menu_page[2]])) {
          unset($submenu[$menu_page[2]]);
          unset($menu[$index]);
        }
      }

      $move = array(
        'edit.php?post_type=page' => array( 'move-to' => 35,  0 => 'Other Pages' ),
        'separator2' => array( 'move-to' => 40 ),
        'upload.php' => array( 'move-to' => 50, 0 => 'Media Library' ),
      );
      $add = array();
      foreach($menu as $index => $menu_page) {
        if (isset($move[$menu_page[2]])) {
          foreach($move[$menu_page[2]] as $value_index => $value) {
            if ($value_index==='move-to') {
              $move_to = $value;
            } else {
              $menu_page[$value_index] = $value;
            }
          }
          $add[$move_to] = $menu_page;
          unset($menu[$index]);
        }
      }
      foreach($add as $index => $value)
        $menu[$index] = $value;

      add_menu_page(
        'Attorney Positions',
        'Attorney Positions',
        'edit_posts',
        'edit-tags.php?taxonomy=attorney-position&amp;post_type=attorney',
        false,
        false,
        55);

      ksort($menu); // Need to sort or it doesn't come out right.
    }
    static function init() {
      register_post_type('attorney',array(
        'label'           => 'Attorneys',
        'public'          => true,
      ));
      register_post_type('practice_area',array(
        'label'           => 'Practice Areas',
        'public'          => true,
      ));
      register_taxonomy('attorney-position','attorney',array(
        'label'=>'Attorney Positions',
      ));
      register_post_type('article',array(
        'label'           => 'Articles & Presentations',
        'public'          => true,
      ));
      register_post_type('case_study',array(
        'label'           => 'Case Studies',
        'public'          => true,
      ));
      register_post_type('news_item',array(
        'label'           => 'Firm News',
        'public'          => true,
      ));
      register_post_type('event',array(
        'label'           => 'Events',
        'public'          => true,
      ));
      register_post_type('transaction',array(
        'label'           => 'Transactions',
        'public'          => true,
      ));

      // Install the test data
      $post_id = 10;
      $attorney = get_post($post_id);
      if (!$attorney) {
        global $wpdb;
        $wpdb->insert($wpdb->posts,array(
          'ID' => $post_id,
          'post_title' => 'John Smith',
          'post_type' => 'attorney',
          'post_content' => 'This is a post about the Attorney John Smith.',
          'post_status' => 'publish',
          'post_author' => 1,
        ));
      }
    }
  }
  TheGreatWordPressAdminMenuChallenge::on_load();
}

Wszystkim, którzy to czytają, mam nadzieję, że możesz pomóc.

Z góry dziękuję.

MikeSchinkel
źródło
Jestem zainteresowany (i naprawdę muszę podnieść poziom doświadczenia ze stroną administracyjną), ale prawdopodobnie poczekam na ostateczną wersję 3.1. Mój lokalny stos testowy nie jest bardzo odpowiedni dla wielu wersji podstawowych, więc trzymam się stabilnej wersji.
Rarst 15.01.11
Wiem dokładnie o problemie, o którym mówisz o Mike'u, nie sądzę, żebym mógł go opisać lepiej niż ty, ale widziałem te same problemy, pisząc menu rozwijane dla administratora (dla zabawy), po prostu dodając moje +1.
t31os 17.01.11
@ t310s - Dziękujemy za dodanie +1. Prawdopodobnie zajęło mi to 2 tygodnie badań, aby móc opisać problem, więc fakt, że możesz nawet rozpoznać, że jest on istotny (i nie spędziłem 2 tygodni, które mam) oznacza, że ​​wyprzedzasz większość, w tym mnie!
MikeSchinkel

Odpowiedzi:

2

Mike, rzuciłem okiem na kod i twoją idealną skrzynkę końcową ... i niektóre z nich, szczerze mówiąc, nie są możliwe w obecnym systemie. Ponownie twoje wymagania:

  1. Uzyskaj stronę podmenu „Mikrostrona”, która zostanie wyróżniona podczas edytowania adwokata
  2. Uzyskaj link do strony menu adwokata, do którego link będzie prowadzić /wp-admin/edit.php?post_type=attorneypodczas edytowania adwokata
  3. Uzyskaj link „Mikrostrona”, aby nie powodować błędu „Nie masz wystarczających uprawnień, aby uzyskać dostęp do tej strony”

Kluczową kwestią jest tutaj # 2.

Co próbowałem

Próbowałem dodać niestandardowy typ postu dla adwokatów i natychmiast przypomniano mi, że /wp-admin/edit.php?post_type=attorneydostaniesz listę adwokatów, a nie rzeczywisty ekran edycji. Właściwa edycja odbywa się w dniu /wp-admin/post.php?post=10&action=edit. Więc jeśli jesteś naprawdę przywiązany do # 2 ... pozostałe dwa kryteria nie będą działać.

Właśnie dlatego # 3 kończy się niepowodzeniem we wdrożeniu ... a ja nawet nie byłem w stanie spróbować # 1, ponieważ nie mogłem dostać się tak daleko.

EAMann
źródło
Uwierz, że Twoja analiza jest poprawna. Przedstawiony układ jest taki, że w swoich celach miałem więcej niż jedno żądanie klienta, aby uprościć struktury menu dla ich przypadków użycia. Zaproponowałem użycie podmenu, ale im się to nie podobało; uważali, że byłoby to zbyt mylące dla ich użytkowników. Jedną rzeczą, o której mógłbym nie wspomnieć, jest to, że opracowuję produkt oparty na WordPressie do dystrybucji w porównaniu z witryną WordPress dla nich, gdzie mogę po prostu przeszkolić ich, aby umieli działać. Inną opcją jest porzucenie WordPress; nie to, co chcę, żeby zrobili.
MikeSchinkel
2

Hej Mike, twój problem nr 3 wynika z tego, że określasz ($microsite, 'the_microsite_editor'), gdzie powinien być (__CLASS__, 'the_microsite_editor').

Aktualizacja: po spędzeniu zbyt dużo czasu na próbach rozwiązania podobnych problemów dla mojej własnej wtyczki, oto coś, co może pomóc w Twoim Wyzwaniu (pamiętaj, że funkcje są metodami pod Twoją klasą):

function add_posttype_submenu_page($mytype, $label, $cap, $slug) {  
    /* we add two submenu pages to work around the 
       edit.php?post_type=...&page=...problem and have 
       our page called as admin.php?page=... instead */
    //first create a 'blind' pseudo-entry to register our page callback
    add_submenu_page($mytype, $label, $label, $cap, $slug, 
                     array( &$this, 'admin_'.$mytype ));
    //then create a real entry that 'calls' our pseudo-entry
    add_submenu_page('edit.php?post_type='.$mytype, $label, 
                     $label, $cap, 'admin.php?page='.$slug);
    /* then lets fix/hack the highlighting */
    global $plugin_page;
    global $submenu_file;
    if ($plugin_page == $slug) {
        // this next line highlights the submenu entry
        $submenu_file = 'admin.php?page='.$slug; 
        add_filter('parent_file', 
                   array(&$this, 'evil_parent_file_hack'));
    }
} 

function evil_parent_file_hack() {
    //we do this to get the parent menu properly highlighted, too
    //it only gets called on the submenu menu page in question
    global $self;
    global $parent_file;
    $self = $parent_file;
    remove_filter('parent_file', array(&$this, 'evil_parent_file_hack'));
}

Następnie wystarczy zadzwonić add_posttype_submenu_page()z odpowiednimi parametrami. To powinno poprawnie dodać pozycję podmenu do menu, które zostało automatycznie utworzone podczas register_post_type()połączenia.

wyrfel
źródło
oops ... podwójne podkreślenia wokół KLASY zostały przekształcone w odważne formatowanie ;-)
wyrfel
Naprawiłem to. :)
fuxia
Och, to jest po prostu niesamowite; dzięki! Jak mogłem przegapić ten pierwszy punkt?!? Doh!
MikeSchinkel,
Dzięki, Mike. Powrót do oryginalnego tematu ... WP wewnętrznie generuje identyfikator dla niektórych pozycji menu i przechowuje go w wartości 4 tablic menu. Takich jak zaczepy strony wtyczki. Jednak w przypadku niestandardowych typów postów przechowuje identyfikator niezgodny z formatem haka wtyczki-strony. Myślę, że wiele można by pomóc, gdyby WP uczyniło to spójnym (tj.
Stworzyło