How to deactivate unused WordPress widgets

We all know and love WordPress widgets, both core and third-party. They give us and our customers the flexibility to “build” specific areas of a website dynamically, displaying anything we choose from an array of available options. This fact was even more important before page builders became prevalent, and may be overshadowed by the coming of Gutenberg, but for the time being, widgets are an integral part of WordPress.

There are times however, that we may need to restrict the selection of available widgets, rather than expand it. Perhaps a widget is irrelevant, or it causes more problems that it solves. Instead of trying to warn or educate your users about potential issues, something they (and you) will ultimately forget, you may opt to completely remove the widgets in question.

Unregister a single widget

According to the WordPress Codex, widgets should be registered on the ‘widgets_init‘ action. We’ll use the same action to unregister the widgets we don’t need, so that we don’t create any conflicts. Unregistering a widget is very simple; we just need to call unregister_widget() passing the widget’s class name as a parameter. As an example, we will unregister the Tag Cloud Widget. Note that the following code can live in a theme, in a child theme, or even in a plugin. It’ll just work.

add_action( 'widgets_init', 'my_theme_unregister_widgets', 100 );
function my_theme_unregister_widgets() {
	unregister_widget( 'WP_Widget_Tag_Cloud' );
}

Of course, you may include as many unregister_widget() calls as you need. Note that we should use a very low priority (bigger number) of 100, so that our code will execute after any code that may register any widgets. Usually, themes and plugins will register their widgets with a priority of 10 which is the default, or a bit later (20-50) in case they need to check if some other widget exists.

If you refresh your widgets screen now, you should see that the Tag Cloud widget is nowhere to be found. Hooray!

Let’s take this one step further, and investigate what other tricks we can perform.

Get a list of registered widgets

If you dive into the inner workings of register_widget() and unregister_widget() functions, you’ll see that they both use the global $wp_widget_factory, which is an instance of the WP_Widget_Factory class. This object publicly exposes the $widgets array, which holds an instance of all registered widgets. We can therefore var_dump() it to take glimpse of its contents.

array (size=39)
  'WP_Widget_Pages' => 
    object(WP_Widget_Pages)[1515]
      public 'id_base' => string 'pages' (length=5)
      public 'name' => string 'Pages' (length=5)
      public 'option_name' => string 'widget_pages' (length=12)
      public 'alt_option_name' => null
      public 'widget_options' => 
        array (size=3)
          'classname' => string 'widget_pages' (length=12)
          'customize_selective_refresh' => boolean true
          'description' => string 'A list of your site’s Pages.' (length=34)
      public 'control_options' => 
        array (size=1)
          'id_base' => string 'pages' (length=5)
      public 'number' => int 1
      public 'id' => string 'pages-1' (length=7)
      public 'updated' => boolean false
  'WP_Widget_Calendar' => 
    object(WP_Widget_Calendar)[1514]
      public 'id_base' => string 'calendar' (length=8)
      public 'name' => string 'Calendar' (length=8)
      public 'option_name' => string 'widget_calendar' (length=15)
      public 'alt_option_name' => null
      public 'widget_options' => 
...

We can clearly see that the keys of the array are the class names of the widgets, and the respective values are instances of those classes. If it’s too much output and we just want to examine the class names, we can do:

add_action( 'widgets_init', 'my_theme_unregister_widgets', 100 );
function my_theme_unregister_widgets() {
	global $wp_widget_factory;
	var_dump( array_keys( $wp_widget_factory->widgets ) );
}

This will give us a more manageable list:

