Artykuły na każdy temat

[PHP][WordPress] Rozwijane menu

Dodano 20.04.2012r. o 18:36
Jakiś czas temu przenosiłem bloga znajomej z jakiegoś darmowego systemu na WordPress'a. Jednym z zadań było skonstruowanie menu z pewnymi założeniami. Po pierwsze poszczególne pozycje w menu powinno być ustalane według ustalonego wcześniej porządku. Niestety zwykłe wp_list_pages() tutaj nie wystarcza. Na szczęście w chwili wykonywania zadania pojawił się nowy feature o nazwie wp_nav_menu(). Problem polegał na tym, że menu miało rozwijać się kiedy ktoś był w danej kategorii i pokazywać wszystkie dzieci przy jednoczesnym schowaniu innych dzieci nie należących do danej kategorii. Niestety geniusze budujący WordPress'a nie przewidziały pewnej ewentualności. Dla wp_list_pages() oczywiście istnieje parametr exclude aczkolwiek jak wcześniej wspomniałem potrzebne jest wp_nav_menu(), które tego parametru nie posiada. Część swoich przemyśleń opisałem tutaj.

W trakcie poszukiwania rozwiązania zadałem pytanie na jednym z for dyskusyjnych oraz o ile mnie pamięć nie myli także na forum WordPress'a. Niestety jak zwykle kiedy potrzebna jest fachowa wiedza to trzeba radzić sobie samemu. Innym przykładem takiej sytuacji jest ten wątek. Po pewnym czasie natrafiłem na półrozwiązanie. Przykład działania można zaobserwować tutaj.

W związku z nie znalezieniem dobrego rozwiązania doszedłem do wniosku, że trzeba napisać samemu mały plugin. Działanie mojego pluginu można zaobserwować tutaj oraz na stronie Moniki Zarczuk. Schemat menu na testowym WordPress'ie wygląda tak. Kod był pisany na szybko i jeżeli znajdziecie jakieś błędy lub macie jakieś sugestie to z chęcią posłucham.
Kod:
<?php
/*
Plugin Name: Fold Page Menus for wp_nav_menu()
Plugin URI:
Description:
Version: 1.0
Dated: 18 Oct 2011
Author: CapaciousCore
Author URI: http://www.capaciouscore.pl/
*/

function fold_wp_nav_menu()
{
 global $id$wpdb;

 if($id)
 {
  if(!is_page())
  {
   return wp_nav_menu(array('depth' => 1));
  }
  else
  {
   $ancestors get_ancestors($id'page');
   $parent = ($ancestors end($ancestors) : $id);
   $pages get_pages(array('post_type' => 'page'));
   $childrens get_page_children($parent$pages);

   if($childrens)
   {
    // Exceptions of major parents
    foreach($pages as $value)
    {
     if(!$value -> post_parent)
     {
      $exceptions[] = $value -> ID;
     }
    }

    // Exceptions of children
    foreach($childrens as $value)
    {
     $exceptions[] = $value -> ID// here can be a problem
    }

    return wp_nav_menu(array('exceptions' => $exceptions'walker' => new fold_wp_nav_menu()));
   }
   else
   {
    return wp_nav_menu(array('depth' => 1));
   }
  }
 }
}

class fold_wp_nav_menu extends Walker_Nav_Menu
{
 function walk($elements$max_depth)
 {
  $args array_slice(func_get_args(), 2);
  $output '';

  if($max_depth < -1//invalid parameter
   return $output;

  if(empty($elements)) //nothing to walk
   return $output;

  $id_field $this -> db_fields['id'];
  $parent_field $this -> db_fields['parent'];

  // Temporary solution Smile
  if($args[0] -> exceptions && $elements// here id not parent id
  {
   foreach($elements as $key => $value)
   {
    if(!in_array($value -> object_id$args[0] -> exceptions))
    {
     unset($elements[$key]);
    }
   }
  }

  // flat display
  if(-== $max_depth)
  {
   $empty_array = array();

   foreach ($elements as $e)
    $this -> display_element($e$empty_array10$args$output);

   return $output;
  }

  /*
   * need to display in hierarchical order
   * separate elements into two buckets: top level and children elements
   * children_elements is two dimensional array, eg.
   * children_elements[10][] contains all sub-elements whose parent is 10.
   */

  $top_level_elements = array();
  $children_elements  = array();

  foreach($elements as $e)
  {
   if(== $e -> $parent_field)
    $top_level_elements[] = $e;
   else
    $children_elements[$e -> $parent_field ][] = $e;
  }

  /*
   * when none of the elements is top level
   * assume the first one must be root of the sub elements
   */

  if(empty($top_level_elements))
  {
   $first array_slice($elements01);
   $root $first[0];
   $top_level_elements = array();
   $children_elements  = array();

   foreach($elements as $e)
   {
    if($root -> $parent_field == $e -> $parent_field)
     $top_level_elements[] = $e;
    else
     $children_elements[$e -> $parent_field ][] = $e;
   }
  }

  foreach($top_level_elements as $e)
   $this -> display_element($e$children_elements$max_depth0$args$output);

  /*
   * if we are displaying all levels, and remaining children_elements is not empty,
   * then we got orphans, which should be displayed regardless
   */

  if(($max_depth == 0) && count($children_elements) > 0)
  {
   $empty_array = array();

   foreach($children_elements as $orphans)
    foreach($orphans as $op)
     $this->display_element($op$empty_array10$args$output);
  }

  return $output;
 }
}
?>
A potem aby zobaczyć menu wystarczy odpalić:
Kod:
<?php fold_wp_nav_menu(); ?>
Banalne, prawda? Spakowany plik można ściągnąć stąd.

Komentarze

Publikowane komentarze są prywatnymi opiniami użytkowników serwisu. Serwis nie ponosi odpowiedzialności za treść opinii. W trosce o zachowanie poziomu dyskusji wszystkie komentarze podlegają akceptacji przed ich publikacją dlatego proszę cierpliwie czekać aż komentarz zostanie opublikowany.

CapaciousCore

Dodano 07.01.2014r. o 20:10
Tworzysz sobie wtyczkę z kodem z pierwszego listingu, a potem tam gdzie ma być menu używasz kodu z drugiego listingu.

5prawnatury

Dodano 07.01.2014r. o 20:01
"aby zobaczyć menu wystarczy odpalić Kod."
ale gdzie mam go "odpalić", bo się na tym kompletnie nie znam...

Dodaj komentarz

Zostaw komentarz jeżeli możesz! Nie bądź przysłowiowym botem! Nie bądź obojętny! Ciebie to nic nie kosztuje, a mi sprawi uśmiech na twarzy.
Zezwolono używać: BBCode
Zabroniono używać:
znaczników HTML

(Wymagany)

(Wymagany, niepublikowany)

(Nie wymagana)

Token:

Obrazek dla bota

(Przepisz tylko cyfry!)

(Wymagana)