Soporte » Diseño – Temas y plantillas » Menú por categorías con actualización automática de items

  • Resuelto Aitor Méndez

    (@aitormendez)


    Hola, quisiera pedir una orientación sobre el enfoque correcto para conseguir un menú basado en categorías que sea actualizable automáticamente. Es decir, que todos los posts de una categoría aparezcan dentro de su epígrafe correspondiente:

    • Categoría 1
    • Post 1
    • Post 2
    • Post 3
    • Categoría 2
    • Post 1
    • Post 2
    • Post 3
    • Categoría 3
    • Post 1
    • Post 2
    • Post 3

    Lo que a mí se me ocurre es:

    1) Crear un array de categorías con get_categories()

    2) Recorrer el array con foreach y hacer una WP_query de los post de cada categoría.

    Así me valdría, pero no sé si es correcto, porque prescindo de toda la infraestructura para menús, walker class, etc.

    ¿Es correcto o hay alguna forma mejor de hacerlo?

Viendo 11 respuestas - de la 1 a la 11 (de un total de 11)
  • Moderador kallookoo

    (@kallookoo)

    Hola,

    Esto dependera de tus conocimientos de PHP y WordPress.

    Te pongo varios ejemplos de como se podria implementar.

    – Crear un menu de categorias y cada vez que se publique una entrada (post) añadirlo al menu.
    – Crear un menu de categorias y usar el filtro wp_get_nav_menu_object para añadir el contenido.
    – Crear un menu de categorias y un custom Walker para añadir el contenido.
    – Hacer una WP_Query y ordenar los posts por categorias, este metodo no usaria los menus del WordPress.

    Como puedes ver hay posibilidades, ahora es cuestion de saber cual seria la mejor opcion, si el menu es el principal de la web, etc…

    Iniciador del debate Aitor Méndez

    (@aitormendez)

    @kallookoo, muchas gracias por tu respuesta.

    El menú es el menú principal del sitio y yo tengo conocimientos moderados de WordPress y PHP, aunque me gusta aprender cosas nuevas.

    De los cuatro enfoques que propones, el primero quedaría descartado por falta de automatización y el último es, según lo entiendo, el que yo proponía.

    He revisado la función wp_get_nav_menu_object. Parece que la función devuelve un objeto menu que ya existe previamente. Por lo que, según entiendo, el menú se crea a mano y luego se usa el objeto para definir las WP_query, de una forma similar al foreach ¿Correcto?

    La que me parece más atractiva es la de extender la clase Walker_Nav_Menu, pero no me dan los conocimientos. Intentaré leyendo la documentación, a ver qué tal. Si pudieras darme alguna pista, estupendo, si no, doy la pregunta por contestada.

    Moderador kallookoo

    (@kallookoo)

    Huy,
    Me explique mal…

    El mas automizado es el primer metodo pero te lo explique mal, te explico:
    Cuando creas un post, page, cpt se llama a un action save_post y save_post_nombre_del_post_type (recomendado) y desde hay puedes actualizar el menu de categorias que ya tienes creado usando wp_update_nav_menu_item, usando este metodo tambien tienes que actualizar el menu si borrases un post.

    Sobre wp_get_nav_menu_object te lo puse para que vieses como trabaja y vieses que es usado por wp_get_nav_menu_items que es la function que devuelve los elementos del menu. Di por hecho que lo comprenderias. Pero el filtro que deberias usar es wp_get_nav_menu_items.

    Sobre le Walker basicamente tienes que detectar la categoria y despues puedes añadir los sub items, pero aqui para añadir las classes que añade WordPress deberias pasarle _wp_menu_item_classes_by_context y añadir las classes CSS extras.

    No suelo poner codigos cuando es algo complejo basicamente por no crear problemas, porque si sucede algo como pegarlo, copiarlo o añadirlo mal, sera un problema para la persona que hace la pregunta o incluso romper el WordPress creando un problema mayor.

    Pero basicamente te reduzco las opciones.
    – Crea un plugin (el codigo es reutilizable si cambias de theme) o añade el codigo en functions.php, la mejor manera para aprender como desarrollar para WordPress.
    – Usa el filter wp_get_nav_menu_items si no te atreves con el primer metodo.
    Te he buscado un ejemplo, aunque esta en ingles creo que lo entenderas.
    https://gist.github.com/daggerhart/c17bdc51662be5a588c9

    Iniciador del debate Aitor Méndez

    (@aitormendez)

    Muchísimas gracias por la explicación. Ahora me toca estudiar lo que me indicas. Cierro la consulta.

    Moderador kallookoo

    (@kallookoo)

    De nada,
    Si tienes problemas o te salen errors puedes preguntar en Plugins y Hacks o WordPress Avanzado y veremos si te podemos ayudar.

    Iniciador del debate Aitor Méndez

    (@aitormendez)

    Pongo aquí la solución que he elaborado. No sé si es la mejor, pero funciona. He usado la modificación del walker, detectando si el item de menú es una taxonomía y buscando sus posts correspondientes con get_posts().

    class ep_submenu extends Walker_Nav_Menu {
        function end_el(&$output, $item, $depth=0, $args=[]) {
            if( 'taxonomy' == $item->type ) {
                $posts_args = [
                    'posts_per_page'   => -1,
                    'category_name'    => $item->title
                ];
                $cat_posts = get_posts($posts_args);
                $output .= '<ul>';
                foreach ($cat_posts as $cat_post) {
                    $permalink = get_permalink($cat_post->ID);
                    $output .= '<li><a href="' . $permalink  . '">' . $cat_post->post_title . '</a></li>';
                }
                $output .= '</ul>';
            }
            $output .= "</li>\n";
        }
    }
    Moderador kallookoo

    (@kallookoo)

    Hola,
    Te contesto por aqui, #foro-mods es para otro tipo de cosas 😉
    Tu solucion es totalmente validad, aunque yo lo hubiese hecho de otra manera.
    Si me lo permites te hago un par de cambios que puedes aplicar:

    
    class ep_submenu extends Walker_Nav_Menu {
    
        public function end_el( &$output, $item, $depth=0, $args=[] ) {
            if ( 'taxonomy' === $item->type ) {
                $posts_args = [
                    'nopaging' => true, // Muestra todos los posts
                    'category' => $item->ID // La ID no cambia aunque le cambies el nombre o slug
                ];
                $cat_posts = get_posts( $posts_args );
                // Si hay se añade el ul, li, etc...
                if ( $cat_posts ) {
                    $output .= '<ul>';
                    foreach ( $cat_posts as $cat_post ) {
                        $link = get_permalink( $cat_post->ID );
                        // Aplicas los filtros predeterminados para el titulo
                        $title = apply_filters( 'the_title', $cat_post->post_title );
                        if ( $title ) {
                            $output .= '<li><a href="' . $link  . '">' . $title . '</a></li>';
                        }
                    }
                    $output .= '</ul>';
                }
            }
            $output .= "</li>\n";
        }
    }
    

    Explicaciones:
    Porque nopaging en vez de posts_per_page basicamente porque es mas claro y si revistas wp-includes/class-wp-query.php:1719 veras que la define a true cuando usas -1.
    Porque category en vez de category_name basicamente porque la ID no cambia aunque le cambies el nombre o slug.
    La comprobacion si hay post es basicamente porque si aplicas padding o margin al ul, te apareceria el submenu y no tiene sentido añadirlo cuando no hay.
    El filtro the_title es para asegurarte que se muestra correctamente el titulo ya que escapa caracteres, etc… El if $title es para asegurarte que despues de pasar los filtros no esta vacio, no tiene sentido un link sin title y mas en un menu.

    Opinion de rendimiento:
    Pensando en los metodos que te comente me doy cuenta que salvo el primer metodo hay un aumento de consultas en la base de datos.
    Te explico:
    Por cada categoria del menu haces 1 consulta para recibir todos los posts de esa categoria, y despues se hace 1 consulta para cada get_permalink ya que usa get_post.
    En cifras hipoteticas seria:
    Menu con 15 categorias
    50 posts por cada categoria del menu
    Total 51 consultas por cada categoria del menu
    Total 765 consultas para mostrar el menu
    Hay le sumas las consultas que haga el propio WordPress, en tema de performance puede ser perjudicial, he puesto numeros mas o menos altos para que se vea el aumento mejor. Claro esta que si solo tienes 5 categorias y 10 posts por cada categoria serian 55 consultas

    Saludos

    Edit:
    Otra cosa que podrias hacer es añadir las classes CSS que usa WordPress asi podras darle un estilo mas compatible por si cambias de theme, etc…

    • Esta respuesta fue modificada hace 5 años por kallookoo.
    Iniciador del debate Aitor Méndez

    (@aitormendez)

    Buenísimas sugerencias, @kallookoo. Las aplicaré todas.

    Respecto al rendimiento, tienes toda la razón y ya lo había pensado. La opción de aplicar un filtro que modifique el menú a la hora de salvar un post, me parece mucho más efectiva en términos de rendimiento. Lo que pasa es que se me escapa un poco la técnica. Hay que hacer varias cosas que aún no domino:

    • Actualizar los submenús cuando se salva un post.
    • Actualizar los submenús cuando se modifica el menú desde el interfaz de edición.
    • Actualizar los submenús cuando se borra un post.

    Esto me parecía bastante complicado para mi nivel actual, aunque reconozco que es mejor.

    Iniciador del debate Aitor Méndez

    (@aitormendez)

    @kallookoo, creo que hay un error en las sugerencias:

    'category' => $item->ID

    Esto debería recoger el ID de la categoría, pero recoge el ID del item de menú, por lo que no funciona.

    Moderador kallookoo

    (@kallookoo)

    Upss, tienes razon… es $item->object_id

    Iniciador del debate Aitor Méndez

    (@aitormendez)

    Dejo aquí el código completo:

    https://github.com/aitormendez/menu-acordeon

    Y un ejemplo de cómo funciona:

    https://stage.esterpartegas.com/

Viendo 11 respuestas - de la 1 a la 11 (de un total de 11)
  • El debate ‘Menú por categorías con actualización automática de items’ está cerrado a nuevas respuestas.