While it’s not technically possible to override a WordPress widget (and remember WooCommerce widgets are nothing more than WordPress widgets), WooCommerce is just so extendable and pluggable and flexible, that some widget functionality can be nearly completely overridden just using the standard WooCommerce template files and/or template functions. For the widgets that aren’t as pluggable, or if you need greater control, you have the option to un-register a core WooCommerce widget and subclass it, or even duplicate it and change it wholesale, all without modifying a single core file, thus maintaining a clean upgrade path.

Your widget override options, listed in order of preference, starting with the most preferred, down to the least preferred but most powerful, are as follows:

  1. Use the widget_display_callback filter to alter configuration details
  2. Hook into any provided filters/actions
  3. Override a WooCommerce template file
  4. Override a pluggable WooCommerce template function
  5. Subclass, modify and register a widget
  6. Duplicate, modify and register a widget

The rest of this article will be devoted to describing, with code examples where applicable, these six options. Note also that while this is written with WooCommerce in mind, most of the strategies described are completely applicable to any WordPress widgets.

Option 1 – Hook into widget_display_callback filter

You can hook onto the widget_display_callback filter to change the configuration settings of a widget on-the-fly. Not really sure how useful this is, and I’m not covering it in great detail as this article is geared towards more substantial behavior overrides. Still, a quick example of how you might use it, here changing the Cart widget title:

add_filter( 'widget_display_callback', 'rename_widget', 10, 3 );

function rename_widget( $settings, $widget, $args ) {

  if ( get_class( $widget ) == 'Custom_WooCommerce_Widget_Cart' ) {
    $settings['title'] = 'My Cart';
  }

  return $settings;
}

Option 2 – Hook into widget filters/actions

I didn’t include this method initially as I don’t know how many widgets actually provide their own action/filter hooks for modifying functionality, but there’s certainly no reason that they couldn’t, and if they should, this would be an ideal way to change the widget behavior. I won’t cover the basics of using WordPress actions/filters, for that check out the WordPress Plugin API codex page.

Option 3 – Override a WooCommerce widget template file

This is the next most preferred means of changing a WooCommerce widget’s behavior, but it’s not always possible. To determine whether you can use this method, you’ll have to inspect the widget class in question. Lets use the WooCommerce Cart widget as an example, which produces a mini cart like the following when active:

The code for this widget can be found at woocommerce/widgets/widget-cart.php. If we take a look at that file, we’ll find that it doesn’t contain much beyond the boilerplate widget code, though it does contain the following line:

$woocommerce->mfunc_wrapper( 'woocommerce_mini_cart()', 'woocommerce_mini_cart', array( 'list_class' => $hide_if_empty ? 'hide_cart_widget_if_empty' : '' ) );

Without diving into the specifics of what’s going on here, suffice it to say that this results in a call to the woocommerce_mini_cart() function, which will do most of the work of creating this widget on the frontend. When we look at the woocommerce_mini_cart(), found in woocommerce/woocommerce-template.php, we see that it in turn does very little other than loading cart/mini-cart.php:

woocommerce_get_template( 'cart/mini-cart.php', $args );

Which you can find at woocommerce/cart/mini-cart.php and actually contains the code that renders that mini cart widget.

Now this may seem like a lot of effort or unnecessary code just to display a mini cart, but what this design provides is quite a lot of flexibility, with multiple avenues for modifying the widget behavior. Thanks to all that flexibility we can completely change the look and feel of this widget by simply overriding the mini-cart.php template file. This is something I’ve covered fully in another article, but the overview is to create a directory named woocommerce within your theme, copy over the template file in question, and modify things to our hearts content. In this example we’d copy woocommerce/templates/cart/mini-cart.php to yourtheme/woocommerce/cart/mini-cart.php and change whatever we want in that file. The template file in the theme will be used in place of the core WooCommerce template.

Option 4 – Override a plugable widget template function

