Zoptymalizowane menu wordpressa – przerabiamy klasę Walker_Nav_Menu
Menu na stronie generowane przez wordpress posiada wiele elementów, które nie zawsze są nam do szczęścia potrzebne, choćby klasy w każdym elemencie. Ale to co jest piękne właśnie w tym cms to możliwość ingerowania w kod bez zmiany plików źródłowych. Chciałbym się podzielić moją wiedzą na temat generowania czyściutkiego menu z kodem okrojonym do minimum.
Ale zacznijmy od przykładu bo nic tak nie kształci jak zajęcia praktyczne. Na potrzeby tego wpisu przygotowałem teoretycznie proste menu o strukturze:
- Menu 1
- Menu 2
- Submenu 1
- Submenu 2
Ale, żeby nie było tak prosto wypełniłem wszędzie pola z atrybutami, klasami i opisem.
Jeśli ktoś nie pamięta (menu nie robi się codziennie) lub jeszcze nie wie to przypominam. Żeby „dobrać się” do dodatkowych opcji w menu należy u góry ekranu podczas tworzenia menu rozwinąć zakładkę Opcje ekranu i tam wszystko mamy.
Skoro mamy utworzone menu to zobaczmy jak ono prezentuje się na ekranie i w kodzie. Oczywiście „phpowcy level hard” mogą pominąć ten infantylny wstępniak a „instalatorzy wtyczek” mogą pominąć dalszą część.
Nasze proste menu na ekranie prezentuje się tak:
Oczywiście wygląd menu zależy od tego jakiego tematu używamy, ale to co kryje się pod warstwą wizualną czyli w kodzie html jest generowane przez funkcję wp_nav_menu i będzie wyglądało dość podobnie dla większości tematów. No to zobaczmy co kryje się za tak banalnym widokiem:
<div class="menu-menu-przykladowe-container"> <ul id="menu-menu-przykladowe" class="menu"> <li id="menu-item-4" class="klasa_menu_1 menu-item menu-item-type-custom menu-item-object-custom menu-item-4"><a title="tytuł menu 1" target="_blank" href="http://menu1">Menu1</a></li> <li id="menu-item-5" class="klasa_menu_2 menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-5"><a title="tytuł menu 2" href="http://menu2">Menu2</a> <ul class="sub-menu"> <li id="menu-item-6" class="klasa_submenu_1 menu-item menu-item-type-custom menu-item-object-custom menu-item-6"><a title="tytuł submenu 1" href="http://submenu1">Submenu1</a></li> <li id="menu-item-7" class="klasa_submenu_2 menu-item menu-item-type-custom menu-item-object-custom menu-item-7"><a title="tytuł submenu 2" href="http://submenu2">Submenu2</a></li> </ul> </li> </ul> </div>
Jak widzimy widzimy struktura listy podręcznikowa ul, li odpowiednio skonstruowane ale te wszystkie klasy i id czy naprawdę są nam niezbędne? W czasach kiedy każdy centymetr kodu ma znaczenie a struktury menu są coraz bardziej rozbudowane. Wyobraźmy sobie, że nasze menu będzie składało się z kilkudziesięciu elementów wtedy tego kodu robi się naprawdę sporo.
Nasze zadanie na dziś to poczyścić wszystko co się da, ale też wiedzieć gdzie możemy sobie coś dodać lub zostawić.
Aby zmienić strukturę nav_menu i usunąć wszystkie elementy class i id musimy nadpisać klasę Walker_Nav_Menu odpowiedzialną za generowanie menu wordpress na stronie.
Nadpisaną klasę wykorzystamy podczas osadzania kodu menu dodając w wp_nav_menu parametr 'walker’ => new wp_czyste_menu()
class wp_czyste_menu extends Walker { var $tree_type = array( 'post_type', 'taxonomy', 'custom' ); var $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' ); function display_element ($element, &$children_elements, $max_depth, $depth = 0, $args, &$output) { // sprawdzamy czy istnieje submenu i dla niego powtarzamy wykonanie funkcji z nowym ID $element->hasChildren = isset($children_elements[$element->ID]) && !empty($children_elements[$element->ID]); return parent::display_element($element, $children_elements, $max_depth, $depth, $args, $output); } function start_lvl(&$output, $depth) { $indent = str_repeat("\t", $depth); $output .= "\n$indent<ul>\n"; } function end_lvl(&$output, $depth) { $indent = str_repeat("\t", $depth); $output .= "$indent</ul>\n"; } function start_el(&$output, $item, $depth, $args) { global $wp_query; $indent = ( $depth ) ? str_repeat( "\t", $depth ) : ''; $class_names = $value = ''; $classes = empty( $item->classes ) ? array() : (array) $item->classes; $classes = in_array( 'current-menu-item', $classes ) ? array( 'current-menu-item' ) : array(); $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) ); $class_names = strlen( trim( $class_names ) ) > 0 ? ' class="' . esc_attr( $class_names ) . '"' : ''; $output .= $indent . '<li>'; $attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : ''; $attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : ''; $attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : ''; $attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : ''; $item_output = $args->before; if($args->walker->has_children) { $item_output .= '<span class="menu-arrow"></span>'; } $item_output .= '<a'. $attributes .'>'; $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after; $item_output .= '</a>'; $item_output .= $args->after; $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args ); } function end_el(&$output, $item, $depth) { $output .= "</li>\n"; } }
Teraz naszą klasę możemy wykorzystać podczas tworzenia menu. Kod zazwyczaj umieszczamy w pliku header.php naszego tematu.
wp_nav_menu(array('items_wrap'=> '<nav role="navigation"><ul>%3$s</ul></nav>', 'walker' => new wp_czysty_navwalker(), 'container'=>false, 'menu_class' => '', 'theme_location'=>'primary', 'fallback_cb'=>false ));
Po zastosowaniu naszego walkera kod html menu wygląda tak:
<nav role="navigation"> <ul> <li><a title="tytuł menu 1" target="_blank" href="http://menu1">Menu1</a></li> <li><a title="tytuł menu 2" href="http://menu2">Menu2</a> <ul> <li><a title="tytuł submenu 1" href="http://submenu1">Submenu1</a></li> <li><a title="tytuł submenu 2" href="http://submenu2">Submenu2</a></li> </ul> </li> </ul></nav>
Jak widać udało nam się wyczyścić wszystkie zbędne elementy i dodatkowo umieściliśmy nasze menu w prawidłowym pojemniku nav zamiast div.