Construcción HTML personalizada para submenús en Custom Nav Walker

19 may 2014, 13:02:30
Vistas: 17.6K
Votos: 1

Tengo mi Custom Nav Walker configurado y funciona bien con los elementos del menú principal, mostrándolos como quiero.

Sin embargo, el mismo HTML se está aplicando a los elementos sub-menu lo cual no es lo que deseo.

Estoy tratando de que el sub-menu tenga el siguiente estilo:

<ul>
    <li>
        <h2 class="dropdown-text">Blog 1</h2>
    </li>
    <li>
        <h2 class="dropdown-text">Blog 2</h2>
    </li>
    <li>
        <h2 class="dropdown-text">Blog 3</h2>
    </li>
    <li>
        <h2 class="dropdown-text">Blog 4</h2>
    </li>
</ul>

Aquí está la estructura HTML para la navegación completa:

<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="Pin decorativo" title="Pin decorativo">
        </div>
        <div class="postit-title">
            <h1 class="nav-title-text">Productos</h1>
        </div>
        <div class="corner-peel">
            <img src="<?php echo get_template_directory_uri(); ?>/assets/corner-flick-cyan.png" alt="Esquina doblada" title="Esquina doblada">
        </div>
    </div>
</a>
<div class="navigation-dropdown">
    <ul>
        <li>
            <h2 class="dropdown-text">Productos 1</h2>
        </li>
        <li>
            <h2 class="dropdown-text">Productos 2</h2>
        </li>
        <li>
            <h2 class="dropdown-text">Productos 3</h2>
        </li>
        <li>
            <h2 class="dropdown-text">Productos 4</h2>
        </li>
        <li>
            <h2 class="dropdown-text">Productos 5</h2>
        </li>
    </ul>
</div>
</div>

Aquí está la llamada HTML para 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>

Aquí está la construcción para mi Custom Walker HTML: (NOTA: Soy nuevo en esto, así que será un poco desordenado...)

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 .'>';
        /* Este filtro está documentado en wp-includes/post-template.php */

        $item_output .= '<div class="postit">
                            <div class="pin">';
        $item_output .= '<img src="' . $direct . '/assets/drawing-pin.png" alt="Pin decorativo" title="Pin decorativo">
                            </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="Esquina doblada" title="Esquina doblada">
                            </div>
                    </div>';
        $item_output .= '</a>';
        $item_output .= '</div>';
        $item_output .= $args->after;

    }    

} // Walker_Nav_Menu

Aquí está el CSS si es necesario: Enlace a PasteBin

No estoy seguro si estoy haciendo la construcción correctamente para obtener el estilo separado que quiero.

¿Qué me recomendarías?

¿Hay alguna alternativa?

¿Crítica constructiva sobre el código? (¡No seas muy duro! :P)

EDITADO -----:

He investigado más para entender el código php, y ahora me doy cuenta de dónde comienza la definición del inicio y fin del sub-menu (Con start_lvl y end_lvl), pero todavía no entiendo cómo separar qué código va a los paneles de navegación principales y cuál va a sus respectivos sub-menús.

Esto es lo que busco con la visualización de la navegación: http://jsfiddle.net/TPD5L/

15
Comentarios

"¿Crítica constructiva sobre el código?". Bien dicho. ;)

Pieter Goosen Pieter Goosen
19 may 2014 13:10:26

@PieterGoosen Gracias :) Hasta yo mismo me estremezco con el código, ¡Dios sabe qué estarán pensando la mayoría que lo ve!

Mallander Mallander
19 may 2014 13:13:59

¿qué método estás sobrescribiendo? Y no creo que necesites un walker personalizado, puedes lograrlo usando la función wp_nav_menu con los argumentos adecuados. Por favor publica el código completo incluyendo los nombres de los métodos de tu walker personalizado

MortalViews MortalViews
19 may 2014 14:47:47

@MortalViews Pregunta editada para incluir el CÓDIGO COMPLETO del Custom Walker, y la llamada HTML wp_nav_menu.

Mallander Mallander
19 may 2014 14:55:27

Hola, cuando extiendes la clase padre, no necesitas incluir ningún método que no estés sobrescribiendo. Revisa: el ejemplo general http://codex.wordpress.org/Class_Reference/Walker

