Thực đơn mô tả món nào? Walker tùy chỉnh cho wp_nav_menu ()


104

Menu Wordpress bình thường trông như:

Trang chủ | Blog | Về chúng tôi | Tiếp xúc

Nhưng tôi đã thấy nhiều trang với các mô tả dưới các liên kết sau:

Trang chủ | Blog của chúng tôi | Về chúng tôi | Liên hệ
.... gặp chúng tôi ... | đọc thêm | thông tin cơ bản | Mâu liên hệ

Làm thế nào để đạt được điều này?

(Tôi muốn nó là chức năng cốt lõi cho tất cả các chủ đề của mình, vì vậy không có plugin nào, tôi chỉ muốn biết nó đã được thực hiện như thế nào)

Câu trả lời:


115

Bạn cần một walker tùy chỉnh cho menu nav.

Về cơ bản, bạn thêm một tham số 'walker'vào các wp_nav_menu()tùy chọn và gọi một thể hiện của lớp nâng cao:

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_Walkermở rộng Walker_Nav_Menuvà thay đổi chức năng start_el( &$output, $item, $depth, $args )để tìm kiếm $item->description.

Một ví dụ cơ bản:

/**
 * 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, thay vào đó, như @nevvermind đã nhận xét , bạn có thể kế thừa tất cả các chức năng của chức năng của cha mẹ start_elvà chỉ cần nối 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 ) 
    );
}

Đầu ra mẫu:

nhập mô tả hình ảnh ở đây

Bây giờ kích hoạt trường mô tả wp-admin/nav-menus.phpđể có khả năng chỉnh sửa trường này. Nếu bạn không WP chỉ cần bỏ nội dung bài viết hoàn chỉnh của bạn vào đó.

nhập mô tả hình ảnh ở đây

Đọc thêm:

Và đó là nó.


11
Nếu cho bạn thừa kế! = Viết lại toàn bộ phương thức, chỉ cần giữ nguyên tên , hãy thử điều 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

2
@nevvermind Ít nhất bạn nên kiểm tra xem phần mô tả có nội dung nào đó không. ;) Vị trí của mô tả trong mã mẫu của tôi chỉ là cách đơn giản nhất để minh họa giải pháp. Nếu bạn cần lấy mô tả vào neo, bạn phải xây dựng lại toàn bộ hàm.
fuxia

1
vâng, 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 ...) nối nó, nó có thể giúp họ đỡ đau đầu. Và đây là lỗi của WP. Cố lên!
nevvermind

Một điều tuyệt vời và tôi đã sử dụng nó trong câu trả lời này bằng cách sửa đổi một chút, có thể bạn có thể làm cho nó tốt hơn nếu tôi bỏ lỡ điều gì đó, cảm ơn.
Alpha

Những gì tôi thực sự cần thiết các wp_nav_menu , nhưng tôi cần phải thay đổi các tham số 'container_class', để làm việc đối với trường hợp sử dụng cụ thể của tôi, nơi tôi trên một số điều kiện hoán đổi menu chính cho nhau, nhưng cần các lớp học để phù hợp cho css.
D. Dân

33

Kể từ WordPress 3.0 , bạn không cần đi bộ tùy chỉnh nữa!

walker_nav_menu_start_elbộ lọc, xem https://developer.wordpress.org/reference/hooks/walker_nav_menu_start_el/

Thí 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);

1
Đẹp! Tôi đã sử dụng giải pháp walk walk của @toscho, nhưng điều này sạch hơn và dễ bảo trì hơn. Đây phải là câu trả lời được chấp nhận, thực hành tốt hơn nhiều.
Neejoh

8

Điều này không tốt hơn hoặc tồi tệ hơn các đề xuất khác; nó chỉ khác nhau Nó ngắn và ngọt ngào quá.

Thay vì sử dụng trường mô tả như @toscho gợi ý, bạn có thể điền vào trường "Tiêu đề" trên mỗi mục menu với văn bản bạn muốn và sau đó sử dụng CSS này:

.menu-item a:after { content: attr(title); }

Cũng có thể dễ dàng sử dụng jQuery để nối nó, nhưng văn bản đủ trang trí để CSS có vẻ phù hợp.


2

Bạn cũng có thể viết một <span>phần tử sau nhãn điều hướng trong các menu và sử dụng quy tắc CSS sau để thay đổi displaycài đặt của nó ( inlinetheo mặc định):

span {display:block}

2
Đó là một giải pháp đơn giản và dễ dàng nhưng tại sao lại sử dụng spannếu bạn làm cho nó chặn? xhtml / html4 không cho phép các thành phần khối bên trong các liên kết, tuy nhiên html5 cũng vậy, vì vậy chỉ cần sử dụng divvà không cần bất kỳ css nào!
James Mitch
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.