¿Cómo puedo personalizar wp_list_categories?
Tengo una lista de categorías en WooCommerce que estoy tratando de personalizar para que se muestre como en la siguiente imagen.
Creé la imagen de arriba usando HTML y CSS normal, sin embargo, ahora me gustaría convertirla a WordPress para que se cree dinámicamente.
Aquí está el HTML:
<div class="col tertiary" id="filters">
<ul class="product-categories">
<li id="pattern_garment_type">
<h5>Mujeres</h5>
<ul>
<li class="selected">
<a href="#">Todo</a>
</li>
<li class="">
<a href="#">Accesorios</a>
</li>
<li class="">
<a href="#">Blusas</a>
</li>
.etc...
</ul>
</li>
<li id="pattern_garment_type">
<h5>Hombres</h5>
<ul>
<li class="selected">
<a href="#">Todo</a>
</li>
<li class="">
<a href="#">Accesorios</a>
</li>
<li class="">
<a href="#">Abrigos</a>
</li>
..etc..
</ul>
</li>
<li id="pattern_garment_type">
<h5>Niños</h5>
<ul>
<li class="selected">
<a href="#">Todo</a>
</li>
<li class="">
<a href="#">Bebés</a>
</li>
<li class="">
<a href="#">Niñas</a>
</li>
<li class="">
<a href="#">Niños</a>
</li>
</ul>
</li>
</ul>
</div>
Aquí está el código actual de WordPress con el que estoy trabajando (no estoy seguro si debería usar el walker para personalizar la salida para que se genere como el HTML anterior):
<div id="content-filters" class="two columns">
<?php $args = array(
'style' => 'list',
'show_count' => 0,
'use_desc_for_title' => 1,
'child_of' => 0,
'title_li' => __( '' ),
'show_option_none' => __('No hay elementos del menú'),
'number' => null,
'echo' => 1,
'depth' => 2,
'taxonomy' => 'product_cat',
); ?>
<div class="col tertiary" id="filters">
<ul class="product-categories">
<?php wp_list_categories( $args ); ?>
</ul>
</div>
1) ¿Cómo puedo usar el filtro wp_list_categories para agregar un enlace "Todo" en la parte superior de las subcategorías que enlace a una página que muestre todos los elementos?
2) ¿Cómo puedo también usar el filtro wp_list_categories para eliminar el enlace de la categoría principal y envolverlo en una etiqueta para hacerlo negrita (como en la imagen de ejemplo)?
Cualquier ayuda sería apreciada

