How to Filter the Output of any WordPress Widget

Sometimes developers need to modify the HTML output of a widget that does not have its own output filter built-in, or does not provide the necessary hooks or filters for doing so. WordPress built-in widgets, I’m looking at you! WordPress provides no native way to filter the final output of any widget, so here are some workarounds that I’ve found.

Modify the widget’s source files.
Obviously this is not a good method, as your modifications will be lost if WordPress, or the plugin creating the widget is updated.

Copy the widget into your own plugin or theme and modify it there.
You could copy the entire original widget code, creating your own new widget in the process with your own modifications, or you could copy only the widget’s display callback function into your theme or plugin, extending the original widget class. This is better than modifying the original core files, in that your code will not be overwritten by updates. You would also have complete control over the generated generated. However, this brings along its own set of problems, chiefly that you now need to maintain all of this new code, porting over updates from the original widget source into your own copy, if the original code is updated with security patches or feature additions. That could be a maintenance nightmare down the road. In addition, the use case described in this post is for relatively minor modifications to a widget’s output, such as changing a CSS class, adding some additional markup, or some other relatively minor modification. Copying the original widget’s code into your own plugin or theme, in order to make those types of minor modifications, is neither efficient nor elegant.

Use output buffering the capture the output of the entire widget area, and run filters on that.
Now we’re getting somewhere. You can use PHP output buffering to save the entire widget area output to a string, and run a filter on that. This method still has some drawbacks, but it may be suitable for some people so here’s what it would look like:

In your sidebar.php template file, this would replace the dynamic_sidebar() function:

dynamic_sidebar( 'my-sidebar-id' );
$sidebar_output = ob_get_clean();
echo apply_filters( 'my_sidebar_output', $sidebar_output );

Then you can do something like this in your theme’s functions.php template file, or in your own custom plugin:

function my_widget_filter( $sidebar_output ) {
     * Perform some kind of search and replace here on $sidebar_output.
     * Regular Expressions will likely be required in order to restrict your
     * modifications to only the widgets you wish to modify, since $sidebar_output
     * contains the output of the entire sidebar, including all widgets.
    return $sidebar_output;
add_filter( 'my_sidebar_output', 'my_widget_filter' );

The drawbacks with this method are that it doesn’t work in the WordPress Theme Customizer, so any modifications you would make to your widgets with the widget area filter would not appear there. It also requires that the theme have this widget area filtering support built-in, so you would need to use your own custom theme, or modify your existing theme in order to add support for this method. It also requires you to use Regular Expressions in order to target only the widgets you wish to modify, because the filter is run not on individual widgets, but on the output of the entire sidebar, which contains the output from all widgets that are active there.

Replace the widget’s original display callback function with a custom function, which then runs the original display callback function, but with filters.
This is the technique that works best for me. It still seems a bit “hack-ish”, so it would be nice if WordPress provided this natively. However, this is the best we’ve got for now. Basically, the widget’s original display callback function is overridden with a new custom function, which runs the widget’s original callback function, but uses output buffering to capture the output, and run it through a filter before displaying it. This method is already used by the Widget Logic plugin in its widget_content filter, so it’s not an entirely new concept. However, there may be times that a developer needs to filter a widget’s output, but doesn’t need the widget visibility feature of Widget Logic. Additionally, plugin or theme developers requiring widget output filtering should not need to require their users to install Widget Logic in order for their theme to work properly. For those cases, here is the code which can be used in a theme or plugin, which will provide a widget_output filter, along with the widget type and unique widget ID as parameters:

First, we need to replace the widget’s original display callback function with a custom function of own:

function my_filter_dynamic_sidebar_params( $sidebar_params ) {
    if ( is_admin() ) {
        return $sidebar_params;
    global $wp_registered_widgets;
    $widget_id = $sidebar_params[0]['widget_id'];
    $wp_registered_widgets[ $widget_id ]['original_callback'] = $wp_registered_widgets[ $widget_id ]['callback'];
    $wp_registered_widgets[ $widget_id ]['callback'] = 'my_custom_widget_callback_function';
    return $sidebar_params;
add_filter( 'dynamic_sidebar_params', 'my_filter_dynamic_sidebar_params' );

Next, we need to create the function referenced in the previous block of code, which will in turn run the widget’s original display callback function, but will capture its output using PHP output buffering. Then, the widget_output filter will be run on the widget’s generated HTML markup, before being output to the page:

function my_custom_widget_callback_function() {
    global $wp_registered_widgets;
    $original_callback_params = func_get_args();
    $widget_id = $original_callback_params[0]['widget_id'];
    $original_callback = $wp_registered_widgets[ $widget_id ]['original_callback'];
    $wp_registered_widgets[ $widget_id ]['callback'] = $original_callback;
    $widget_id_base = $wp_registered_widgets[ $widget_id ]['callback'][0]->id_base;
    if ( is_callable( $original_callback ) ) {
        call_user_func_array( $original_callback, $original_callback_params );
        $widget_output = ob_get_clean();
        echo apply_filters( 'widget_output', $widget_output, $widget_id_base, $widget_id );

With that in place, you can do something like this in a plugin or theme, to modify the output of any widget:

function my_widget_output_filter( $widget_output, $widget_id_base, $widget_id ) {
    /* To target a specific widget ID: */
    if ( 'target_widget_id' == $widget_id ) {
        // Apply your desired search and replace operations here
    /* To target all widgets of a particular type: */
    if ( 'target_widget_type' == $widget_type ) {
        // Apply your desired search and replace operations here
    return $widget_output;
add_filter( 'widget_output', 'my_widget_output_filter', 10, 3 );

This code can be added to a plugin or theme to enable the filtering of widget output, and is also available in plugin form in the official WordPress plugin repository.

3 thoughts on “How to Filter the Output of any WordPress Widget

  1. Pretty awesome. Definitely would love to see something like this in core…. I noticed your plugin hasn’t had much action on it yet. I posted some answers in stackexchange referencing to it. Hopefully we can get more support for it!

    The only thing I think this is missing (or at least what I can’t figure out), is a way to run the filter on widgets only of a specific sidebar.

    This must be possible, since sidebar ‘id’ is one of the parameters in the ‘dynamic_sidebar_params’ filter. However, I can’t seem to get a grasp on how to do it…

    function my_widget_output_filter( $widget_output, $widget_type, $widget_id, $sidebar_id ) {
    if ( ‘categories’ == $widget_type && ‘primary-sidebar’ == $sidebar_id ) {
    $widget_output = str_replace(”, ”, $widget_output);
    $widget_output = str_replace(‘<li class="cat-item cat-item-', '<li class="list-group-item cat-item cat-item-', $widget_output);
    $widget_output = str_replace('(', ' ‘, $widget_output);
    $widget_output = str_replace(‘)’, ‘ ‘, $widget_output);
    return $widget_output;
    add_filter( ‘widget_output’, ‘my_widget_output_filter’, 10, 3 );

    • Thanks for the comment. You’re right, being able to check which sidebar the widget is in isn’t currently a feature, but I think it’s a great idea and something that should be added. Next time I have a free hour or two I’ll see what I can do to add in that functionality to the plugin. I’m sure there’s a way it can be done.

Leave a Reply

Your email address will not be published. Required fields are marked *