13 sierpnia 2020

Tworzenie menu w szablonie WordPress

Kategoria: Programowanie
Tagi: WordPress
Autor: Paweł Mansfeld

W tym artykule zajmiemy się rejestracją i zaprogramowaniem menu we własnym szablonie WordPress. Aby poradnik był przydatny w wielu przypadkach, praktycznym przykładem będzie wielopoziomowe (lub jak kto woli rozwijane) menu.

Menu to tak naprawdę taki specjalny widget. Programowanie we własnym szablonie i zarządzanie z perspektywy redaktora strony bardzo przypomina korzystanie z widgetów. Jeżeli potrafisz stworzyć własny widget WordPress to ze stworzeniem własnego menu też nie będzie problemu.

Krok 1: Rejestracja menu

Każde menu trzeba najpierw zarejestrować. Kod prezentowałem w artykule o tworzeniu motywów WordPress:

function reg_mymenu() {
  register_nav_menu("header-menu",__("Menu główne"));
}
add_action("init", "reg_mymenu");

Taki kod możemy (a nawet powinno się) dodać do pliku functions.php.

Krok 2: Utworzenie menu

Jeżeli wszystko jest OK, po odświeżeniu panelu, w grupie „Wygląd” pojawi się nowa strona „Menu”.

Panel do zarządzania menu

Możemy tutaj dodać podstrony, poszczególne wpisy lub linki zewnętrzne. Jak widać edycja menu jest bardzo wygodna – za pomocą interakcji „przeciągnij i upuść” można zmieniać kolejność elementów a dodawanie i usuwanie ich działa asynchronicznie – bez odświeżania strony panelu.

Podsumowując, rejestracja co najmniej jednego menu pozwala uzyskać dostęp do strony z tymi ustawieniami a po kliknięciu w „Utwórz menu” będziemy mogli przypisać stworzone menu do zarejestrowanych i nazwanych obiektów:

Wybór miejsca wyświetlania utworzonego menu.

Krok 3: Wyświetlanie menu w szablonie

Teraz musimy w szablonie wywołać funkcję drukującą menu. WordPress posiada wewnętrzną funkcję do realizacji tego celu:

wp_nav_menu(array("theme_location" => "header-menu"));

Taka funkcja umieszczona gdziekolwiek w szablonie wygeneruje nam gotowy kod HTML menu:

<div class="menu-menu-1-container">
   <ul id="menu-menu-1" class="menu">
      <li id="menu-item-204" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-home current-menu-item page_item page-item-17 current_page_item menu-item-204">
         <a href="http://localhost/" aria-current="page">Strona główna</a>
      </li>
      <li id="menu-item-205" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-205">
         <a href="http://localhost/blog/">Blog</a>
      </li>
      <li id="menu-item-206" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-206">
         <a href="http://localhost/kontakt/">Kontakt</a>
      </li>
      <li id="menu-item-208" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-208">
         <a href="http://localhost/oferta/">Oferta</a>
      </li>
   </ul>
</div>

Na tym możemy zakończyć oficjalną część tutorialu.

Zaawansowane programowanie menu WordPress

Za pomocą argumentów możemy dodawać klasy, otaczać elementy i linki niestandardowymi kawałkami kodu. Dla przykładu, możemy się pozbyć otaczającego diva:

wp_nav_menu(array(
   "theme_location" => "header-menu",
   "container" => ""
));

Załóżmy, że nasz szablon budujemy za pomocą Boostrapa i do głównego tagu ul chcemy dodać klasę navbar-nav. Nic prostszego:

"menu_class" => "navbar-nav"

Jak widać, funkcja umożliwia wygenerować kod według wymagań. Nie można jednak tak prostym sposobem dodać klasy do poszczególnych elementów <li>. Aby to osiągnąć mamy dwa wyjścia:

  • stworzenie własnego argumentu za pomocą filtra,
  • stworzyć własny „walker”,
  • użyć funkcji wp_get_nav_menu_object(), za pomocą której zakodujemy całe menu od podstaw

Załóżmy, że do każdego elementu <li> chcemy dodać klasę nav-item a do każdego linku <a> nav-link.

Metoda 1: Filtry

Tworzymy funkcję, która będzie nam umożliwiać dodanie dodatkowego parametru my_menu_li_class:

function my_menu_li_class($classes, $item, $args) {
   if (property_exists($args, 'my_menu_li_class')) {
      $classes[] = $args->my_menu_li_class;
   }
   return $classes;
}
add_filter('nav_menu_css_class', 'my_menu_li_class', 1, 3);

oraz my_menu_a_class:

function my_menu_a_class( $attributes, $item, $args ) {
   if (property_exists($args, 'my_menu_a_class')) {
      $attributes['class'] = $args->my_menu_a_class;
   }
   return $attributes;
}
add_filter( 'nav_menu_link_attributes', 'my_menu_a_class', 1, 3 );

Teraz dodajemy stworzone przez nas parametry do funkcji wp_nav_menu:

'my_menu_li_class' => 'nav-item',
'my_menu_a_class' => 'nav-link'

Metoda 2: Rozszerzanie klasy Walker

Poprzednia metoda wymaga od nas znajomości filtrów i każdorazowej edycji parametrów. Alternatywnym rozwiązaniem jest rozszerzenie klasy Walker. Tworzymy klasę My_Walker która dziedziczy po klasie Walker:

class My_Walker extends Walker {
   var $db_fields = array(
   'parent' => 'menu_item_parent',
   'id' => 'db_id'
);
function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
   $output .= sprintf( "\n<li class=\"nav-item\"><a class=\"nav-link\" href='%s'%s>%s</a></li>\n",
   $item->url,
   ( $item->object_id === get_the_ID() ) ? ' class="current"' : '',
   $item->title
);
}
}

Przy $output widać dodane przez nas klasy nav-item i nav-link. Teraz możemy specjalnym parametrem odnieść się do Walkera:

"walker"  => new My_Walker()

Jeżeli nie wiesz co oznacza dziedziczenie, zapraszam do kursu obiektowego PHP od podstaw.

Metoda 3: Generowanie własnego kodu

Możemy też bez wspierania się gotowymi funkcjami wygenerować cały kod dynamicznego menu. To najbardziej hardkorowa metoda, ale dająca najwięcej możliwości i zwalniająca nas z używania wbudowanych w WordPressa funkcji i filtrów, których używanie – przynajmniej według mnie – może się stać męczące.

Za pomocą funkcji wp_get_nav_menu_object oraz wp_get_nav_menu_items możemy otrzymać wszystko co jest możliwe do odczytania z obiektu menu:

$menu_name = "header-menu";
if (($locations = get_nav_menu_locations()) && isset($locations[$menu_name])) {
   $menu = wp_get_nav_menu_object($locations[$menu_name]);
   $menu_items = wp_get_nav_menu_items($menu->term_id);
   var_dump($menu_items);
}

Teraz za pomocą pętli foreach możemy iterować po elementach i generować kod HTML menu:

$html = "";
foreach ((array) $menu_items as $key => $menu_item) {
   $title = $menu_item->title;
   $url = $menu_item->url;
   $html .= <li><a href="$url">$title</a></li> 
}

Advanced Custom Fields (ACF) w Menu WordPress

Taka metoda generowania dynamicznego menu może być potrzebna w przypadku kiedy korzystamy z niestandardowych pól ACF. Załóżmy, że chcemy mieć możliwość kolorowania każdego elementu menu lub dodać do elementów menu tła graficzne – wystarczy stworzyć pole ACF, przypisać go do menu i wtedy takie wartości można otrzymać wewnątrz foreach za pomocą:

$color = get_field("color", $menu_item);

Jeżeli chcemy dodać ikony do pozycji menu, można użyć filtra zaprezentowanego w dokumentacji ACF:

function my_wp_nav_menu_icons( $items, $args ) {
   foreach( $items as &$item ) {
   $icon = get_field('icon', $item);
   if( $icon ) {
      $item->title .= ' <i class="fa fa-'.$icon.'"></i>';
   }
}
return $items;
}
add_filter('wp_nav_menu_objects', 'my_wp_nav_menu_icons', 10, 2);

Implementacja menu Bootstrap

Klasy z tego frameworka podałem jako przykład. Oczywiście, nie trzeba samemu implementować całej struktury nawigacji Bootstrapa, ponieważ w sieci są opublikowane gotowe rozszerzenia klasy Walker dla tak popularnych bibliotek.

Jedną z nich jest: https://github.com/wp-bootstrap/wp-bootstrap-navwalker

Wystarczy dodać do folderu z motywem plik class-wp-bootstrap-navwalker.php dołączyć go do functions.php

function register_navwalker(){
require_once get_template_directory() . '/class-wp-bootstrap-navwalker.php';
}
add_action( 'after_setup_theme', 'register_navwalker' );

W argumentach naszego menu dodajemy wtedy tylko:

'fallback_cb' => 'WP_Bootstrap_Navwalker::fallback',
'walker' => new WP_Bootstrap_Navwalker(),

Ukryte pola elementów menu

Na koniec jeszcze pokażę małą ciekawostkę związaną z dodatkowymi opcjami jakie możemy wykorzystać z poziomu panelu WordPress. Pozostając cały czas na podstronie Menu, w Opcjach Ekranu, które zazwyczaj można rozwinąć u góry po prawej stronie panelu możemy włączyć dodatkowe pola dla elementów menu:

Zaawansowane właściwości menu WordPress

Od teraz dla każdego elementu menu będziemy mieli do dyspozycji dodatkowe pola.

Edycja elementów menu w trybie rozszerzonym
  • Tytuł czyli atrybut title,
  • Klasę CSS, która jest dodawana do elementu li
  • Relację XFN czyli atrybut rel
  • Opis – dodatkową treść, którą można zaprezentować dla elementu menu

Podsumowanie

Jak widać w WordPressie mamy bardzo wiele narzędzi, które udostępniają praktycznie nieograniczone możliwości dostosowania kodu HTML całej struktury menu do naszych potrzeb. Dynamiczne menu, którym łatwo może zarządzać użytkownik to bardzo przydatny element strony WordPress.

Za pomocą menu i zagnieżdżania elementów możemy tworzyć najbardziej skomplikowane struktury a za pomocą wbudowanych funkcji i metod które zaprezentowałem w tym artykule, możemy dowolnie dostosowywać wygenerowany kod HTML dokładnie tak jak tego chcemy.

Źródła:

https://developer.wordpress.org/reference/functions/wp_nav_menu/

https://developer.wordpress.org/reference/functions/wp_get_nav_menu_object/

https://developer.wordpress.org/reference/functions/wp_get_nav_menu_items/

Oceń artykuł na temat: Tworzenie menu w szablonie WordPress
Średnia : 4.8 , Maksymalnie : 5 , Głosów : 5


 

Odpowiedz lub skomentuj

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *


 

Wykryto brak połączenia z Internetem.