This method is quite related to the template file method described in the previous section. If you’ve read through and paid attention to Option 3, you’ll remember the function woocommerce_mini_cart(), found in woocommerce/woocommerce-template.php which loaded the mini-cart.php template file. This function is known as a pluggable function because it can be replaced with your own custom version. The full function looks like the following:

if ( ! function_exists( 'woocommerce_mini_cart' ) ) {

  function woocommerce_mini_cart( $args = array() ) {

    $defaults = array( 'list_class' => '' );
    $args = wp_parse_args( $args, $defaults );
    woocommerce_get_template( 'cart/mini-cart.php', $args );

  }

}

Thanks to that function_exists() check, we are actually given the opportunity to “plug-in” our own function implementation before this one is loaded; hence the term “pluggable”. We can do so by simply copying this function to our theme’s functions.php and making whatever changes we might want, including loading the same or perhaps an entirely different template file.

Keep in mind that not all WooCommerce widgets are structured to use template functions and files, so you’ll have to actually look at the code for the widget in question and determine whether this override option is available to you. If it is, and allows you to do what you need, that’s great as like the previous options it’s very easy, safe, and doesn’t impact WooCommerce upgrades.

Option 5 – Subclass, modify and register a widget

Among the benefits of this option are: the fact that we can do this with any widget regardless of whether it uses a pluggable template function, by subclassing we can inherit some behavior while overriding other, we can change anything about the plugin’s behavior, and this is quite upgrade-safe. That is unless your child class depends on a part of the parent widget implementation which happens to change in a subsequent release; something that is possible but probably unlikely, and could be addressed with the final option, described after this one.

The basic recipe for the subclass method is as follows:

  1. Subclass the widget in question in a new widget class, changing whatever functionality you desire.
  2. Unregister the widget in question
  3. Register your new widget
  4. Use the new widget!

As an example, lets say we want to change the WooCommerce Best Sellers widget, which displays a list of the best selling products on your site. What we want to change about this widget is immaterial, the basic steps will remain the same. First we take a look at the widget code, which can be found at woocommerce/widgets/widget-best_seller.php to determine whether we can use one of the more preferred modes of overriding described above. It’s pretty obvious that the bulk of code, both for accessing the database, as well as rendering the best sellers list, is contained right within the widget() method, and with no real filter/action hooks, options 1-4 are out. In addition to the widget() method, there are a number of other methods such as the constructor and widget form display, which perhaps we don’t care about changing, hence making a subclass the ideal solution as we can rely on the parent for the implementation of those methods, and focus on just changing the main widget() method to do whatever it is we need.

So we’ll start by creating a new file in our theme named: my-theme/widgets/widget-best_sellers.php, and containing a new class class that extends WC_Widget_Best_Sellers and copying in the entire widget() method from woocommerce/widgets/widget-best_seller.php:

class Custom_WC_Widget_Best_Sellers extends WC_Widget_Best_Sellers {

  function widget( $args, $instance ) {
    // copy the widget function from woocommerce/widgets/widget-best_seller.php
  }

}

Then add the following code to your theme’s functions.php to unregister the WooCommerce Best Sellers widget and register our custom one in its place:

add_action( 'widgets_init', 'override_woocommerce_widgets', 15 );

function override_woocommerce_widgets() {
  // Ensure our parent class exists to avoid fatal error (thanks Wilgert!)

  if ( class_exists( 'WC_Widget_Best_Sellers' ) ) {
    unregister_widget( 'WC_Widget_Best_Sellers' );

    include_once( 'widgets/widget-best_sellers.php' );

    register_widget( 'Custom_WC_Widget_Best_Sellers' );
  }

}

Now you’ll be able to use this new widget in exactly the same manner as the old one, and change any of the functionality you need in the widget() method. There will be no confusion in the admin UI as there will only be one version of the Best Sellers widget shown; your custom version. Future updates of WooCommerce should be relatively painless as you haven’t actually modified any core files.

Option 6 – Duplicate, modify and register a widget

