I'm trying to restrict the number of widgets from the "wp_inactive_widgets" sidebar to maximum 10, because the widgets admin page is incredibly slow:

add_filter('pre_update_option_sidebars_widgets', 'cleanup_inactive_widgets', 10, 2);

function cleanup_inactive_widgets($new, $old){
  if(!empty($new['wp_inactive_widgets']) && count($new['wp_inactive_widgets']) > 10)
    $new['wp_inactive_widgets'] = array_slice($new['wp_inactive_widgets'], -10, 10);

  return $new;

This works apparently, but the problem is that the widget instance options still remain in the database, regardless if the widget instance exists or not inside a sidebar...

Does anyone know a way to remove the widget options too?

I found out a solution:

Edit: in certain situations it seems to remove widgets from other sidebars too, I'm not sure what's causing this...

if(!empty($new['wp_inactive_widgets']) && count($new['wp_inactive_widgets']) > 10){

  // find out which widget instances to remove
  $removed_widgets = array_slice($new['wp_inactive_widgets'], 0, -10);

  // remove instance options
  foreach($removed_widgets as $widget_id)

      $instance = $GLOBALS['wp_registered_widgets'][$widget_id]['callback'][0]->number;
      $option_name = $GLOBALS['wp_registered_widgets'][$widget_id]['callback'][0]->option_name;

      $options = get_option($option_name);   // get options of all instances
      unset($options[$instance]);            // remove this instance's options
      update_option($option_name, $options);

  // keep only the last 10 records from the inactive widgets area
  $new['wp_inactive_widgets'] = array_slice($new['wp_inactive_widgets'], -10, 10);

return $new;
  • 1
    Could you write this as an A and mark it as accepted please? Thanks!
    – kaiser
    Aug 15, 2011 at 1:49
  • No because I found out it's not working correctly. It seems to be removing settings from other sidebars Aug 20, 2011 at 12:59
  • Then you should remove the "I found a solution" from the Q. Hm?
    – kaiser
    Aug 20, 2011 at 16:10
  • 1
    Updated Q. I'm going to give it another try when I have the time Aug 21, 2011 at 10:59
  • Have you tried to wrap it in a if ( is_admin() && /* page does here */ ) statement? I guess the point is that you're globally removing those widgets on each request everywhere. Ok: Edit. After some thinking about it, your problem might be that you use update_option which is accessible globally (don't know the exact internals for widgets). Maybe you could update a custom limited widgets option and "feed" the inactive widgets area with your custom option to get around interference.
    – kaiser
    Oct 22, 2011 at 14:02

1 Answer 1


Tested under v3.2.1:

$sidebars = wp_get_sidebars_widgets();
if(count($sidebars['wp_inactive_widgets']) > 10){
    $new_inactive = array_slice($sidebars['wp_inactive_widgets'],-10,10);

    // remove the dead widget options
    $dead_inactive = array_slice($sidebars['wp_inactive_widgets'],0,count($sidebars['wp_inactive_widgets'])-10);
    foreach($dead_inactive as $dead){
        $pos = strpos($dead,'-');
        $widget_name = substr($dead,0,$pos);
        $widget_number = substr($dead,$pos+1);
        $option = get_option('widget_'.$widget_name);

    // save our new widget setup
    $sidebars['wp_inactive_widgets'] = $new_inactive;

The above code limits the inactive sidebar to the last 10 widgets, and only the inactive sidebar. It also removes the options for the widgets that have been deleted.


Your Answer

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

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