WordPress.org

Make WordPress Core

Opened 5 years ago

Last modified 3 days ago

#37178 new enhancement

Add $cache_only parameter to get_option

Reported by: joostdevalk Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version:
Component: Options, Meta APIs Keywords: has-patch dev-feedback needs-unit-tests
Focuses: performance Cc:

Description

When you do get_option() and the option doesn't exist in the option cache, WordPress does a query to check whether that option exists and loads it. This is great as default behavior, but when you know that an option would have been autoloaded, you might not want that to happen.

I propose adding a parameter $cache_only, which defaults to false, which, when set to true, returns false when there is no option set in the cache. The "workaround" currently would be to set an empty option, but that means adding unnecessary data to the database.

Attachments (2)

37178.diff (1.3 KB) - added by joostdevalk 5 years ago.
Patch, first go.
37178.2.diff (1.1 KB) - added by michalzuber 5 years ago.
Rewrote a bit :) Don't know in which scenario it could be handy. That one select isn't so perf expensive. If somebody is using get_option he/she needs to know if it exists, that's default consideration for me from the function name.

Download all attachments as: .zip

Change History (7)

@joostdevalk
5 years ago

Patch, first go.

@michalzuber
5 years ago

Rewrote a bit :) Don't know in which scenario it could be handy. That one select isn't so perf expensive. If somebody is using get_option he/she needs to know if it exists, that's default consideration for me from the function name.

#1 in reply to: ↑ description @SergeyBiryukov
5 years ago

Replying to joostdevalk:

The "workaround" currently would be to set an empty option, but that means adding unnecessary data to the database.

Another workaround would be adding a pre_option_* filter for that option that returns an empty string or null to short-circuit the function and avoid the SQL query:

function wp37178_get_autoloaded_option( $option, $default = false ) {
	// prevent non-existent options from triggering multiple queries
	$notoptions = wp_cache_get( 'notoptions', 'options' );
	if ( isset( $notoptions[ $option ] ) ) {
		return $default;
	}

	$alloptions = wp_load_alloptions();

	if ( isset( $alloptions[$option] ) ) {
		$value = $alloptions[$option];
	} else {
		$value = wp_cache_get( $option, 'options' );
	}

	if ( ! $value ) {
		$value = null;
	}

	return maybe_unserialize( $value );
}
add_filter( 'pre_option_myoption', 'wp37178_get_autoloaded_option' );

#2 @SergeyBiryukov
5 years ago

  • Component changed from General to Options, Meta APIs

#3 @jipmoors
5 years ago

  • Keywords needs-unit-tests added

#4 @SergeyBiryukov
7 days ago

#54459 was marked as a duplicate.

#5 @desrosj
3 days ago

  • Milestone set to Awaiting Review

Readding a milestone. Seems like it was lost at some point.

Also, copying over some of my findings from exploring this in ticket:54459#comment:2:

I took a look and reacquainted with how get_option() works because I feel like this has come up somewhere for me in the past.

It seems there are a few ways to accomplish this already. Because this change would be an opt-in change, I'm wondering if these are better options because they don't require additional arguments to be added.

  • Using the pre_cache_alloptions filter, someone could check ! isset( $alloptions['myoption'] ) and add the default value for that option. wp_load_alloptions() fetches all options with autoload = 'yes' (unless there are no options set to autoload).
  • At some point during the bootstrap process after wp_load_alloptions() has been called (or after calling it early on), a dev could run code that checks the keys present in the alloptions cache, and add their own known autoload options with default values before updating that cache.
  • The same as previous, a dev could add their keys to the notoptions cache, and the function would fall back to returning the passed default value without a query.

Personally, I like option 3 because it allows a different default to be passed in different locations where get_option() is called if desired. A filter could be probably be added to allow someone to adjust the notoptions cache before it's updated to make this easier.

Another way to protect these extra queries is to have a list of registered options. But this is really the same thing as the alloption list, except it would include the ones that don't currently exist.

Note: See TracTickets for help on using tickets.