Khi bạn thêm một menu vào theme trong WordPress bằng hàm register_nav_menu
và hiển thị nó bằng hàm wp_nav_menu
, WordPress sẽ áp dụng một cấu trúc mặc định cho menu. Thông thường, các menu con sẽ được bọc trong thẻ <ul> có class “sub-menu”, và mỗi mục trong menu sẽ có các class gọi một cách cụ thể.
Tuy nhiên, trong trường hợp bạn muốn sử dụng một cấu trúc menu khác (như cấu trúc menu của Bootstrap hoặc Foundation), bạn cần chỉnh sửa lại cấu trúc menu trong WordPress.
Trong bài viết này, tôi sẽ giới thiệu cho bạn về lớp Walker_Nav_Menu
trong WordPress, được sử dụng để thiết lập cấu trúc hiển thị của menu. Bằng cách tạo một lớp mới kế thừa từ lớp này, bạn có thể tùy chỉnh cấu trúc của các menu cụ thể.
Contents
Sử dụng Walker trong Menu
Để chỉ định một menu cụ thể hiển thị theo cấu trúc được thiết lập trong Walker_Nav_Menu
của bạn, bạn cần kích hoạt nó bằng cách thêm tham số “walker” vào hàm wp_nav_menu
.
$thachpham_walker = new ThachPham_Nav_Walker;
wp_nav_menu( array(
'theme_location' => 'primary',
'menu_class' => 'nav-menu',
'menu_id' => 'primary-menu',
'walker' => $thachpham_walker
) );
Ở đoạn mã trên, tôi tạo một đối tượng mới có tên là $thachpham_walker
từ lớp ThachPham_Nav_Walker
. Sau đó, tôi sử dụng đối tượng này trong tham số “walker” của hàm wp_nav_menu
.
Vậy ThachPham_Nav_Walker
là gì? Đây là một lớp bạn tạo ra bằng cách kế thừa từ lớp Walker_Nav_Menu
và thực hiện một số phương thức trừu tượng như sau:
class ThachPham_Nav_Walker extends Walker_Nav_Menu {
/**
* Phương thức start_lvl()
* Được sử dụng để hiển thị các thẻ bắt đầu cấu trúc của một cấp độ mới trong menu. (ví dụ: <ul class="sub-menu">)
* @param string $output | Sử dụng để thêm nội dung vào những gì hiển thị ra bên ngoài
* @param interger $depth | Cấp độ hiện tại của menu. Cấp độ 0 là lớn nhất.
* @param array $args | Các tham số trong hàm wp_nav_menu()
**/
public function start_lvl( &$output, $depth = 0, $args = array() ) {
}
/**
* Phương thức end_lvl()
* Được sử dụng để hiển thị đoạn kết thúc của một cấp độ mới trong menu. (ví dụ: </ul> )
* @param string $output | Sử dụng để thêm nội dung vào những gì hiển thị ra bên ngoài
* @param interger $depth | Cấp độ hiện tại của menu. Cấp độ 0 là lớn nhất.
* @param array $args | Các tham số trong hàm wp_nav_menu()
**/
public function end_lvl( &$output, $depth = 0, $args = array() ) {
}
/**
* Phương thức start_el()
* Được sử dụng để hiển thị đoạn bắt đầu của một phần tử trong menu. (ví dụ: <li id="menu-item-5"> )
* @param string $output | Sử dụng để thêm nội dung vào những gì hiển thị ra bên ngoài
* @param string $item | Dữ liệu của các phần tử trong menu
* @param interger $depth | Cấp độ hiện tại của menu. Cấp độ 0 là lớn nhất.
* @param array $args | Các tham số trong hàm wp_nav_menu()
* @param interger $id | ID của phần tử hiện tại
**/
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
}
/**
* Phương thức end_el()
* Được sử dụng để hiển thị đoạn kết thúc của một phần tử trong menu. (ví dụ: </li> )
* @param string $output | Sử dụng để thêm nội dung vào những gì hiển thị ra bên ngoài
* @param string $item | Dữ liệu của các phần tử trong menu
* @param interger $depth | Cấp độ hiện tại của menu. Cấp độ 0 là lớn nhất.
* @param array $args | Các tham số trong hàm wp_nav_menu()
* @param interger $id | ID của phần tử hiện tại
**/
public function end_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
}
} // kết thúc lớp ThachPham_Nav_Walker
Các phương thức được định nghĩa trong lớp này có ý nghĩa như sau:
start_lvl()
: Sử dụng để hiển thị các thẻ bắt đầu cấu trúc của một cấp độ mới trong menu. Ví dụ,<ul class="sub-menu">
.end_lvl()
: Sử dụng để hiển thị đoạn kết thúc của một cấp độ mới trong menu. Ví dụ,</ul>
.start_el()
: Sử dụng để hiển thị đoạn bắt đầu của một phần tử trong menu. Ví dụ,<li id="menu-item-5">
.end_el()
: Sử dụng để hiển thị đoạn kết thúc của một phần tử trong menu. Ví dụ,</li>
.
Bạn có thể xem toàn bộ mã nguồn của lớp Walker_Nav_Menu
trong tập tin /wp-includes/nav-menu-template.php
của WordPress. Chúng ta sẽ làm việc bằng cách tùy chỉnh code trong phần này mà không cần sửa đổi mã nguồn gốc, bằng cách kế thừa Walker_Nav_Menu
cho lớp ThachPham_Nav_Walker
của chúng ta.
Làm việc với start_lvl()
Như tôi đã đề cập ở trong code, phương thức start_lvl()
được sử dụng để thiết lập lại các thẻ mở đầu của một cấp độ menu mới, tính từ cấp độ menu gốc. Điều này có nghĩa là chúng ta sẽ sử dụng phương thức này để thay đổi lại cấu trúc của thẻ <ul class="sub-menu">
mặc định của WordPress cho menu con.
Ở file /wp-includes/nav-menu-template.php
, từ dòng 47 đến 50, phương thức này được định nghĩa như sau:
public function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("t", $depth);
$output .= "n$indent<ul class="sub-menu">n";
}
Đoạn trên có nghĩa là nó lặp lại chuỗi tab (ký tự t) tương ứng với giá trị của $depth
(nếu menu đó có cấp độ là 2, thì lặp lại chuỗi tab 2 lần) và đưa vào biến $indent
. Trong PHP, ký tự "t"
nghĩa là một tab (khoảng trắng trước ký tự). Sau đó, nó sử dụng biến $indent
này cho $output
để hiển thị ra ngoài bằng "n$indent"
, trong đó "n"
nghĩa là ký tự đại diện cho một hàng văn bản. Vậy ý nghĩa đoạn trên là nó in <ul class="sub-menu">
thụt vào so với phần tử trước đó, kiểu như thế này:
<li>
<ul class="sub-menu">
<li>Level 1</li>
</ul>
</li>
Khoảng trắng đằng trước thẻ <ul>
chính là tab đấy.
Ở bài này, chúng ta sẽ thực hành bằng cách thêm một thẻ <span>
đằng trước menu con. Đầu tiên, hãy viết code cho phương thức start_lvl()
trong lớp ThachPham_Nav_Walker
như sau:
public function start_lvl( &$output, $depth, $args ) {
$indent = str_repeat("t", $depth);
$output .= "<span class="sub-intro">Menu con</span>";
$output .= "n$indent<ul class="sub-menu">n";
}
Sử dụng phương thức end_el()
Phương thức end_el()
cũng tương tự như end_lvl()
, để hiển thị phần kết thúc của phần tử <li>
trong menu.
Từ dòng 187 đến 189 trong /wp-includes/nav-menu-template.php
, nó đã thiết lập sẵn như sau:
public function end_el( &$output, $item, $depth = 0, $args = array() ) {
$output .= "</li>n";
}
Ý nghĩa của nó cũng tương tự như phần end_lvl()
, chỉ khác là nó có thêm </li>
.
Sử dụng phương thức start_el()
Phương thức này có lẽ là chúng ta sẽ làm việc nhiều nhất trong Walker_Nav_Menu
, vì nó sẽ thiết lập lại cấu trúc hiển thị của các phần tử <li>
trong menu. Trước khi sử dụng, bạn cần đọc qua code của phương thức này từ dòng 81 đến 173 trong /wp-includes/nav-menu-template.php
. Và ở đây, tôi sẽ giải thích cặn kẽ ý nghĩa của các mã trong phần này của lớp gốc Walker_Nav_Menu
trong tập tin này.
Dòng số 82 ta có biến $indent
là để thiết lập các khoảng trắng với ký tự tab để nó hiển thị thẻ <li>
thụt vào (xem dòng 115).
$indent = ( $depth ) ? str_repeat( "t", $depth ) : '';
Dòng 84 và 85 nghĩa là nó sẽ lấy ID của đối tượng trong menu thông qua đối tượng dữ liệu $item->ID
và nối vào đối tượng $item->classes
để hiển thị các class HTML tượng trưng cho mỗi đối tượng trong menu (ví dụ như class “menu-item-83”), các class sau khi được nối sẽ được đưa vào biến $classes
.
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$classes[] = 'menu-item-' . $item->ID;
Kế tiếp ở dòng 98 và 99, sau khi có biến $classes
ở trên, nó tiến hành bóc tách các giá trị trong mảng $classes
để hiển thị ra các phần tử menu cách nhau một khoảng trắng. Ở đoạn này, bạn sẽ thấy có dòng apply_filters
với hook tên là nav_menu_css_class
, sau này bạn có nhu cầu sửa lại class trong menu, bạn có thể sử dụng add_filter
để lọc qua hook này.
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
Dòng 112 và 113 cũng tương tự như 98 và 99, nhưng nó thiết lập ID của từng phần tử trong menu.
$id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args, $depth );
$id = $id ? ' id="' . esc_attr( $id ) . '"' : '';
Dòng 115 là thiết lập những gì sẽ hiển thị ra bên ngoài. Ở đây bạn có thể dễ dàng hiểu là nó in một phần tử <li>
với ID và Class theo hai biến $class_names
và $id
ở trên.
$output .= $indent . '<li' . $id . $class_names .'>';
Dòng 117 đến dòng 121 nghĩa là nó sẽ đưa một số thuộc tính của mỗi phần tử danh sách trong menu vào mảng $atts
để sau đó nó sẽ dùng foreach để tách các giá trị ra để hiển thị với thẻ <a>
.
$atts = array();
$atts['title'] = ! empty( $item->attr_title ) ? $item->attr_title : '';
$atts['target'] = ! empty( $item->target ) ? $item->target : '';
$atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';
$atts['href'] = ! empty( $item->url ) ? $item->url : '';
$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );
Cuối cùng, dòng 124 đến dòng 132 sẽ hiển thị cấu trúc của phần tử nằm bên trong <li>
ra, các phần tử này được chứa trong biến $item_output
.
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
/** This filter is documented in wp-includes/post-template.php */
$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
$item_output .= '</a>';
$item_output .= !empty( $atts['description'] ) ? '<span class="description">' . esc_attr( $atts['description'] ) . '</span>' : '';
$item_output .= $args->after;
Nếu chúng ta muốn hiển thị thêm phần Description của đối tượng trong menu ra bên ngoài, trước tiên ta sẽ khai báo thêm một dòng với biến $item_output
, và kiểm tra xem nếu có description rồi thì nó mới hiển thị.
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
/** This filter is documented in wp-includes/post-template.php */
$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
$item_output .= '</a>';
$item_output .= !empty( $atts['description'] ) ? '<span class="description">' . esc_attr( $atts['description'] ) . '</span>' : '';
$item_output .= $args->after;
Kết quả:
Dưới đây là danh sách các thư viện walker với nhiều tính năng khác nhau có sẵn mà bạn có thể sử dụng lại trên internet:
- wp-bootstrap-navwalker: Thư viện walker để hiển thị menu theo cấu trúc của Bootstrap.
- wp-foundation-walker: Thư viện walker để hiển thị menu theo cấu trúc của Foundation.
- Clean-Menu-Walker: Thư viện walker để hiển thị menu gọn hơn, loại bỏ các class không cần thiết.
Lời kết
Tôi hi vọng rằng bài viết này đã giúp bạn hiểu rõ hơn về cách tùy chỉnh cấu trúc menu trong WordPress bằng Walker_Nav_Menu
. Dù nhìn dài và khá là kỹ, nhưng giải thích kỹ như vậy sẽ giúp bạn hiểu tốt hơn, tránh những thắc mắc hoặc hiểu lầm. Nếu sau khi đọc xong mà vẫn chưa hiểu, hãy xem video ở đầu bài nhé.