Make WordPress Core

Opened 11 years ago

Closed 9 years ago

Last modified 9 years ago

#26876 closed defect (bug) (fixed)

Default widgets causing unnecessary database queries

Reported by: codydh's profile codydh Owned by: wonderboymusic's profile wonderboymusic
Milestone: 4.4 Priority: normal
Severity: minor Version: 3.0
Component: Widgets Keywords: has-patch
Focuses: Cc:

Description

I wasn't able to find this bug reported, so I hope it's not a duplicate. Apologies in advance if it is!

It seems that WordPress is checking the options table of the database for four widgets, widget_pages, widget_calendar, widget_tag_cloud, and widget_nav_menu, even when these widgets aren't activated, and even when the theme has no widget area:

Query: SELECT option_value FROM xy_options WHERE option_name = 'widget_pages' LIMIT 1
Query: SELECT option_value FROM xy_options WHERE option_name = 'widget_calendar' LIMIT 1
Query: SELECT option_value FROM xy_options WHERE option_name = 'widget_tag_cloud' LIMIT 1
Query: SELECT option_value FROM xy_options WHERE option_name = 'widget_nav_menu' LIMIT 1

One easy fix is to add the following lines to functions.php:

add_action( 'widgets_init', 'remove_unneeded_widgets' );
function remove_unneeded_widgets() {
    unregister_widget('WP_Widget_Pages');
    unregister_widget('WP_Widget_Calendar');
    unregister_widget('WP_Widget_Tag_Cloud');
    unregister_widget('WP_Nav_Menu_Widget');
}

Much of this information was corroborated by a StackExchange post (http://wordpress.stackexchange.com/questions/81785/remove-unnecessary-mysql-query/82420#82420) from early 2013, indicating this may have been around for a while.

Attachments (4)

26876.diff (691 bytes) - added by kovshenin 11 years ago.
26876.2.diff (675 bytes) - added by MikeHansenMe 9 years ago.
Refreshed
26876.3.patch (1.7 KB) - added by dlh 9 years ago.
26876.3.diff (1.8 KB) - added by wonderboymusic 9 years ago.

Download all attachments as: .zip

Change History (15)

#1 @johnbillion
11 years ago

  • Keywords needs-patch added
  • Version changed from 3.8 to 3.0

I've noticed this too. It's caused by the fact that these options aren't present in the database by default, which means they're not present in the array returned by wp_load_all_options(), which means get_option() falls back to a second database query to look for the value.

Off the top of my head, we could solve this by inserting a default option value for each of these keys (in the upgrade routine), or we could avoid trying to fetch options for widgets that aren't in use.

@kovshenin
11 years ago

#2 @kovshenin
11 years ago

  • Keywords has-patch added; needs-patch removed

Nice catch! This is not only related to core widgets. Any registered widget without a database entry will fire a query during widgets_init. We could solve it for core widgets by adding some fields to populate_options(), however I think we can do better than that :)

During _register() we really only need that setting to determine how many times _register_one() should be called, so for widgets that haven't been used (not in a sidebar and not in the inactive widgets array, and no db entry) that's always one.

26876.diff attempts to fix this with is_active_widget().

This does mean that an additional regex will run during widgets_init for every available widget, but I don't think that will ever be a concern since we use _get_widget_id_base and the regex is most likely cached by then.

@MikeHansenMe
9 years ago

Refreshed

#4 @westonruter
9 years ago

Note that I think it would be ideal for performance reasons if widgets were only registered if they are active for the current context, i.e. after sidebars_widgets has been filtered or when dynamic_sidebar is called. I'm working on a site that has hundreds of widgets, maybe thousands when factoring in inactive widgets, and yet only a dozen are actually used on a given page.

Last edited 9 years ago by westonruter (previous) (diff)

#5 @westonruter
9 years ago

#33292 was marked as a duplicate.

@dlh
9 years ago

#6 @dlh
9 years ago

26876.3.patch would have WP_Widget::get_settings() call WP_Widget::save_settings() with an empty array when no option is found in the database and the alt_option_name property isn't set. On the next request, the widget option would be autoloaded and not generate another query.

#8 @wonderboymusic
9 years ago

  • Milestone changed from Awaiting Review to 4.4

#9 @wonderboymusic
9 years ago

  • Owner set to wonderboymusic
  • Resolution set to fixed
  • Status changed from new to closed

In 35100:

Widgets: when getting settings, and none exist, set them to empty to avoid extraneous database queries on subsequent requests.

Adds unit tests.

Props kovshenin, MikeHansenMe, dlh.
Fixes #26876.

#10 @westonruter
9 years ago

In 35272:

Widgets: Modify unit test assertion to be compatible with widget_nav_menu option being filtered by plugin to return ArrayIterator.

Modifies assertion added in [35100].

See #26876.
See #32474.

#11 @westonruter
9 years ago

I made the change in [35272] because the change in [35100] broke unit tests for the Customize Widgets Plus plugin's Widget Posts module.

Note: See TracTickets for help on using tickets.