This approach is exactly the same as option 5, except you’ll need to copy the entire parent widget file over, and you won’t be extending from it as we did in the previous option. Here we’re literally creating an entirely new widget and swapping it in place of the old, so it’s fairly brute force, but on the other hand does not rely on any implementation details of the original widget. The same basic code is used to unregister and register the widgets.

Conclusion

And so there you have it, 6 different ways of seamlessly and safely modifying widget behavior. I’d be curious to hear if you end up overriding any widgets, WooCommerce or otherwise, which widgets you change and what for; let me know in the comments section below!

Published by Justin Stern

Justin is one of our co-founders, and is our resident overengineer. He likes to write developer tutorials and make black magic happen in our plugins. He thinks that writing code is a lot easier than writing words.

54 Comments

  1. Hi, Would it be possible to hack into a cart widget to use ajax to query the content dynamically? When caching the whole woocommerce website using varnish or similar, cart widget stays cached which is not good.

    Thanks

    • Hey Jozef, I would think it should certainly be possible. I’ve never actually used varnish or any of the cacheing plugins, so I don’t know exactly what’s involved or what it would look like, but I don’t see why it couldn’t be done.

    • Hi,

      You need to change the browsers cache to 0 seconds to solved all “Full Page Cache” plugin to make eCommerce website dynamically. The page load performance remain unchanged.

      You take the risk to set 5 seconds for browsers cache. For me that not much different.

      Cheers

    • Hi Justin, Thanks for this post. Actually I’m creating a new widget based on the core woocommerce’s Mini Cart Widget, so I have copied the mini widget class from core to my theme’s widget file and created a custom template based on core’s mini-cart.php and modified code inside this template. but in core widget file the code which calls that template file is just echo ‘

      ‘; you can see it at github https://github.com/woothemes/woocommerce/blob/master/includes/widgets/class-wc-widget-cart.php on line 68. My problem is how to tell WooCommerce to load my template for custom widget at this point, now it calls core template which is obvious. I don’t want to code the whole mini cart logic over there. Thanks in advance.

  2. hi. thanks for this post, it very helpful for me
    i used method #5, but in the widget settings lost widget name

    • i used translated version woocommerce, maybe i need include translated files in my theme folder (how?) or may manual translate widget?

      • I solved the problem
        Need rename the “function WooCommerce_Widget_Best_Sellers()” to “function Custom_WooCommerce_Widget_Best_Sellers()” in the new widgets/widget-best_seller.php

        sorry for my bad english(

  3. Actually to make it upgrade-safe when extending an existing widget class you should check if the class exists. Because in the upgrade process the Woocommerce plugin is disabled which causes a fatal error. You can use the class_exists(‘woocommerce_class_name’) php function to do this.

  4. Justin, I know this is immensely off-topic but could you help me find some simple code to add a custom option field to the general settings tab of the woocommerce admin area? Trying to avoid re-inventing the wheel here.

  5. Would this work to change the WooCommerce Search Products widgets to search for Order Numbers instead of Products? I’d like to have a dynamic widget – visible only to the shop owner – on the front page so he can quickly search for an order.

  6. Thank you for this very useful article, really appreciate it.

  7. Thank you ! You just saved my life !
    I had to customize the woocommerce random product widget and keep woocommerce updatable.
    option 4 worked fine for me. Thank you again !

  8. Hi,

    I am trying to add a woocommerce widget (layered nav) into my bookstore, but it’s not really working.

    I am using this code:

    `add_action( ‘woocommerce_before_shop_loop’, ‘widgetized_shop_filter’, 50 );

    function widgetized_shop_filter() {
    global $woocommerce;

    echo ”;
    the_widget(‘WC_Widget_Layered_Nav’, ‘title=&attribute=irauthor&query_type=AND&display_type=dropdown’);
    echo ”;

    }`

    It doesn’t sort the books, and on category pages, I get this error: Warning: array_merge() [function.array-merge]: Argument #1 is not an array in /home/riztuf/indireads.com/wp-content/plugins/woocommerce/classes/widgets/class-wc-widget-layered-nav.php on line 56

    Do you think you could help me out with this?

  9. As SM, I would like to add the layered nav on the top of page, alongside the “sort by”, based on my products attributes.
    Any idea someone?

    • Hi,

      Try covert you layer nav to shortcode and paste to page description/excerpts, and provided you must use with yoast seo’s meta description, if not your page description will display the shortcode (refer page resources).

      I had made 3 WC dropdown widget as shortcode and pasted into page excerpt, which just below breadcrumbs and sort by for mobile view only.

      Good Luck.

      Cheers ^.^

  10. After an hour of trying to integrate option 5 for the Best Sellers widget I almost gave up.
    Turns out Woocommerce has changed the name of the class!

    So instead of this class name:
    WooCommerce_Widget_Best_Sellers
    it should be this:
    WC_Widget_Best_Sellers

    Replace where necessary.

  11. Hi, I’m trying to make this work with my featured products widget (class-wc-widget-featured-products.php) but I can’t see the widget () method that you mention here…

    “So we’ll start by creating a new file in our theme named: my-theme/widgets/widget-best_sellers.php, and containing a new class class that extends WC_Widget_Best_Sellers and copying in the entire widget() method from woocommerce/widgets/widget-best_seller.php:”

    Should I copy over all of the “class WC_Widget_Featured_Products extends WP_Widget {” method and place it inside this:

    class Custom_WC_Widget_Best_Sellers extends WC_Widget_Best_Sellers {
    function widget( $args, $instance ) {
    // copy the widget function from woocommerce/widgets/widget-best_seller.php
    }
    }

    Any help will be greatly appreciated!

    Thank you so much for this tutorial!
    I’ve been looking for a way to change this widget while still keeping it update proof!

  12. Hello everybody,

    I have a small problem. I have tried to translate a minicart http://www.eyeloly.com/ but I don´t know what to do to fix it. I made a translation in mini-cart.php but it doesn´t work. I tried to make .po and .mo translation but still doesn´t work.
    Anyone knows what to do?

    Thank you,
    Jay

    • Localization is a huge pain, and something I’ve written about more than once: https://www.skyverge.com/blog/tag/localize/

      To translate a string within WooCommerce core you’d need to generate an mo file and drop it into woocommerce/i18n/languages/ Of course when you update WooCommerce it could be lost, so if it’s a good translation it’s best to contribute it back to WooCommerce so it can be included in the next release.

  13. Thanks for the nice how to!

    Maybe I’m just missing a point here, but I’m having some problems.
    I would like to create a new widget for Woocommerce. I have a child theme for changes to my site, so I thought I would just add the widget code in the functions.php file for now.

    I added the entire widget class in my functions.php file, but when I do I get this error: Fatal error: Class ‘WC_Widget’ not found in /home/wordpress/wordpress-3.8.1/wp-content/themes/gt3-wp-shopper-child/functions.php on line 5

    I guess woocommerce hasn’t been loaded yet, but how do I add a new widget then?

    • Yep, you’ll need to wrap your class inside an action that’s hooked into widgets_init so something like:


      function load_my_custom_widget() {
      // define your class, etc
      }
      add_action( 'widgets_init', 'load_my_custom_widget' );

  14. In the mini cart image posted above, there is a bracketed (ex-tax) immediately after the Subtotal price. I’ve also been trying to add this to my mini cart, but can’t get it to appear no matter what I do.
    My path to the mini-cart.php file is:
    wp-content/themes/themename/woocommerce/cart/mini-cart.php

    All I need is the (ex-tax). It would appear, at first glance, to be an easy edit. However, I’m now on the verge of giving up. I must be making a mistake somewhere. Would you be able to point me in the correct direction?
    Many thanks 🙂

    • You’ll want to add your (ex tax) label here — hope that helps!

      • Thanks Max. I appreciate it. That’s exactly the line I was trying to edit. I’ve been inserting the label but it never shows up for some reason. It’s all very frustrating.

  15. Thanks for deleting my post. It was just a simple call for help. Have a nice weekend.

  16. Hey max any idea how to change the woocommerce dashboard widget title? They updated the dash widget in 2.1 and I can’t find any reference in their docs. Thanks!

  17. Hi – wondering if you could help me change the order of the WooCommerce Tabs Manager on my product page. I want to put the tabs above the pricing / add to cart section, and I have searched literally hundreds of posts, but I haven’t had any luck.

    I am working in my functions.php file and have tried:

    remove_action( ‘woocommerce_single_product_summary’, ‘woocommerce_output_product_data_tabs’, 10 );

    which doesn’t do anything. However, if I change this to:

    add_action( ‘woocommerce_single_product_summary’, ‘woocommerce_output_product_data_tabs’, 5 );

    it displays 2 tab groups. Any suggestions?

    • Hey there, this isn’t controlled by the Tab Manager, but rather the theme / WooCommerce product page template – Tab Manager simply adds tabs where the WooCommerce tabs are located. You could remove / re-add some of the actions that make up the product page to change this display, but it may be labor-intensive to get it to look right.

  18. Thank you so much for writing this article. I was really stuck on this, and your article helped me understand.

  19. I want to add remove button for each product showing on cart widget & a quantity box how can i do this?

  20. Hi, I am use option 6 method to register new widget of WooCommerce Product Categories into my theme folder, i am plan to create specific product category widget (with “Exclude a category from the WooCommerce category widget” Snippets from http://www.wpexplorer[.]com/best-woocommerce-snippets/ #5 snipptes).

    add_action( ‘widgets_init’, ‘Business_And_Finance_Categories’ );
    function Business_And_Finance_Categories() {
    if ( class_exists( ‘WC_Widget_Product_Categories’ ) ) {
    unregister_widget( ‘WC_Widget_Product_Categories’ );
    include_once( ‘widgets/widget-product-categories.php’ ); //link to my theme widget path
    register_widget( ‘Business_And_Finance_Categories’ );
    }
    }

    Look like successes register widget, but I can find the new product category widget shown up at appearance > widgets, Need to help here? Thousand thanks!

    Can I change the widget_name and widget_id from class-wc-widget-product-categories.php?

    And, is that possible to use “Exclude a category from the WooCommerce category widget” Snippets? If yes! Any guide?

    Thanks again

    • Your approach certainly looks right. I guess just make sure that your custom widget has a class name of Business_And_Finance_Categories and I’d think it should work

  21. mini cart widget not showing in cart and checkout pages…
    how to solve it?
    I am using Mystyle theme in my wordpress website

  22. I just need to show the best sellers in a vertical list one column is their any easy wasy to do this in a sidebar ?

  23. I’m trying to duplicate WC_Widget_Layered_Nav but it’s based on a $_chosen_attributes array that is initialized only if there’s a woocommerce_layered_nav widget active (in class-wc-query.php).
    I guess I can only override it (option 5) or duplicate a lot of more code to handle the attributes parameters in the query of the loop shop.
    Am I right?
    Thanks in advance

  24. I’ve been searching high and low to try and find how to change the default text in the “Woocommerce Product Categories” widget. By default it shows “select a category” but I want to be able to change that text. Do you know where I’d edit that?

  25. I have been trying to alter the href of my woocommerce sidebar cart widget by looking for the appropriate php file and manually overwriting it, and adding that as a child – but to no avail.

    Is there any way I can add some function to manually alter the href of the “Go to checkout”-button of the built in woocommerce sidebar cart?

    Would love to get an answer! 🙂

    • This can’t really be done via pure PHP since the checkout link uses WC()->cart-get_checkout_url() — that’s filterable, but there’s no way to scope it solely to use within the widget (unless you’re okay with changing it globally, then use that filter 🙂 ). A jQuery solution to target the link and update the href would be straight-forward though, as the cart widget uses unique CSS classes.

Hmm, looks like this article is quite old! Its content may be outdated, so comments are now closed.