Aunque exista un filtro wp_list_categories
, este pasa (y por lo tanto debes devolver) el marcado HTML generado por la función wp_list_categories()
. Esto significa que si quieres usar ese filtro, tendrás que alterar el DOM con PHP, y aunque es posible (ojalá usando bibliotecas externas de PHP), seguro que no es la mejor solución para tus necesidades.
Una alternativa es usar JavaScript para alterar el HTML después de creado. Es una posibilidad, pero yo soy desarrollador de WordPress, no de JavaScript, así que te daré la solución de WordPress.
Debes crear una clase personalizada de Category Walker y luego usarla dentro de una versión personalizada de wp_list_categories()
.
Empecemos.
Primero, la clase personalizada Category Walker (colócala en functions.php
):
class My_Category_Walker extends Walker_Category {
var $lev = -1;
var $skip = 0;
static $current_parent;
function start_lvl( &$output, $depth = 0, $args = array() ) {
$this->lev = 0;
$output .= "<ul>" . PHP_EOL;
}
function end_lvl( &$output, $depth = 0, $args = array() ) {
$output .= "</ul>" . PHP_EOL;
$this->lev = -1;
}
function start_el( &$output, $category, $depth = 0, $args = array(), $id = 0 ) {
extract($args);
$cat_name = esc_attr( $category->name );
$class_current = $current_class ? $current_class . ' ' : 'current ';
if ( ! empty($current_category) ) {
$_current_category = get_term( $current_category, $category->taxonomy );
if ( $category->term_id == $current_category ) $class = $class_current;
elseif ( $category->term_id == $_current_category->parent ) $class = rtrim($class_current) . '-parent ';
} else {
$class = '';
}
if ( ! $category->parent ) {
if ( ! get_term_children( $category->term_id, $category->taxonomy ) {
$this->skip = 1;
} else {
if ($class == $class_current) self::$current_parent = $category->term_id;
$output .= "<li class='" . $class . $level_class . "'>" . PHP_EOL;
$output .= sprintf($parent_title_format, $cat_name) . PHP_EOL;
}
} else {
if ( $this->lev == 0 && $category->parent) {
$link = get_term_link(intval($category->parent) , $category->taxonomy);
$stored_parent = intval(self::$current_parent);
$now_parent = intval($category->parent);
$all_class = ($stored_parent > 0 && ( $stored_parent === $now_parent) ) ? $class_current . ' all' : 'all';
$output .= "<li class='" . $all_class . "'><a href='" . $link . "'>" . __('Todos') . "</a></li>\n";
self::$current_parent = null;
}
$link = '<a href="' . esc_url( get_term_link($category) ) . '" >' . $cat_name . '</a>';
$output .= "<li";
$class .= $category->taxonomy . '-item ' . $category->taxonomy . '-item-' . $category->term_id;
$output .= ' class="' . $class . '"';
$output .= ">" . $link;
}
}
function end_el( &$output, $page, $depth = 0, $args = array() ) {
$this->lev++;
if ( $this->skip == 1 ) {
$this->skip = 0;
return;
}
$output .= "</li>" . PHP_EOL;
}
}
Extiende la clase WP Walker_Category y sobrescribe los 4 métodos con algo que se ajuste a tus necesidades.
Después, en el functions.php
coloca la función personalizada:
function custom_list_categories( $args = '' ) {
$defaults = array(
'taxonomy' => 'category',
'show_option_none' => '',
'echo' => 1,
'depth' => 2,
'wrap_class' => '',
'level_class' => '',
'parent_title_format' => '%s',
'current_class' => 'current'
);
$r = wp_parse_args( $args, $defaults );
if ( ! isset( $r['wrap_class'] ) ) $r['wrap_class'] = ( 'category' == $r['taxonomy'] ) ? 'categories' : $r['taxonomy'];
extract( $r );
if ( ! taxonomy_exists($taxonomy) ) return false;
$categories = get_categories( $r );
$output = "<ul class='" . esc_attr( $wrap_class ) . "'>" . PHP_EOL;
if ( empty( $categories ) ) {
if ( ! empty( $show_option_none ) ) $output .= "<li>" . $show_option_none . "</li>" . PHP_EOL;
} else {
if ( is_category() || is_tax() || is_tag() ) {
$current_term_object = get_queried_object();
if ( $r['taxonomy'] == $current_term_object->taxonomy ) $r['current_category'] = get_queried_object_id();
}
$depth = $r['depth'];
$walker = new My_Category_Walker;
$output .= $walker->walk($categories, $depth, $r);
}
$output .= "</ul>" . PHP_EOL;
if ( $echo ) echo $output; else return $output;
}
La parte difícil está hecha. Ahora el código de la plantilla, colócalo donde lo necesites:
<div id="content-filters" class="two columns">
<div class="col tertiary" id="filters">
<?php
$args = array(
'taxonomy' => 'product_cat',
'show_option_none' => __('No hay elementos en el menú.'),
'echo' => 1,
'depth' => 2,
'wrap_class' => 'product-categories',
'level_class' => 'pattern_garment_type',
'parent_title_format' => '<h5>%s</h5>',
'current_class' => 'selected'
);
custom_list_categories( $args );
?>
</div>
</div>
Personaliza los argumentos $args
si lo deseas, los he configurado según tu código de respuesta. Solo he cambiado 'pattern_garment_type' para que sea una clase y no un ID, porque no puedes tener el mismo ID de etiqueta múltiples veces en HTML (como en tu marcado).
Eso es todo, espero que te ayude.

Oudin,
Responderé aquí la parte CSS de tu pregunta:
Usa esto para eliminar los puntos de la lista:
.ul.product-categories, ul.children{
list-style-type: none;
}
Usa esto para poner en negrita solo las categorías principales:
li {font-weight:normal} // necesitas establecer primero el estado por defecto de la lista
ul.product-categories > li{font-weight:bold;} //luego puedes cambiar el nivel superior de la lista sin afectar a sus hijos
Así es como puedes apuntar a esos elementos con css sin tener que escribir tus propias clases.
También puedes añadir esto a los argumentos de tu wp_list_categories
'hide_empty' => 0
Para mostrar todas las categorías, incluso aquellas que no tienen una publicación.
Hay dos enfoques que puedes tomar para la segunda parte de tu pregunta (añadir el enlace ALL, y eliminar el enlace de las categorías principales)
- Puedes usar Javascript/jquery para eliminar/añadir lo que quieras una vez que la página se haya cargado
- Puedes escribir un filtro wp_list_categories, para hacer esos cambios
La opción 2 sería la forma más limpia de hacerlo. La opción 1 sería la forma más rápida de hacerlo.
No he llegado a ninguna de las dos, por falta de tiempo. Pero echa un vistazo a cómo crear filtros en WordPress.

Gracias por la respuesta, sin embargo estoy más interesado en la codificación de WordPress en lugar de CSS como mencioné, ya he creado el HTML y CSS para la imagen incluida. Lo que se requiere es la forma correcta de generar el HTML a través de WordPress similar a lo que he proporcionado. Así que si puedes ampliar los filtros sería genial.
