Añadir iconos de Font-Awesome al widget de categorías programáticamente
Utilizo el widget de Categorías en mi barra lateral y me gustaría mostrar un icono de Font Awesome junto a cada categoría listada en el widget. Por ahora, el icono sería el mismo para todas las categorías, pero en el futuro me gustaría asignar un icono único a cada categoría.
Quiero modificar el widget de Categorías usando código en mi archivo functions.php para añadir el icono insertando marcado como <i class="fa fa-chevron-right"></i>
dentro del elemento anchor/enlace de la categoría después del título de la categoría. Podría hacer esto mediante CSS, pero perdería la capacidad de determinar programáticamente qué icono mostrar, junto con la flexibilidad para otras mejoras/cambios que pueda querer hacer en el futuro.
Básicamente, quiero lograr este efecto:
Cat 1 > Cat 2 > Cat 3 >
(El símbolo '>' representa la ubicación del icono relativa al título de la categoría)
Tengo Font Awesome cargado en el archivo functions.php usando el hook wp_enqueue_scripts
como se muestra a continuación, y carga y muestra los iconos perfectamente. Nota que no uso ningún plugin de Font Awesome construido para WordPress.
/* Encolar Scripts
-----------------------------------------------------------------*/
add_action( 'wp_enqueue_scripts', 'essentials_enqueue_scripts' );
function essentials_enqueue_scripts() {
/* jQuery */
wp_enqueue_script('jquery');
wp_enqueue_script( 'jquery_ui', "http" . ($_SERVER['SERVER_PORT'] == 443 ? "s" : "") . "://ajax.googleapis.com/ajax/libs/jqueryui/2.0.3/jquery-ui.min.js", false, null);
wp_enqueue_script( 'waypoints', get_template_directory_uri() . '/js/waypoints.min.js');
wp_enqueue_script( 'essentials_main', get_template_directory_uri() . '/js/essentials_main.js', array(), '1.0.0', true );
wp_enqueue_script( 'essentials_show_stuff', get_template_directory_uri() . '/js/essentials_show_stuff.js', array(), '1.0.0', true );
/* Google Fonts */
wp_register_style('GoogleFonts','http://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700,800|Bad+Script');
wp_enqueue_style( 'GoogleFonts');
/* Font Awesome Fonts */
wp_register_style('Font Awesome','//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css');
wp_enqueue_style( 'Font Awesome');
}
A pesar de mis mejores esfuerzos de investigación, no pude encontrar una solución para modificar el widget de categorías.
Suposiciones:
No explicas cómo deseas instalar el paquete de Font Awesome, así que por el momento asumo que estás usando el plugin Font Awesome Icons.
Has escrito:
Antes de que alguien diga que use una imagen de fondo, no quiero hacer eso. Prefiero que sea físico.
así que asumo que deseas usar la etiqueta <i>
directamente, por ejemplo:
<i class="fa icon-caret-right"></i>
después de cada enlace de categoría en la lista de categorías del widget.
Idea:
Puedes usar el filtro wp_list_categories
para modificar la salida de la lista de categorías del widget.
Ejemplo:
Aquí tienes un ejemplo sencillo de cómo inyectarlo en la lista de categorías a través del filtro wp_list_categories
:
/**
* Inyecta la etiqueta Font Awesome <i> después de cada enlace de categoría en el widget
*
* @param string $output
* @return string $output
*/
function custom_wp_list_categories( $output )
{
remove_filter( current_filter(), __FUNCTION__ );
return str_ireplace( '</li>', '<i class="fa icon-caret-right"></i></li>', $output);
}
add_action( 'widgets_init', function(){
add_filter( 'wp_list_categories', 'custom_wp_list_categories' );
});
Esto te dará una salida similar a esta:

Excelente fragmento de código, lo revisaré cuando regrese en un rato. Publicaré los resultados.

solo recuerda ajustar el nombre de la clase según tus necesidades ;-) Yo usé icon-caret-right
porque esa es la regla de nomenclatura de clases según el plugin. En otros casos podría ser fa-caret-right
.

return str_ireplace( '</li>', '<i class="fa fa-chevron-right"></i></li>', $output);
funcionó, pero return str_ireplace( '</a></li>', '<i class="fa fa-chevron-right"></i></a></li>', $output);
no lo hizo.

vale, quieres añadirlo dentro de la etiqueta <a></a>
, entonces prueba esto: return preg_replace( '/<\/a>\s*<\/li>/i', ' <i class="fa fa-chevron-right"></i></a></li>', $output );

Vale, ahora me he perdido con la nueva parte... ¿cómo funciona exactamente eso? Entiendo la última parte, pero no la primera.

No voy a votar negativamente una solución/intento legítimo de ayudar al OP, pero en serio: usar reemplazo de cadenas PHP cuando una simple regla CSS bastaría parece ser excesivo.

Lamento no haber sido más específico en mi 'Pregunta' original, pero esto no se limitará a algo tan pequeño como poner el icono allí. Esto se expandirá en el futuro, y CSS no cumplió con mis necesidades, por eso publiqué aquí ;).

