1

I use the Categories widget on my sidebar(s) and I would like to display a Font Awesome icon next to each category listed in the widget. The icon would be the same for all categories, for now, but I would like to give each category it's own unique icon in the future.

I would like to modify the Categories widget using code in my functions.php file to add the icon by inserting markup like <i class="fa fa-chevron-right"></i> into category's link/anchor element after the category's title. I could accomplish this via CSS, but in doing so I lose the ability to programmatically determine which icon to display, along with the flexibility for other improvements/changes that I may wish to make in the future.


Basically, I wish to achieve this effect:

Cat 1          >

Cat 2          >

Cat 3          >

(The greater-than symbol '>' represents the icon placement relative to the category title)


I have Font Awesome enqueued in the functions.php file using the wp_enqueue_scripts hook as follows, and it loads and displays the icons perfectly. Note that I do not use any Font Awesome plugin built for WordPress.

/* Enqueue 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'); 
}

Despite my best research efforts, I was unable to find a solution to modify the categories widget.

16
  • 1
    Please clarify your question to explain how it is WordPress-specific, rather than merely CSS. Also, please edit your question to include what you have done/tried so far. How are you including/enqueueing the FontAwesome font? Jan 4, 2014 at 14:05
  • 1
    "This is WordPress specific due to me wanting to customize WordPress categories via the FUNCTIONS.PHP file" - given that the ultimate solution is still entirely CSS, the question still isn't WordPress specific. It merely happens in the context of WordPress. Your limitation of wanting a function to pop into functions.php, which excludes the most plausible answers, also makes this question too localized. Perhaps if you edited the question to focus on how to enqueue custom CSS, it would be on-topic for WPSE? Jan 6, 2014 at 21:04
  • 1
    The CSS content attribute isn't a background image, it's content. And a CSS solution is the best way to implement - even if you want to expose end-user options. What I'm trying to help you see is that your unnecessary and arbitrary constraints are making the problem unnecessarily difficult. Jan 7, 2014 at 0:53
  • 1
    "I do not really wish to have to put 25 lines of code into my CSS to display the different icons." - the real problem with this is that it makes your question too localized, because you restrict the best and most obvious solution: CSS. I simply can't fathom why 25 lines of CSS is less-desirable than multiple filters, and 50 lines of PHP string-replacement. Jan 7, 2014 at 14:54
  • 1
    "I don't know why we are still battling over something that has been answered." - because Stack Exchange sites are not support forums, but Question and Answer sites intended to build a knowledge base for general/universal application. Your arbitrary limitation makes the question not universally useful, which is why it renders the question as too localized. And while you're free to accept whatever answer best suits your needs personally, the accepted answer is, quite frankly, terrible for the vast majority of people who need to incorporate icon fonts. Jan 7, 2014 at 16:35

4 Answers 4

6
+100

Assumptions:

You don't explain how you want to install the Font Awesome package, so I just assume for the moment that you use the plugin Font Awesome Icons.

You wrote:

Before anyone says use a background image, I do not want to do that. I would like it to be physical.

so I assume you want to use the <i> tag directly, for example:

<i class="fa icon-caret-right"></i>

after each category link in the widget category list.

Idea:

You can use the wp_list_categories filter to modify the output of the widget category list.

Example:

Here is a simple example how to inject it into the category list via the wp_list_categories filter:

/**
 * Inject Font Awesome <i> tag after each widget category link
 *
 * @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' );
 });

This will give you an output similar to this one:

catlist

12
  • 1
    Not going to downvote a legitimate solution/attempt to help the OP, but really: using PHP string-replacement when a simple CSS rule would suffice seems to be overkill. Jan 6, 2014 at 21:05
  • 1
    @MrJustin thanks for the voting, I'm also impressed by the ingenious answers provided by the other users. ps: \s* matches any whitespace character, like space, tab and newline.
    – birgire
    Jan 6, 2014 at 22:53
  • 2
    @MrJustin could you please expand your question to detail these "future needs" for which CSS is insufficient? As it stands your question is specifically regarding CSS and is not tied to WordPress, and as such is sitting on shifty grounds for being closed as off-topic.
    – bosco
    Jan 7, 2014 at 2:43
  • 2
    I might also add that a WordPress filter was excessive enough given the scope of MrJustin's question. I hardly think leading him into regular expressions is a good idea... I can't help but feel regular expressions lie polar opposite to the simplicity of a static CSS implementation. I fear for any future WPSEpedian who comes here looking to display a single character out of an icon-font and winds up with a chunk of regular expressions in their backend. Have pity on the n00bs!
    – bosco
    Jan 7, 2014 at 2:47
  • 2
    one could also use: return str_ireplace( '</a>', ' <i class="fa fa-chevron-right"></i></a>', $output);
    – birgire
    Jan 7, 2014 at 5:40
5

This answer contains a fairly simple CSS solution.

Essentially, you'd add the following to your stylesheet:

.cat-item cat-item-7 {
     list-style-image: url('my-epic-news-icon');
}


cat-item cat-item-11 {
     list-style-image: url('my-epic-jquery-icon');
}

etc

Yes, it's not a very dynamic solution, but your categories aren't likely to change I suppose.

3
  • 2
    That the answer is pure CSS is indicative of the underlying question being off-topic for WPSE. That said: I think your CSS selectors do not have proper syntax. You should use .cat-item.cat-item-7 - or, since the same icon font image is intended to be used for all list items, just use .cat-item. Also: a font icon would use the content attribute, and would target the :after pseudo-class, such as: .cat-item:after { content: '\f18d'; }. Jan 4, 2014 at 14:25
  • Fair points. Yes I made a mistake in the syntax. Are we sure OP wants the same image, or different one per category? (That's how I understood it). I just wanted to propose the easiest solution, although that does take the qu/answer off-topic.
    – JMB
    Jan 4, 2014 at 14:32
  • 1
    Not the solution I was looking for as I had said I didn't want to use a background and that I would want the icon after the text. While it may not be a background, it's still an image, and not Font Awesome. Good solution, but not the solution for me.
    – MrJustin
    Jan 4, 2014 at 23:35
4

Assuming that you want to use the fa-chevron-right icon, you simply need to target the list item via CSS. Use the :after pseudo-class:

.list-item:after {
    font-family: FontAwesome; // or whatever the font awesome family is registered as
    content: '\f054';
}

Edit

So, to give an idea of how you might pass dynamic CSS (which can be easily adapted to a custom Plugin option) via a callback, here's an example:

(Note: "plugin" and "theme" are interchangeable below.)

First, we'll modify the CSS to target list items inside of a Widget specifically. WordPress adds a class, .widget, to the Widget container. So you can target that:

.widget .list-item:after {}

Or, if this will all be wrapped up in a Plugin that registers a custom Widget, then you can target the CSS class that you define in your custom Widget, via the $widget_ops array:

$widget_ops = array( 
    'classname' => 'custom-widget-classname', 
    'description' => __( 'Custom Widget Description', 'namespace' ) 
);

So, you can target that custom classname:

.custom-widget-classname .list-item:after {}

Or, if you want to target the core "Categories" Widget, you can use the .widget_categories class. We'll go with that approach for the example.

We're going to put it inside a callback, hooked into wp_head, though you can just as easily use wp_print_styles:

function pluginslug_fontawesome_styles() {
    // Code will go here
}
add_action( 'wp_head', 'pluginslug_fontawesome_styles' );

Inside, we're just going to output a stylesheet, with our rule from above:

function pluginslug_fontawesome_styles() {
    ?>
<script type="text/css">
.widget_categories .list-item:after {
    font-family: FontAwesome; // or whatever the font awesome family is registered as
    content: '\f054';
}
</script>
    <?php
}
add_action( 'wp_head', 'pluginslug_fontawesome_styles' );

At this point, you're done. Easy peasy. But, since you're already inside a PHP function, you can easily make this stylesheet dynamic, by using a variable:

function pluginslug_fontawesome_styles() {

    // Define list-style icon variable
    $list_item_icon = '\f054';

    // ...snip:
    content: <?php echo $list_item_icon; ?>;

So now, it's a simple matter to use a custom Plugin option value, just by passing it to the variable:

function pluginslug_fontawesome_styles() {

    // Get Plugin options, assumed to be an array
    $plugin_options = get_option( 'pluginslug_plugin_options' );

    // Define list-style icon variable
    $list_item_icon = $plugin_options['list_item_icon'];

    // Output stylesheet
    ?>
<script type="text/css">
.widget_categories .list-item:after {
    font-family: FontAwesome; // or whatever the font awesome family is registered as
    content: <?php echo $list_item_icon; ?>;
}
</script>
    <?php
}
add_action( 'wp_head', 'pluginslug_fontawesome_styles' );

So that's it! Dynamic CSS, outputting an actual icon (not a background image), pulling from a Plugin option.

And since it's just CSS, it's easily extensible to pretty much any selector you can imagine - not just limited to a list item inside of a Widget.

6
  • Very nice option, but I wanted a function. :)
    – MrJustin
    Jan 6, 2014 at 20:42
  • You know that you can wrap up CSS rules in a callback, and enqueue at wp_head or wp_print_styles, right? But that part of the implementation is a separate question and outside of the scope of the question as-written. Jan 6, 2014 at 21:01
  • Yes I do know how to enqueue. However, I don't want to use CSS. I know it's a quick and efficient way of doing it, and I do compliment you on that.. but maybe I should be using the words 'need a' instead of 'want a' when it comes to the function.
    – MrJustin
    Jan 6, 2014 at 21:19
  • Please see the edited question. I added an example to show how the entire thing really can be handled via CSS, dynamically, extensibly, and able to account for custom Plugin options. Jan 7, 2014 at 1:16
  • Right, but now, what if I wanted to have the 'icon' float to the right? In my normal CSS I have attached it to li a:after {content} and tried: text-align: right and it did nothing for me. What I mean by this, to clarify, is what if I wanted all of the icons on the right of the LI with the text on the left. Say the ul/li was set to 250px, the text is always a link, but I had it set to block. Then I added the 'icon' and wanted the icon to sit to the right of the li. With the <i...></i> I can easily float it.
    – MrJustin
    Jan 7, 2014 at 1:30
1

I would do it like this:

// If you're using the widget only on specific pages,
// you might want to use some appropriate conditions here
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 your desired icon here
    $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');

    // Since we're hijacking this filter, we just pass through its data
    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');

    // Since we're hijacking this filter, we just pass through its data
    return $output;
} // function wpse_128247_remove_filter
add_filter('wp_list_categories', 'wpse_128247_remove_filter');

First, we enqueue the font awesome styles. Then, we hijack some filters to add/remove our own filter for the category listing. That's it.


// EDIT:
Without the comments, adapted to the fact that you already have enqueued Font Awesome, using closures, and letting the filter remove itself, the code reads like the following:

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');

I would not call that overkill. But yes, my code consists of more lines than birgire's current solution.

3
  • Your solution wasn't bad, but an overkill compared to birgire's. I already have Font-Awesome enqueued, sorry I didn't specify.
    – MrJustin
    Jan 6, 2014 at 20:41
  • 2
    Yeah, that code is not an overkill, I will agree with that. It probably just looked like more with the 4 functions instead of 2, and the amount of commenting. I appreciate the commenting, I'm not downing that. It just looked like a lot more :).
    – MrJustin
    Jan 7, 2014 at 1:26
  • Since you are using remove_filter on the function that adds the icon it's only going to run a single time. This means an icon will only be added to the first item in the widget_categories list.
    – WPExplorer
    May 12, 2020 at 6:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.