Пользовательский Nav Walker: структура HTML для подменю

19 мая 2014 г., 13:02:30
Просмотры: 17.6K
Голосов: 1

У меня настроен Custom Nav Walker, и он правильно работает с основными пунктами меню, отображая их так, как я хочу.

Однако тот же HTML применяется к элементам sub-menu, что не соответствует моим требованиям.

Я хочу, чтобы sub-menu имел следующую структуру:

<ul>
    <li>
        <h2 class="dropdown-text">Блог 1</h2>
    </li>
    <li>
        <h2 class="dropdown-text">Блог 2</h2>
    </li>
    <li>
        <h2 class="dropdown-text">Блог 3</h2>
    </li>
    <li>
        <h2 class="dropdown-text">Блог 4</h2>
    </li>
</ul>

Вот HTML структура для полной навигации:

<div class="postit-surround">
<a href="#">
    <div class="postit">
        <div class="pin">
            <img src="<?php echo get_template_directory_uri(); ?>/assets/drawing-pin.png" alt="Кнопка" title="Кнопка">
        </div>
        <div class="postit-title">
            <h1 class="nav-title-text">Продукты</h1>
        </div>
        <div class="corner-peel">
            <img src="<?php echo get_template_directory_uri(); ?>/assets/corner-flick-cyan.png" alt="Уголок" title="Уголок">
        </div>
    </div>
</a>
<div class="navigation-dropdown">
    <ul>
        <li>
            <h2 class="dropdown-text">Продукт 1</h2>
        </li>
        <li>
            <h2 class="dropdown-text">Продукт 2</h2>
        </li>
        <li>
            <h2 class="dropdown-text">Продукт 3</h2>
        </li>
        <li>
            <h2 class="dropdown-text">Продукт 4</h2>
        </li>
        <li>
            <h2 class="dropdown-text">Продукт 5</h2>
        </li>
    </ul>
</div>
</div>

Вот вызов wp_nav_menu:

<div class="navigation-container">
<?php 

$walker = new my_nav_walker;
wp_nav_menu( array( 'theme_location' => 'header-menu', 'menu' => 'ul', 'menu_class' => 'navigation', 'menu_id' => '', 'walker' => $walker ) ); 

?>
</div>

Вот структура моего Custom Walker HTML: (ПРИМЕЧАНИЕ: Я новичок в этом, так что код может быть неоптимальным...)

class my_nav_walker extends Walker {
       function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {

            $direct = get_template_directory_uri();

            $item_output = $args->before;
            $item_output .= '<div class="postit-surround">';
            $item_output .= '<a'. $attributes .'>';
            /** Этот фильтр описан в wp-includes/post-template.php */

            $item_output .= '<div class="postit">
                                    <div class="pin">';
            $item_output .= '<img src="' . $direct . '/assets/drawing-pin.png" alt="Кнопка" title="Кнопка">
                                    </div>
                                    <div class="postit-title">
                                            <h1 class="nav-title-text">';
            $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;

            $item_output .= '</h1>
                            </div>
                                    <div class="corner-peel">
                                            <img src="' . $direct . '/assets/corner-flick-green.png" alt="Уголок" title="Уголок">
                                    </div>
                            </div>';
            $item_output .= '</a>';
            $item_output .= '</div>';
            $item_output .= $args->after;

        }    

} // Walker_Nav_Menu

Вот CSS, если нужно: Ссылка на PasteBin

Я не уверен, правильно ли я создаю структуру для получения отдельного стиля, который мне нужен.

Что вы посоветуете?

Есть ли альтернативы?

Конструктивная критика кода? (Не будьте слишком строги! :P)

РЕДАКТИРОВАНИЕ -----:

Я провел дополнительные исследования, чтобы понять PHP код, и теперь понимаю, где начинается определение начала и конца подменю (с помощью start_lvl и end_lvl), но все еще не понимаю, как разделить код для родительских элементов навигации и их соответствующих подменю.

Вот чего я хочу добиться в отображении навигации: http://jsfiddle.net/TPD5L/

15
Комментарии

"Конструктивная критика кода?". Хорошо сказано. ;)

Pieter Goosen Pieter Goosen
19 мая 2014 г. 13:10:26

@PieterGoosen Спасибо :) Даже мне самому этот код режет глаз, что уж говорить о других, кто его видит!

Mallander Mallander
19 мая 2014 г. 13:13:59

