Mô tả của Menu items? Custom Walker cho wp_nav_menu()
Câu hỏi:
Menu bình thường của WordPress trông như thế này:
Home | Blog | About us | Contact
Nhưng tôi có thấy nhiều trang có các mô tả (description) ở phía dưới những link như vậy:
Home Page | Our Blogs | About us | Contact
….meet us…| read more| basic info| contact form
Làm thế nào để được như vậy?
Mô tả của Menu items? Custom Walker cho wp_nav_menu()
(Tôi muốn nó sẽ là hàm lõi cho tất cả thêm của tôi, vì vậy sẽ không dùng được plugin. Tôi chỉ muốn biết nó được làm như thế nào)
WordPressor
Câu trả lời chính xác nhất
Bạn cần có một custom walker cho nav menu.
Về cơ bản, thêm một tham số ‘walker’ vào các tùy chọn wp_nav_menu() và gọi một thể hiện (instance) của một lớp nâng cao (enhanced class):
wp_nav_menu(
array (
‘menu’ => ‘main-menu’,
‘container’ => FALSE,
‘container_id’ => FALSE,
‘menu_class’ => ”,
‘menu_id’ => FALSE,
‘depth’ => 1,
‘walker’ => new Description_Walker
)
);
Lớp Description_Walker mở rộng Walker_Nav_Menu và thay đổi hàm start_el( &$output, $item, $depth, $args ) để tìm kiếm $item->description.
Một ví dụ điển hình:
/**
* Create HTML list of nav menu items.
* Replacement for the native Walker, using the description.
*
* @see https://wordpress.stackexchange.com/q/14037/
* @author fuxia
*/
class Description_Walker extends Walker_Nav_Menu
{
/**
* Start the element output.
*
* @param string $output Passed by reference. Used to append additional content.
* @param object $item Menu item data object.
* @param int $depth Depth of menu item. May be used for padding.
* @param array|object $args Additional strings. Actually always an
instance of stdClass. But this is WordPress.
* @return void
*/
function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 )
{
$classes = empty ( $item->classes ) ? array () : (array) $item->classes;$class_names = join(
‘ ‘
, apply_filters(
‘nav_menu_css_class’
, array_filter( $classes ), $item
)
);! empty ( $class_names )
and $class_names = ‘ class=”‘. esc_attr( $class_names ) . ‘”‘;$output .= “<li id=’menu-item-$item->ID’ $class_names>”;
$attributes = ”;
! empty( $item->attr_title )
and $attributes .= ‘ title=”‘ . esc_attr( $item->attr_title ) .'”‘;
! empty( $item->target )
and $attributes .= ‘ target=”‘ . esc_attr( $item->target ) .'”‘;
! empty( $item->xfn )
and $attributes .= ‘ rel=”‘ . esc_attr( $item->xfn ) .'”‘;
! empty( $item->url )
and $attributes .= ‘ href=”‘ . esc_attr( $item->url ) .'”‘;// insert description for top level elements only
// you may change this
$description = ( ! empty ( $item->description ) and 0 == $depth )
? ‘<small class=”nav_desc”>’ . esc_attr( $item->description ) . ‘</small>’ : ”;$title = apply_filters( ‘the_title’, $item->title, $item->ID );
$item_output = $args->before
. “<a $attributes>”
. $args->link_before
. $title
. ‘</a> ‘
. $args->link_after
. $description
. $args->after;// Since $output is called by reference we don’t need to return anything.
$output .= apply_filters(
‘walker_nav_menu_start_el’
, $item_output
, $item
, $depth
, $args
);
}
}
Hoặc có thể thay thế bằng cách mà @nevvermind đã bình luận, bạn có thể kế thừa tất cả các chức năng của hàm parent’s start_el và chỉ việc thêm mô tả vào $output:
function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 )
{
parent::start_el( $output, $item, $depth, $args );
$output .= sprintf(
‘<i>%s</i>’,
esc_html( $item->description )
);
}
Output mẫu:
Bây giờ kích hoạt trường mô tả trong wp-admin/nav-menus.php để có thể edit trường này. Nếu bạn không WP, chỉ cần ném nội dung đầy đủ của post vào đó.
Đọc thêm ở đây:
- Associated bugs (Lỗi liên quan)
- Similar example with different markup and formatting (Ví dụ tương tự với đánh dấu và định dạng khác)
- Enable description box in menu management screen programmatically (Kích hoạt box mô tả trong màn hình quản lý menu theo lập trình)
- Collect the item description for later usage (Thu thập mô tả item để sử dụng sau này)
Vậy là xong.
Câu trả lời của fuxia
Nếu bạn muốn thừa kế từ cái cũ!= viết lại toàn bộ phương pháp, chỉ giữ lại tên cũ, hãy thử cái này: public function start_el(&$output, $item, $depth, $args) { parent::start_el($output, $item, $depth, $args); $output .= sprintf(‘<i>%s</i>’, esc_html($item->description)); } – nevvermind
@nevvermind Bạn ít nhất nên kiểm tra xem mô tả (description) có nội dung hay không. 😉 Vị trí của mô tả trong code mẫu của tôi chỉ là cách đơn giản nhất để minh họa cho giải pháp mà tôi đã đưa ra. Nếu bạn muốn đưa mô tả vào anchor, bạn phải xây dựng lại toàn bộ hàm. – fuxia
Đúng vậy, bạn phải viết toàn bộ phương pháp, không nghi ngờ gì về điều đó, nhưng đối với những người cần nối (append) thêm nó, nó có thể giúp họ bớt phải đau đầu. Và đây hoàn toàn là lỗi của WP. – nevvermind
Câu trả lời tuyệt vời và tôi đã sử dụng nó bằng cách sửa đổi một chút. Có lẽ là bạn có thể làm cho nó tốt hơn nếu tôi quên mất cái gì đó, cảm ơn. – The Alpha
Những gì tôi thực sự cần là wp_nav_menu, nhưng tôi cần thay đổi tham số ‘container_class’. Đối với trường hợp của tôi, tôi đã đổi menu chính với một cái khác, nhưng điều này đòi hỏi các lớp phải nhất quán cho css. – D. Dan
Kể từ phiên bản WordPress 3.0, bạn không cần dùng tới custom walker nữa!
Đã có bộ lọc walker_nav_menu_start_el, hãy xem ở đây:
https://developer.wordpress.org/reference/hooks/walker_nav_menu_start_el/
Ví dụ:
function add_description_to_menu($item_output, $item, $depth, $args) {
if (strlen($item->description) > 0 ) {
// append description after link
$item_output .= sprintf(‘<span class=”description”>%s</span>’, esc_html($item->description));// insert description as last item *in* link ($input_output ends with “</a>{$args->after}”)
//$item_output = substr($item_output, 0, -strlen(“</a>{$args->after}”)) . sprintf(‘<span class=”description”>%s</span >’, esc_html($item->description)) . “</a>{$args->after}”;
}return $item_output;
}
add_filter(‘walker_nav_menu_start_el’, ‘add_description_to_menu’, 10, 4);
Câu trả lời của Joost
Câu trả lời rất hay! Tôi đã sử dụng giải pháp nav walker của @toscho, nhưng cái của bạn dễ dàng duy trì hơn. Đây nên phải là câu trả lời chính xác nhất, nó tốt hơn nhiều. – Neejoh
Đây không phải là một cái tốt hơn hay tệ hơn các gợi ý khác. Nó là một cái hoàn toàn khác. Và nó cũng ngắn và dễ dàng hơn.
Thay vì sử dụng trường mô tả (description field) giống như gợi ý của @toscho, bạn có thể điền vào trường “Title” (tiêu đề) ở mỗi menu item với text mà bạn muốn. Sau đó dùng CSS sau đây:
.menu-item a:after { content: attr(title); }
Nó cũng sẽ dễ dàng hơn khi dùng jQuery để nối (append) nó. Nhưng text đã đủ để trang trí và làm cho CSS trông phù hợp rồi.
Câu trả lời của mrwweb
Bạn cũng có thể viết một phần tử <span> sau nhãn điều hướng (navigation label) trong menu và sử dụng quy tắc CSS sau đây để thay đổi cài đặt hiển thị (display setting) của nó (nó sẽ được mặc định là inline):
span {display:block}
Câu trả lời của Markus
Oh đây là một giải pháp đơn giản và dễ dàng nhưng tại sao lại dùng span vì bạn sẽ làm cho nó bị chặn? xhtml/html4 không cho phép chặn các phần tử trong links, tuy nhiên html5 lại cho phép điều đó. Vì vậy chỉ nên dùng div, và không cần css! – James Mitch