@MrJustin gracias por el voto, también estoy impresionado por las ingeniosas respuestas proporcionadas por los otros usuarios. pd: \s*
coincide con cualquier carácter de espacio en blanco, como espacio, tabulación y nueva línea.

@MrJustin ¿podrías ampliar tu pregunta para detallar estas "necesidades futuras" para las que CSS es insuficiente? Tal como está, tu pregunta es específicamente sobre CSS y no está vinculada a WordPress, por lo que se encuentra en terreno movedizo para ser cerrada por estar fuera de tema.

También podría agregar que un filtro de WordPress era excesivo dado el alcance de la pregunta de MrJustin. Difícilmente creo que llevarlo hacia expresiones regulares sea una buena idea... No puedo evitar sentir que las expresiones regulares se encuentran en el polo opuesto a la simplicidad de una implementación CSS estática. Temo por cualquier futuro usuario de WPSE que venga aquí buscando mostrar un solo carácter de una fuente de íconos y termine con un trozo de expresiones regulares en su backend. ¡Tengan piedad de los n00bs!

también se podría usar: return str_ireplace( '</a>', ' <i class="fa fa-chevron-right"></i></a>', $output);

Esta respuesta contiene una solución CSS bastante sencilla.
Básicamente, agregarías lo siguiente a tu hoja de estilos:
.cat-item cat-item-7 {
list-style-image: url('mi-epico-icono-noticias');
}
cat-item cat-item-11 {
list-style-image: url('mi-epico-icono-jquery');
}
etcétera
Sí, no es una solución muy dinámica, pero supongo que tus categorías no van a cambiar con frecuencia.

Que la respuesta sea CSS puro es indicativo de que la pregunta subyacente está fuera de tema para WPSE. Dicho esto: creo que tus selectores CSS no tienen la sintaxis adecuada. Deberías usar .cat-item.cat-item-7
- o, dado que se pretende usar la misma imagen de fuente de icono para todos los elementos de la lista, simplemente usa .cat-item
. Además: un icono de fuente usaría el atributo content
y apuntaría al pseudo-clase :after
, como: .cat-item:after { content: '\f18d'; }
.

Puntos válidos. Sí, cometí un error en la sintaxis. ¿Estamos seguros de que OP quiere la misma imagen, o una diferente por categoría? (Así es como lo entendí). Solo quería proponer la solución más fácil, aunque eso saca la pregunta/respuesta fuera de tema.