какой метод вы переопределяете? и не думаю, что вам нужен кастомный Walker, можно обойтись функцией wp_nav_menu с правильными аргументами, пожалуйста, приведите полный код, включая названия методов вашего кастомного Walker

MortalViews MortalViews
19 мая 2014 г. 14:47:47

@MortalViews Вопрос отредактирован, чтобы включить ПОЛНЫЙ код Custom Walker и вызов HTML wp_nav_menu.

Mallander Mallander
19 мая 2014 г. 14:55:27

Привет, когда вы расширяете родительский класс, вам не нужно включать методы, которые вы не переопределяете. Смотрите: общий пример http://codex.wordpress.org/Class_Reference/Walker

MortalViews MortalViews
19 мая 2014 г. 15:00:34

@MortalViews Не могли бы вы пояснить? Многое из этого мне непонятно :)

Mallander Mallander
19 мая 2014 г. 15:02:03

ознакомьтесь с примером общего меню @ http://codex.wordpress.org/Class_Reference/Walker а также http://codex.wordpress.org/Function_Reference/wp_nav_menu

MortalViews MortalViews
19 мая 2014 г. 15:02:50

Спасибо, но я не понимаю, как это позволяет мне разделить HTML для элементов верхнего уровня и подменю.

Mallander Mallander
19 мая 2014 г. 15:06:09

какова структура вашего меню? это? <ul><li><a>Услуги</a><ul clas='submenu'><li><a>Охота на волков</a></li><li><a>Охота на лошадей</a></li></ul></li></ul> т.е.: Элемент главного меню->элементы подменю

MortalViews MortalViews
19 мая 2014 г. 15:22:51

Я добавлю это к вопросу

Mallander Mallander
19 мая 2014 г. 15:27:26

@MortalViews Добавил.

Mallander Mallander
19 мая 2014 г. 15:36:30

Пожалуйста, взгляните на оригинальный Walker и удалите из вашего walker'а все методы, которые совпадают с оригинальными. Когда вы используете extend, у вас устанавливаются отношения родитель/потомок. Вам не нужно дублировать методы, которые уже есть в родительском классе, если только вы не хотите их изменить. После того как вы это сделаете, я посмотрю снова. В текущем виде слишком много избыточного кода.

s_ha_dum s_ha_dum
19 мая 2014 г. 15:51:56

@s_ha_dum Так лучше? Я просто удалил всё, что не нужно для генерации HTML-структуры.

Mallander Mallander
19 мая 2014 г. 15:55:54

Лучше, но ты удалил слишком много. Тебе всё ещё нужны определения методов для используемых методов -- часть с function start_el(...).

s_ha_dum s_ha_dum
19 мая 2014 г. 16:00:08

@s_ha_dum Вот так, теперь должно быть правильно. Хотя, когда я запускаю это на локальном сайте, я получаю: pastebin

Mallander Mallander
19 мая 2014 г. 16:04:44
Показать остальные 10 комментариев
Все ответы на вопрос 1
8

Решение: Скопируйте и вставьте приведенный ниже код в вашу функцию. Затем в шаблоне используйте

my_nav_menu($menu_location);

// Поместите это в ваши функции

class MY_Menu_Walker_Ext extends Walker {

    var $tree_type = array('post_type', 'taxonomy', 'custom');
    var $db_fields = array('parent' => 'menu_item_parent', 'id' => 'db_id');

    function start_el(&$output, $object, $depth = 0, $args = array(), $current_object_id = 0) {
        $output .="<li><h2 class='dropdown-text'>{$object->title}</h2>";
    }

    function end_el(&$output, $object, $depth = 0, $args = array()) {
        $output.='</li>';
    }

}

class my_custom_menu {

    public $menu;
    public $menuItems;
    public $parents;
    public $walker;

    public function __construct($menu_location) {
        $this->setMenu($menu_location);
        $this->getMenuItems();
        $this->getParents();

        $this->walker = new MY_Menu_Walker_Ext();
    }

    public function drawMenu() {

    }

    public function setMenu($menu_location) {

        $this->menu = $this->getMenuByLocation($menu_location);
    }

    protected function getMenuByLocation($menu_location) {
        $locations = get_nav_menu_locations();

        $menu = null;
        if ($locations && isset($locations[$menu_location])) {
            $menu = wp_get_nav_menu_object($locations[$menu_location]);
        }

        return $menu;
    }

    public function get() {

    }

    public function getMenuItems() {
        if ($this->menuItems)
            return $this->menuItems;
        $this->menuItems = wp_get_nav_menu_items($this->menu);

        return $this->menuItems;
    }