MortalViews MortalViews
19 may 2014 15:00:34

@MortalViews ¿Podrías elaborar? No entiendo mucho de esto :)

Mallander Mallander
19 may 2014 15:02:03

revisa el Ejemplo de Menú General en http://codex.wordpress.org/Class_Reference/Walker y también http://codex.wordpress.org/Function_Reference/wp_nav_menu

MortalViews MortalViews
19 may 2014 15:02:50

Gracias por eso, pero no entiendo cómo eso me permite separar el HTML para los elementos de nivel superior y el sub-menú.

Mallander Mallander
19 may 2014 15:06:09

¿cómo es tu estructura de menú? ¿es así? <ul><li><a>Servicios</a><ul clas='submenu'><li><a>Caza de Lobos</a></li><li><a>Caza de Caballos</a></li></ul></li></ul> es decir: Elemento del Menú Principal -> elementos del submenú

MortalViews MortalViews
19 may 2014 15:22:51

Lo agregaré a la pregunta

Mallander Mallander
19 may 2014 15:27:26

@MortalViews Agregado.

Mallander Mallander
19 may 2014 15:36:30

Por favor revisa el Walker original y elimina todos los métodos de tu walker que sean iguales al original. Cuando haces extend tienes una especie de relación padre/hijo. No necesitas duplicar métodos que existen en el padre a menos que quieras cambiarlos. Una vez que hagas eso, le echaré otro vistazo. Hay demasiado código innecesario como está ahora.

s_ha_dum s_ha_dum
19 may 2014 15:51:56

@s_ha_dum ¿Está mejor así? Solo eliminé todo lo que no era necesario para la generación de la estructura HTML.

Mallander Mallander
19 may 2014 15:55:54

Mejor, pero has eliminado demasiado. Todavía debes tener las definiciones de los métodos que estás usando-- la parte del function start_el(...).

s_ha_dum s_ha_dum
19 may 2014 16:00:08

@s_ha_dum Ahí vamos, debería estar bien ahora. Aunque, cuando tengo esto en mi sitio localhost, me aparece: pastebin

Mallander Mallander
19 may 2014 16:04:44
Mostrar los 10 comentarios restantes
Todas las respuestas a la pregunta 1
8

Solución: Copia y pega el siguiente código en tu función. y luego en la plantilla usa

my_nav_menu($menu_location);

//coloca esto en tus funciones

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="Icono de chincheta" title="Chincheta decorativa">
                </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="Esquina despegada" title="Efecto de esquina despegada">
                </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 may 2014 15:58:32
Comentarios

Gracias, eso funciona bien por sí solo, sin embargo, me cuesta ver cómo integrarlo con mi Walker de nivel superior para obtener la estructura general indicada en la pregunta.

Mallander Mallander
19 may 2014 16:20:19

No te entendí. No necesitas otro Walker de nivel superior.

MortalViews MortalViews
19 may 2014 16:22:10

Reemplaza tu clase my_nav_walker con esta. Y en la plantilla donde quieras mostrar el menú de navegación, copia y pega el código de la segunda sección. Nota: la salida incluirá también el div contenedor.

MortalViews MortalViews
19 may 2014 16:23:24

No estoy seguro de que estés entendiendo lo que busco con la navegación (he sido muy poco claro en mi pregunta, lo siento por eso) Mira este fiddle: http://jsfiddle.net/TPD5L/

Mallander Mallander
19 may 2014 16:25:58

ok, el html para la parte del 'postit' debería incluirse en la plantilla. <div post it>< el código del post it></> Aquí llama al menú de navegación </div>

MortalViews MortalViews
19 may 2014 16:28:27

NO deberías intentar obtener todo el html desde wp_nav_menu. usa wp_nav_menu solo para la parte del 'menú'. el resto debería incluirse en el código de la plantilla, ¿me entiendes?

MortalViews MortalViews
19 may 2014 16:29:56

¿Entonces en lugar de usar wp_nav_menu para obtener los elementos del menú de primer nivel, simplemente lo usas para obtener los elementos hijos?

Mallander Mallander
19 may 2014 16:36:40

continuemos esta discusión en el chat

MortalViews MortalViews
19 may 2014 16:38:52
Mostrar los 3 comentarios restantes