array (size=39)
  0 => string 'WP_Widget_Pages' (length=15)
  1 => string 'WP_Widget_Calendar' (length=18)
  2 => string 'WP_Widget_Archives' (length=18)
  3 => string 'WP_Widget_Media_Audio' (length=21)
  4 => string 'WP_Widget_Media_Image' (length=21)
  5 => string 'WP_Widget_Media_Gallery' (length=23)
  6 => string 'WP_Widget_Media_Video' (length=21)
  7 => string 'WP_Widget_Meta' (length=14)
  8 => string 'WP_Widget_Search' (length=16)
  9 => string 'WP_Widget_Text' (length=14)
  10 => string 'WP_Widget_Categories' (length=20)
  11 => string 'WP_Widget_Recent_Posts' (length=22)
  12 => string 'WP_Widget_Recent_Comments' (length=25)
  13 => string 'WP_Widget_RSS' (length=13)
  14 => string 'WP_Widget_Tag_Cloud' (length=19)
  15 => string 'WP_Nav_Menu_Widget' (length=18)
  16 => string 'WP_Widget_Custom_HTML' (length=21)
  17 => string 'WC_Widget_Cart' (length=14)
  18 => string 'WC_Widget_Layered_Nav_Filters' (length=29)
  19 => string 'WC_Widget_Layered_Nav' (length=21)
  20 => string 'WC_Widget_Price_Filter' (length=22)
  21 => string 'WC_Widget_Product_Categories' (length=28)
  22 => string 'WC_Widget_Product_Search' (length=24)
  23 => string 'WC_Widget_Product_Tag_Cloud' (length=27)
  24 => string 'WC_Widget_Products' (length=18)
  25 => string 'WC_Widget_Recently_Viewed' (length=25)
  26 => string 'WC_Widget_Top_Rated_Products' (length=28)
  27 => string 'WC_Widget_Recent_Reviews' (length=24)
  28 => string 'WC_Widget_Rating_Filter' (length=23)
  29 => string 'CI_Widget_Socials' (length=17)
  30 => string 'CI_Widget_Contact' (length=17)
  31 => string 'CI_Widget_Schedule' (length=18)
  32 => string 'CI_Widget_Latest_Post_Type' (length=26)
  33 => string 'CI_Widget_Home_Latest_Post_Type' (length=31)
  34 => string 'CI_Widget_Home_Post_Type_Items' (length=30)
  35 => string 'CI_Widget_Buttons' (length=17)
  36 => string 'CI_Widget_Callout' (length=17)
  37 => string 'CI_Widget_Home_Hero_Callout' (length=27)
  38 => string 'CI_Widget_Home_Brands' (length=21)

From the list above we can distinguish the WordPress core widgets prefixed with “WP_”, WooCommerce widgets prefixed with “WC_”, and CSSIgniter widgets prefixed with “CI_”.

Whitelisting widgets

Unregistering one or more specific widgets, counts as blacklisting them. The opposite, whitelisting, is to exclude everything except a list of specifically allowed widgets. This may be desirable in a tightly controlled WordPress installation, so that no new widgets (from new plugins) will ever appear without the explicit approval of a developer.

In order to achieve that, we need to define an array with the whitelisted class names, and compare each registered widget against it. If it’s not in the array, it gets unregistered. In the following snippet, only the core Pages, Search and Text widgets are whitelisted, along with the theme’s Social widget.

add_action( 'widgets_init', 'my_theme_unregister_widgets', 100 );
function my_theme_unregister_widgets() {
	global $wp_widget_factory;

	$widgets = array_keys( $wp_widget_factory->widgets );

	$whitelist = array(
		'WP_Widget_Pages',
		'WP_Widget_Search',
		'WP_Widget_Text',
		'CI_Widget_Socials',
	);

	foreach ( $widgets as $class ) {
		if ( ! in_array( $class, $whitelist, true ) ) {
			unregister_widget( $class );
		}
	}
}

Conclusion

Unregistering widgets is a great way of tightly controlling what can be used in a WordPress website. However, it needs to be done in moderation and only on specific cases, as people will expect to find and be able to use certain widgets, especially users with previous experience on WordPress.

Let us know in the comments if you have any other tricks regarding WordPress widgets!

Leave a Reply

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