    public function getParents() {
        if ($this->parents)
            return $this->parents;
        $parents = array();

        foreach ($this->menuItems as $item) {
            if ($item->menu_item_parent == 0) {
                array_push($parents, $item);
            }
        }

        $this->parents = $parents;
        return $this->parents;
    }

    public function getChild($parent_id) {

        $childs = array();


        foreach ($this->menuItems as $item) {
            if ($parent_id == $item->menu_item_parent) {
                $item->menu_item_parent = 0;

                array_push($childs, $item);
                foreach ($this->menuItems as $item1) {
                    if ($item->ID == $item1->menu_item_parent) {
                        array_push($childs, $item1);
                    }
                }
            }
        }

        return $childs;
    }

    public function draw() {
        echo "<div class='postit-surround'>";

        foreach ($this->parents as $item) {
            $this->displayParentHTML($item->title);
            $this->drawChildren($this->getChild($item->ID));
        }
        echo "</div>";
    }

    public function displayParentHTML($title) {
        ?>
        <a href="#">
            <div class="postit">
                <div class="pin">
                    <img src="<?php echo get_template_directory_uri(); ?>/assets/drawing-pin.png" alt="Кнопка" title="Кнопка меню">
                </div>
                <div class="postit-title">
                    <h1 class="nav-title-text"><?php echo $title ?></h1>
                </div>
                <div class="corner-peel">
                    <img src="<?php echo get_template_directory_uri(); ?>/assets/corner-flick-cyan.png" alt="Загнутый уголок" title="Элемент дизайна">
                </div>
            </div>
        </a>

        <?php
    }

    public function drawChildren($children) {
        $defaults = array('menu' => '', 'container' => 'div', 'container_class' => '', 'container_id' => '', 'menu_class' => 'menu', 'menu_id' => '',
            'echo' => true, 'fallback_cb' => 'wp_page_menu', 'before' => '', 'after' => '', 'link_before' => '', 'link_after' => '', 'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
            'depth' => 0, 'walker' => '', 'theme_location' => '');
        $args = array(
            'theme_location' => 'header-menu',
            'container' => 'div',
            'container_class' => 'navigation-dropdown',
            'items_wrap' => '<ul >%3$s</ul>',
            'depth' => 0,
        );
        $args = wp_parse_args($args, $defaults);

        echo "<div class='navigation-dropdown'><ul>";
        echo $this->walker->walk($children, 2, $args);
        echo "</ul></div>";
    }

}

function my_nav_menu($name = null) {
    $myMenu = new my_custom_menu($name);
    $myMenu->draw();
}
19 мая 2014 г. 15:58:32
Комментарии

Спасибо, это работает само по себе, но мне сложно понять, как интегрировать это с моим Walker верхнего уровня, чтобы получить общую структуру, указанную в вопросе?

Mallander Mallander
19 мая 2014 г. 16:20:19

Я не понял вас. Вам не нужен другой Walker верхнего уровня.

MortalViews MortalViews
19 мая 2014 г. 16:22:10

Замените ваш класс my_nav_walker на этот. И в шаблоне, где вы хотите отобразить навигационное меню, скопируйте и вставьте код из второго раздела. Примечание: вывод будет включать также контейнер div

MortalViews MortalViews
19 мая 2014 г. 16:23:24

Я не уверен, что вы правильно поняли, что я имею в виду по поводу навигации (я был очень неясен в своем вопросе, извините за это). Посмотрите этот пример: http://jsfiddle.net/TPD5L/

Mallander Mallander
19 мая 2014 г. 16:25:58

Хорошо, HTML-код для части 'postit' должен быть включен в шаблон. <div для postit><код postit></> Здесь вызываем меню навигации </div>

MortalViews MortalViews
19 мая 2014 г. 16:28:27

Вы НЕ должны пытаться получить весь HTML из wp_nav_menu. Используйте wp_nav_menu только для части 'меню'. Остальное должно быть включено в код шаблона, понимаете?

MortalViews MortalViews
19 мая 2014 г. 16:29:56

Так вместо использования wp_nav_menu для получения элементов меню верхнего уровня, просто используйте его для получения дочерних элементов?

Mallander Mallander
19 мая 2014 г. 16:36:40

давайте продолжим обсуждение в чате

MortalViews MortalViews
19 мая 2014 г. 16:38:52
Показать остальные 3 комментариев