Suponiendo que quieras usar el icono fa-chevron-right
, simplemente necesitas apuntar al elemento de lista mediante CSS. Usa la pseudo-clase :after
:
.list-item:after {
font-family: FontAwesome; // o como sea que esté registrada la familia de FontAwesome
content: '\f054';
}
Editar
Para darte una idea de cómo podrías pasar CSS dinámico (que puede adaptarse fácilmente a una opción de Plugin personalizada) mediante un callback, aquí tienes un ejemplo:
(Nota: "plugin" y "theme" son intercambiables a continuación).
Primero, modificaremos el CSS para apuntar específicamente a los elementos de lista dentro de un Widget. WordPress añade una clase, .widget
, al contenedor del Widget. Así que puedes apuntar a eso:
.widget .list-item:after {}
O, si todo esto estará empaquetado en un Plugin que registra un Widget personalizado, entonces puedes apuntar a la clase CSS que defines en tu Widget personalizado, mediante el array $widget_ops
:
$widget_ops = array(
'classname' => 'custom-widget-classname',
'description' => __( 'Descripción del Widget Personalizado', 'namespace' )
);
Así que puedes apuntar a ese nombre de clase personalizado:
.custom-widget-classname .list-item:after {}
O, si quieres apuntar al Widget "Categorías" principal, puedes usar la clase .widget_categories
. Usaremos ese enfoque para el ejemplo.
Vamos a colocarlo dentro de un callback, enganchado a wp_head
, aunque también podrías usar wp_print_styles
:
function pluginslug_fontawesome_styles() {
// El código irá aquí
}
add_action( 'wp_head', 'pluginslug_fontawesome_styles' );
Dentro, simplemente vamos a generar una hoja de estilos, con nuestra regla de arriba:
function pluginslug_fontawesome_styles() {
?>
<script type="text/css">
.widget_categories .list-item:after {
font-family: FontAwesome; // o como sea que esté registrada la familia de FontAwesome
content: '\f054';
}
</script>
<?php
}
add_action( 'wp_head', 'pluginslug_fontawesome_styles' );
En este punto, ya has terminado. Fácil. Pero, como ya estás dentro de una función PHP, puedes hacer fácilmente que esta hoja de estilos sea dinámica, usando una variable:
function pluginslug_fontawesome_styles() {
// Definir variable para el icono de estilo de lista
$list_item_icon = '\f054';
// ...snip:
content: <?php echo $list_item_icon; ?>;
Así que ahora, es sencillo usar un valor de opción de Plugin personalizado, simplemente pasándolo a la variable:
function pluginslug_fontawesome_styles() {
// Obtener opciones del Plugin, se asume que es un array
$plugin_options = get_option( 'pluginslug_plugin_options' );
// Definir variable para el icono de estilo de lista
$list_item_icon = $plugin_options['list_item_icon'];
// Generar hoja de estilos
?>
<script type="text/css">
.widget_categories .list-item:after {
font-family: FontAwesome; // o como sea que esté registrada la familia de FontAwesome
content: <?php echo $list_item_icon; ?>;
}
</script>
<?php
}
add_action( 'wp_head', 'pluginslug_fontawesome_styles' );
¡Eso es todo! CSS dinámico, generando un icono real (no una imagen de fondo), obtenido de una opción de Plugin.
Y como es solo CSS, es fácilmente extensible a prácticamente cualquier selector que puedas imaginar, no limitado solo a un elemento de lista dentro de un Widget.

Sabes que puedes envolver reglas CSS en un callback y ponerlas en cola con wp_head
o wp_print_styles
, ¿verdad? Pero esa parte de la implementación es una pregunta aparte y está fuera del alcance de la pregunta tal como está escrita.

Sí, sé cómo poner en cola. Sin embargo, no quiero usar CSS. Sé que es una forma rápida y eficiente de hacerlo, y te felicito por eso... pero quizás debería haber usado las palabras "necesito una" en lugar de "quiero una" cuando se trata de la función.

Por favor, revisa la pregunta editada. Añadí un ejemplo para mostrar cómo todo esto realmente puede manejarse mediante CSS, de forma dinámica, extensible y capaz de tener en cuenta opciones personalizadas de Plugins.

Correcto, pero ahora, ¿qué pasa si quisiera que el 'icono' flotara hacia la derecha? En mi CSS normal lo he adjuntado a li a:after {content}
e intenté: text-align: right
y no hizo nada para mí. Lo que quiero decir con esto, para aclarar, es qué pasaría si quisiera que todos los iconos estuvieran a la derecha del LI con el texto a la izquierda. Digamos que el ul/li estaba configurado en 250px, el texto siempre es un enlace, pero lo tenía configurado como bloque. Luego añadí el 'icono' y quería que el icono se colocara a la derecha del li. Con el <i...></i> puedo flotarlo fácilmente.

Para responder a esa pregunta específica: en lugar de li a:after
, usa li a:before
. Pero el estilo/posicionamiento de los elementos: aparte de conocer el marcado proporcionado por WordPress (incluyendo las clases CSS específicas y el marcado HTML de la lista), estas son preguntas de CSS/HTML. Curiosamente, la respuesta que marcaste como aceptada no usa nada más que CSS. (La hoja de estilos Font Awesome en cola que hace uso de la clase que añades mediante el reemplazo de cadenas usa el pseudo-clase :after
y el atributo content
para mostrar el icono).

Lo haría de esta manera:
// Si solo estás usando el widget en páginas específicas,
// podrías querer usar algunas condiciones apropiadas aquí
add_action('wp_enqueue_scripts', function() {
wp_enqueue_style('font-awesome',
'//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css');
});
function wpse_128247_font_awesome_categories($cat_name) {
// Define tu icono deseado aquí
$icon = ' <i class="fa fa-smile-o"></i>';
return $cat_name.$icon;
} // function wpse_128247_font_awesome_categories
function wpse_128247_add_filter($cat_args) {
add_filter('list_cats', 'wpse_128247_font_awesome_categories');
// Como estamos interceptando este filtro, simplemente pasamos sus datos
return $cat_args;
} // function wpse_128247_add_filter
add_filter('widget_categories_args', 'wpse_128247_add_filter');
function wpse_128247_remove_filter($output) {
remove_filter('list_cats', 'wpse_128247_font_awesome_categories');
// Como estamos interceptando este filtro, simplemente pasamos sus datos
return $output;
} // function wpse_128247_remove_filter
add_filter('wp_list_categories', 'wpse_128247_remove_filter');
Primero, encolamos los estilos de Font Awesome. Luego, interceptamos algunos filtros para agregar/eliminar nuestro propio filtro para el listado de categorías. Eso es todo.
// EDITADO:
Sin los comentarios, adaptado al hecho de que ya tienes Font Awesome encolado, usando closures y dejando que el filtro se elimine a sí mismo, el código queda así:
function wpse_128247_font_awesome_categories($cat_name) {
remove_filter(current_filter(), __FUNCTION__);
return $cat_name.' <i class="fa fa-smile-o"></i>';
} // function wpse_128247_font_awesome_categories
function wpse_128247_add_filter($cat_args) {
add_filter('list_cats', 'wpse_128247_font_awesome_categories');
return $cat_args;
} // function wpse_128247_add_filter
add_filter('widget_categories_args', 'wpse_128247_add_filter');
No llamaría a eso excesivo. Pero sí, mi código consta de más líneas que la solución actual de birgire.

Tu solución no era mala, pero era excesiva en comparación con la de birgire. Ya tengo Font-Awesome encolado, lo siento, no lo especifiqué.

Sí, ese código no es excesivo, estoy de acuerdo con eso. Probablemente solo parecía más con las 4 funciones en lugar de 2, y la cantidad de comentarios. Aprecio los comentarios, no los estoy menospreciando. Solo parecía mucho más :).
