wp/wp-includes/option.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
    27  * In most cases non-string scalar and null values will be converted and returned
    27  * In most cases non-string scalar and null values will be converted and returned
    28  * as string equivalents.
    28  * as string equivalents.
    29  *
    29  *
    30  * Exceptions:
    30  * Exceptions:
    31  *
    31  *
    32  * 1. When the option has not been saved in the database, the `$default` value
    32  * 1. When the option has not been saved in the database, the `$default_value` value
    33  *    is returned if provided. If not, boolean `false` is returned.
    33  *    is returned if provided. If not, boolean `false` is returned.
    34  * 2. When one of the Options API filters is used: {@see 'pre_option_$option'},
    34  * 2. When one of the Options API filters is used: {@see 'pre_option_$option'},
    35  *    {@see 'default_option_$option'}, or {@see 'option_$option'}, the returned
    35  *    {@see 'default_option_$option'}, or {@see 'option_$option'}, the returned
    36  *    value may not match the expected type.
    36  *    value may not match the expected type.
    37  * 3. When the option has just been saved in the database, and get_option()
    37  * 3. When the option has just been saved in the database, and get_option()
    65  *
    65  *
    66  * @since 1.5.0
    66  * @since 1.5.0
    67  *
    67  *
    68  * @global wpdb $wpdb WordPress database abstraction object.
    68  * @global wpdb $wpdb WordPress database abstraction object.
    69  *
    69  *
    70  * @param string $option  Name of the option to retrieve. Expected to not be SQL-escaped.
    70  * @param string $option        Name of the option to retrieve. Expected to not be SQL-escaped.
    71  * @param mixed  $default Optional. Default value to return if the option does not exist.
    71  * @param mixed  $default_value Optional. Default value to return if the option does not exist.
    72  * @return mixed Value of the option. A value of any type may be returned, including
    72  * @return mixed Value of the option. A value of any type may be returned, including
    73  *               scalar (string, boolean, float, integer), null, array, object.
    73  *               scalar (string, boolean, float, integer), null, array, object.
    74  *               Scalar and null values will be returned as strings as long as they originate
    74  *               Scalar and null values will be returned as strings as long as they originate
    75  *               from a database stored option value. If there is no option in the database,
    75  *               from a database stored option value. If there is no option in the database,
    76  *               boolean `false` is returned.
    76  *               boolean `false` is returned.
    77  */
    77  */
    78 function get_option( $option, $default = false ) {
    78 function get_option( $option, $default_value = false ) {
    79 	global $wpdb;
    79 	global $wpdb;
    80 
    80 
    81 	if ( is_scalar( $option ) ) {
    81 	if ( is_scalar( $option ) ) {
    82 		$option = trim( $option );
    82 		$option = trim( $option );
    83 	}
    83 	}
    93 	$deprecated_keys = array(
    93 	$deprecated_keys = array(
    94 		'blacklist_keys'    => 'disallowed_keys',
    94 		'blacklist_keys'    => 'disallowed_keys',
    95 		'comment_whitelist' => 'comment_previously_approved',
    95 		'comment_whitelist' => 'comment_previously_approved',
    96 	);
    96 	);
    97 
    97 
    98 	if ( ! wp_installing() && isset( $deprecated_keys[ $option ] ) ) {
    98 	if ( isset( $deprecated_keys[ $option ] ) && ! wp_installing() ) {
    99 		_deprecated_argument(
    99 		_deprecated_argument(
   100 			__FUNCTION__,
   100 			__FUNCTION__,
   101 			'5.5.0',
   101 			'5.5.0',
   102 			sprintf(
   102 			sprintf(
   103 				/* translators: 1: Deprecated option key, 2: New option key. */
   103 				/* translators: 1: Deprecated option key, 2: New option key. */
   104 				__( 'The "%1$s" option key has been renamed to "%2$s".' ),
   104 				__( 'The "%1$s" option key has been renamed to "%2$s".' ),
   105 				$option,
   105 				$option,
   106 				$deprecated_keys[ $option ]
   106 				$deprecated_keys[ $option ]
   107 			)
   107 			)
   108 		);
   108 		);
   109 		return get_option( $deprecated_keys[ $option ], $default );
   109 		return get_option( $deprecated_keys[ $option ], $default_value );
   110 	}
   110 	}
   111 
   111 
   112 	/**
   112 	/**
   113 	 * Filters the value of an existing option before it is retrieved.
   113 	 * Filters the value of an existing option before it is retrieved.
   114 	 *
   114 	 *
   115 	 * The dynamic portion of the hook name, `$option`, refers to the option name.
   115 	 * The dynamic portion of the hook name, `$option`, refers to the option name.
       
   116 	 *
       
   117 	 * Returning a value other than false from the filter will short-circuit retrieval
       
   118 	 * and return that value instead.
       
   119 	 *
       
   120 	 * @since 1.5.0
       
   121 	 * @since 4.4.0 The `$option` parameter was added.
       
   122 	 * @since 4.9.0 The `$default_value` parameter was added.
       
   123 	 *
       
   124 	 * @param mixed  $pre_option    The value to return instead of the option value. This differs from
       
   125 	 *                              `$default_value`, which is used as the fallback value in the event
       
   126 	 *                              the option doesn't exist elsewhere in get_option().
       
   127 	 *                              Default false (to skip past the short-circuit).
       
   128 	 * @param string $option        Option name.
       
   129 	 * @param mixed  $default_value The fallback value to return if the option does not exist.
       
   130 	 *                              Default false.
       
   131 	 */
       
   132 	$pre = apply_filters( "pre_option_{$option}", false, $option, $default_value );
       
   133 
       
   134 	/**
       
   135 	 * Filters the value of all existing options before it is retrieved.
   116 	 *
   136 	 *
   117 	 * Returning a truthy value from the filter will effectively short-circuit retrieval
   137 	 * Returning a truthy value from the filter will effectively short-circuit retrieval
   118 	 * and return the passed value instead.
   138 	 * and return the passed value instead.
   119 	 *
   139 	 *
   120 	 * @since 1.5.0
   140 	 * @since 6.1.0
   121 	 * @since 4.4.0 The `$option` parameter was added.
   141 	 *
   122 	 * @since 4.9.0 The `$default` parameter was added.
   142 	 * @param mixed  $pre_option    The value to return instead of the option value. This differs from
   123 	 *
   143 	 *                              `$default_value`, which is used as the fallback value in the event
   124 	 * @param mixed  $pre_option The value to return instead of the option value. This differs
   144 	 *                              the option doesn't exist elsewhere in get_option().
   125 	 *                           from `$default`, which is used as the fallback value in the event
   145 	 *                              Default false (to skip past the short-circuit).
   126 	 *                           the option doesn't exist elsewhere in get_option().
   146 	 * @param string $option        Name of the option.
   127 	 *                           Default false (to skip past the short-circuit).
   147 	 * @param mixed  $default_value The fallback value to return if the option does not exist.
   128 	 * @param string $option     Option name.
   148 	 *                              Default false.
   129 	 * @param mixed  $default    The fallback value to return if the option does not exist.
   149 	 */
   130 	 *                           Default false.
   150 	$pre = apply_filters( 'pre_option', $pre, $option, $default_value );
   131 	 */
       
   132 	$pre = apply_filters( "pre_option_{$option}", false, $option, $default );
       
   133 
   151 
   134 	if ( false !== $pre ) {
   152 	if ( false !== $pre ) {
   135 		return $pre;
   153 		return $pre;
   136 	}
   154 	}
   137 
   155 
   141 
   159 
   142 	// Distinguish between `false` as a default, and not passing one.
   160 	// Distinguish between `false` as a default, and not passing one.
   143 	$passed_default = func_num_args() > 1;
   161 	$passed_default = func_num_args() > 1;
   144 
   162 
   145 	if ( ! wp_installing() ) {
   163 	if ( ! wp_installing() ) {
   146 		// Prevent non-existent options from triggering multiple queries.
       
   147 		$notoptions = wp_cache_get( 'notoptions', 'options' );
       
   148 
       
   149 		if ( isset( $notoptions[ $option ] ) ) {
       
   150 			/**
       
   151 			 * Filters the default value for an option.
       
   152 			 *
       
   153 			 * The dynamic portion of the hook name, `$option`, refers to the option name.
       
   154 			 *
       
   155 			 * @since 3.4.0
       
   156 			 * @since 4.4.0 The `$option` parameter was added.
       
   157 			 * @since 4.7.0 The `$passed_default` parameter was added to distinguish between a `false` value and the default parameter value.
       
   158 			 *
       
   159 			 * @param mixed  $default The default value to return if the option does not exist
       
   160 			 *                        in the database.
       
   161 			 * @param string $option  Option name.
       
   162 			 * @param bool   $passed_default Was `get_option()` passed a default value?
       
   163 			 */
       
   164 			return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
       
   165 		}
       
   166 
       
   167 		$alloptions = wp_load_alloptions();
   164 		$alloptions = wp_load_alloptions();
   168 
   165 
   169 		if ( isset( $alloptions[ $option ] ) ) {
   166 		if ( isset( $alloptions[ $option ] ) ) {
   170 			$value = $alloptions[ $option ];
   167 			$value = $alloptions[ $option ];
   171 		} else {
   168 		} else {
   172 			$value = wp_cache_get( $option, 'options' );
   169 			$value = wp_cache_get( $option, 'options' );
   173 
   170 
   174 			if ( false === $value ) {
   171 			if ( false === $value ) {
       
   172 				// Prevent non-existent options from triggering multiple queries.
       
   173 				$notoptions = wp_cache_get( 'notoptions', 'options' );
       
   174 
       
   175 				// Prevent non-existent `notoptions` key from triggering multiple key lookups.
       
   176 				if ( ! is_array( $notoptions ) ) {
       
   177 					$notoptions = array();
       
   178 					wp_cache_set( 'notoptions', $notoptions, 'options' );
       
   179 				} elseif ( isset( $notoptions[ $option ] ) ) {
       
   180 					/**
       
   181 					 * Filters the default value for an option.
       
   182 					 *
       
   183 					 * The dynamic portion of the hook name, `$option`, refers to the option name.
       
   184 					 *
       
   185 					 * @since 3.4.0
       
   186 					 * @since 4.4.0 The `$option` parameter was added.
       
   187 					 * @since 4.7.0 The `$passed_default` parameter was added to distinguish between a `false` value and the default parameter value.
       
   188 					 *
       
   189 					 * @param mixed  $default_value  The default value to return if the option does not exist
       
   190 					 *                               in the database.
       
   191 					 * @param string $option         Option name.
       
   192 					 * @param bool   $passed_default Was `get_option()` passed a default value?
       
   193 					 */
       
   194 					return apply_filters( "default_option_{$option}", $default_value, $option, $passed_default );
       
   195 				}
       
   196 
   175 				$row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
   197 				$row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
   176 
   198 
   177 				// Has to be get_row() instead of get_var() because of funkiness with 0, false, null values.
   199 				// Has to be get_row() instead of get_var() because of funkiness with 0, false, null values.
   178 				if ( is_object( $row ) ) {
   200 				if ( is_object( $row ) ) {
   179 					$value = $row->option_value;
   201 					$value = $row->option_value;
   180 					wp_cache_add( $option, $value, 'options' );
   202 					wp_cache_add( $option, $value, 'options' );
   181 				} else { // Option does not exist, so we must cache its non-existence.
   203 				} else { // Option does not exist, so we must cache its non-existence.
   182 					if ( ! is_array( $notoptions ) ) {
       
   183 						$notoptions = array();
       
   184 					}
       
   185 
       
   186 					$notoptions[ $option ] = true;
   204 					$notoptions[ $option ] = true;
   187 					wp_cache_set( 'notoptions', $notoptions, 'options' );
   205 					wp_cache_set( 'notoptions', $notoptions, 'options' );
   188 
   206 
   189 					/** This filter is documented in wp-includes/option.php */
   207 					/** This filter is documented in wp-includes/option.php */
   190 					return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
   208 					return apply_filters( "default_option_{$option}", $default_value, $option, $passed_default );
   191 				}
   209 				}
   192 			}
   210 			}
   193 		}
   211 		}
   194 	} else {
   212 	} else {
   195 		$suppress = $wpdb->suppress_errors();
   213 		$suppress = $wpdb->suppress_errors();
   198 
   216 
   199 		if ( is_object( $row ) ) {
   217 		if ( is_object( $row ) ) {
   200 			$value = $row->option_value;
   218 			$value = $row->option_value;
   201 		} else {
   219 		} else {
   202 			/** This filter is documented in wp-includes/option.php */
   220 			/** This filter is documented in wp-includes/option.php */
   203 			return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
   221 			return apply_filters( "default_option_{$option}", $default_value, $option, $passed_default );
   204 		}
   222 		}
   205 	}
   223 	}
   206 
   224 
   207 	// If home is not set, use siteurl.
   225 	// If home is not set, use siteurl.
   208 	if ( 'home' === $option && '' === $value ) {
   226 	if ( 'home' === $option && '' === $value ) {
   225 	 * @param mixed  $value  Value of the option. If stored serialized, it will be
   243 	 * @param mixed  $value  Value of the option. If stored serialized, it will be
   226 	 *                       unserialized prior to being returned.
   244 	 *                       unserialized prior to being returned.
   227 	 * @param string $option Option name.
   245 	 * @param string $option Option name.
   228 	 */
   246 	 */
   229 	return apply_filters( "option_{$option}", maybe_unserialize( $value ), $option );
   247 	return apply_filters( "option_{$option}", maybe_unserialize( $value ), $option );
       
   248 }
       
   249 
       
   250 /**
       
   251  * Primes specific options into the cache with a single database query.
       
   252  *
       
   253  * Only options that do not already exist in cache will be loaded.
       
   254  *
       
   255  * @since 6.4.0
       
   256  *
       
   257  * @global wpdb $wpdb WordPress database abstraction object.
       
   258  *
       
   259  * @param string[] $options An array of option names to be loaded.
       
   260  */
       
   261 function wp_prime_option_caches( $options ) {
       
   262 	global $wpdb;
       
   263 
       
   264 	$alloptions     = wp_load_alloptions();
       
   265 	$cached_options = wp_cache_get_multiple( $options, 'options' );
       
   266 	$notoptions     = wp_cache_get( 'notoptions', 'options' );
       
   267 	if ( ! is_array( $notoptions ) ) {
       
   268 		$notoptions = array();
       
   269 	}
       
   270 
       
   271 	// Filter options that are not in the cache.
       
   272 	$options_to_prime = array();
       
   273 	foreach ( $options as $option ) {
       
   274 		if (
       
   275 			( ! isset( $cached_options[ $option ] ) || false === $cached_options[ $option ] )
       
   276 			&& ! isset( $alloptions[ $option ] )
       
   277 			&& ! isset( $notoptions[ $option ] )
       
   278 		) {
       
   279 			$options_to_prime[] = $option;
       
   280 		}
       
   281 	}
       
   282 
       
   283 	// Bail early if there are no options to be loaded.
       
   284 	if ( empty( $options_to_prime ) ) {
       
   285 		return;
       
   286 	}
       
   287 
       
   288 	$results = $wpdb->get_results(
       
   289 		$wpdb->prepare(
       
   290 			sprintf(
       
   291 				"SELECT option_name, option_value FROM $wpdb->options WHERE option_name IN (%s)",
       
   292 				implode( ',', array_fill( 0, count( $options_to_prime ), '%s' ) )
       
   293 			),
       
   294 			$options_to_prime
       
   295 		)
       
   296 	);
       
   297 
       
   298 	$options_found = array();
       
   299 	foreach ( $results as $result ) {
       
   300 		/*
       
   301 		 * The cache is primed with the raw value (i.e. not maybe_unserialized).
       
   302 		 *
       
   303 		 * `get_option()` will handle unserializing the value as needed.
       
   304 		 */
       
   305 		$options_found[ $result->option_name ] = $result->option_value;
       
   306 	}
       
   307 	wp_cache_set_multiple( $options_found, 'options' );
       
   308 
       
   309 	// If all options were found, no need to update `notoptions` cache.
       
   310 	if ( count( $options_found ) === count( $options_to_prime ) ) {
       
   311 		return;
       
   312 	}
       
   313 
       
   314 	$options_not_found = array_diff( $options_to_prime, array_keys( $options_found ) );
       
   315 
       
   316 	// Add the options that were not found to the cache.
       
   317 	$update_notoptions = false;
       
   318 	foreach ( $options_not_found as $option_name ) {
       
   319 		if ( ! isset( $notoptions[ $option_name ] ) ) {
       
   320 			$notoptions[ $option_name ] = true;
       
   321 			$update_notoptions          = true;
       
   322 		}
       
   323 	}
       
   324 
       
   325 	// Only update the cache if it was modified.
       
   326 	if ( $update_notoptions ) {
       
   327 		wp_cache_set( 'notoptions', $notoptions, 'options' );
       
   328 	}
       
   329 }
       
   330 
       
   331 /**
       
   332  * Primes the cache of all options registered with a specific option group.
       
   333  *
       
   334  * @since 6.4.0
       
   335  *
       
   336  * @global array $new_allowed_options
       
   337  *
       
   338  * @param string $option_group The option group to load options for.
       
   339  */
       
   340 function wp_prime_option_caches_by_group( $option_group ) {
       
   341 	global $new_allowed_options;
       
   342 
       
   343 	if ( isset( $new_allowed_options[ $option_group ] ) ) {
       
   344 		wp_prime_option_caches( $new_allowed_options[ $option_group ] );
       
   345 	}
       
   346 }
       
   347 
       
   348 /**
       
   349  * Retrieves multiple options.
       
   350  *
       
   351  * Options are loaded as necessary first in order to use a single database query at most.
       
   352  *
       
   353  * @since 6.4.0
       
   354  *
       
   355  * @param string[] $options An array of option names to retrieve.
       
   356  * @return array An array of key-value pairs for the requested options.
       
   357  */
       
   358 function get_options( $options ) {
       
   359 	wp_prime_option_caches( $options );
       
   360 
       
   361 	$result = array();
       
   362 	foreach ( $options as $option ) {
       
   363 		$result[ $option ] = get_option( $option );
       
   364 	}
       
   365 
       
   366 	return $result;
       
   367 }
       
   368 
       
   369 /**
       
   370  * Sets the autoload values for multiple options in the database.
       
   371  *
       
   372  * Autoloading too many options can lead to performance problems, especially if the options are not frequently used.
       
   373  * This function allows modifying the autoload value for multiple options without changing the actual option value.
       
   374  * This is for example recommended for plugin activation and deactivation hooks, to ensure any options exclusively used
       
   375  * by the plugin which are generally autoloaded can be set to not autoload when the plugin is inactive.
       
   376  *
       
   377  * @since 6.4.0
       
   378  *
       
   379  * @global wpdb $wpdb WordPress database abstraction object.
       
   380  *
       
   381  * @param array $options Associative array of option names and their autoload values to set. The option names are
       
   382  *                       expected to not be SQL-escaped. The autoload values accept 'yes'|true to enable or 'no'|false
       
   383  *                       to disable.
       
   384  * @return array Associative array of all provided $options as keys and boolean values for whether their autoload value
       
   385  *               was updated.
       
   386  */
       
   387 function wp_set_option_autoload_values( array $options ) {
       
   388 	global $wpdb;
       
   389 
       
   390 	if ( ! $options ) {
       
   391 		return array();
       
   392 	}
       
   393 
       
   394 	$grouped_options = array(
       
   395 		'on'  => array(),
       
   396 		'off' => array(),
       
   397 	);
       
   398 	$results         = array();
       
   399 	foreach ( $options as $option => $autoload ) {
       
   400 		wp_protect_special_option( $option ); // Ensure only valid options can be passed.
       
   401 		if ( 'off' === $autoload || 'no' === $autoload || false === $autoload ) { // Sanitize autoload value and categorize accordingly.
       
   402 			$grouped_options['off'][] = $option;
       
   403 		} else {
       
   404 			$grouped_options['on'][] = $option;
       
   405 		}
       
   406 		$results[ $option ] = false; // Initialize result value.
       
   407 	}
       
   408 
       
   409 	$where      = array();
       
   410 	$where_args = array();
       
   411 	foreach ( $grouped_options as $autoload => $options ) {
       
   412 		if ( ! $options ) {
       
   413 			continue;
       
   414 		}
       
   415 		$placeholders = implode( ',', array_fill( 0, count( $options ), '%s' ) );
       
   416 		$where[]      = "autoload != '%s' AND option_name IN ($placeholders)";
       
   417 		$where_args[] = $autoload;
       
   418 		foreach ( $options as $option ) {
       
   419 			$where_args[] = $option;
       
   420 		}
       
   421 	}
       
   422 	$where = 'WHERE ' . implode( ' OR ', $where );
       
   423 
       
   424 	/*
       
   425 	 * Determine the relevant options that do not already use the given autoload value.
       
   426 	 * If no options are returned, no need to update.
       
   427 	 */
       
   428 	// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
       
   429 	$options_to_update = $wpdb->get_col( $wpdb->prepare( "SELECT option_name FROM $wpdb->options $where", $where_args ) );
       
   430 	if ( ! $options_to_update ) {
       
   431 		return $results;
       
   432 	}
       
   433 
       
   434 	// Run UPDATE queries as needed (maximum 2) to update the relevant options' autoload values to 'yes' or 'no'.
       
   435 	foreach ( $grouped_options as $autoload => $options ) {
       
   436 		if ( ! $options ) {
       
   437 			continue;
       
   438 		}
       
   439 		$options                      = array_intersect( $options, $options_to_update );
       
   440 		$grouped_options[ $autoload ] = $options;
       
   441 		if ( ! $grouped_options[ $autoload ] ) {
       
   442 			continue;
       
   443 		}
       
   444 
       
   445 		// Run query to update autoload value for all the options where it is needed.
       
   446 		$success = $wpdb->query(
       
   447 			$wpdb->prepare(
       
   448 				"UPDATE $wpdb->options SET autoload = %s WHERE option_name IN (" . implode( ',', array_fill( 0, count( $grouped_options[ $autoload ] ), '%s' ) ) . ')',
       
   449 				array_merge(
       
   450 					array( $autoload ),
       
   451 					$grouped_options[ $autoload ]
       
   452 				)
       
   453 			)
       
   454 		);
       
   455 		if ( ! $success ) {
       
   456 			// Set option list to an empty array to indicate no options were updated.
       
   457 			$grouped_options[ $autoload ] = array();
       
   458 			continue;
       
   459 		}
       
   460 
       
   461 		// Assume that on success all options were updated, which should be the case given only new values are sent.
       
   462 		foreach ( $grouped_options[ $autoload ] as $option ) {
       
   463 			$results[ $option ] = true;
       
   464 		}
       
   465 	}
       
   466 
       
   467 	/*
       
   468 	 * If any options were changed to 'on', delete their individual caches, and delete 'alloptions' cache so that it
       
   469 	 * is refreshed as needed.
       
   470 	 * If no options were changed to 'on' but any options were changed to 'no', delete them from the 'alloptions'
       
   471 	 * cache. This is not necessary when options were changed to 'on', since in that situation the entire cache is
       
   472 	 * deleted anyway.
       
   473 	 */
       
   474 	if ( $grouped_options['on'] ) {
       
   475 		wp_cache_delete_multiple( $grouped_options['on'], 'options' );
       
   476 		wp_cache_delete( 'alloptions', 'options' );
       
   477 	} elseif ( $grouped_options['off'] ) {
       
   478 		$alloptions = wp_load_alloptions( true );
       
   479 
       
   480 		foreach ( $grouped_options['off'] as $option ) {
       
   481 			if ( isset( $alloptions[ $option ] ) ) {
       
   482 				unset( $alloptions[ $option ] );
       
   483 			}
       
   484 		}
       
   485 
       
   486 		wp_cache_set( 'alloptions', $alloptions, 'options' );
       
   487 	}
       
   488 
       
   489 	return $results;
       
   490 }
       
   491 
       
   492 /**
       
   493  * Sets the autoload value for multiple options in the database.
       
   494  *
       
   495  * This is a wrapper for {@see wp_set_option_autoload_values()}, which can be used to set different autoload values for
       
   496  * each option at once.
       
   497  *
       
   498  * @since 6.4.0
       
   499  *
       
   500  * @see wp_set_option_autoload_values()
       
   501  *
       
   502  * @param string[]    $options  List of option names. Expected to not be SQL-escaped.
       
   503  * @param string|bool $autoload Autoload value to control whether to load the options when WordPress starts up.
       
   504  *                              Accepts 'yes'|true to enable or 'no'|false to disable.
       
   505  * @return array Associative array of all provided $options as keys and boolean values for whether their autoload value
       
   506  *               was updated.
       
   507  */
       
   508 function wp_set_options_autoload( array $options, $autoload ) {
       
   509 	return wp_set_option_autoload_values(
       
   510 		array_fill_keys( $options, $autoload )
       
   511 	);
       
   512 }
       
   513 
       
   514 /**
       
   515  * Sets the autoload value for an option in the database.
       
   516  *
       
   517  * This is a wrapper for {@see wp_set_option_autoload_values()}, which can be used to set the autoload value for
       
   518  * multiple options at once.
       
   519  *
       
   520  * @since 6.4.0
       
   521  *
       
   522  * @see wp_set_option_autoload_values()
       
   523  *
       
   524  * @param string      $option   Name of the option. Expected to not be SQL-escaped.
       
   525  * @param string|bool $autoload Autoload value to control whether to load the option when WordPress starts up.
       
   526  *                              Accepts 'yes'|true to enable or 'no'|false to disable.
       
   527  * @return bool True if the autoload value was modified, false otherwise.
       
   528  */
       
   529 function wp_set_option_autoload( $option, $autoload ) {
       
   530 	$result = wp_set_option_autoload_values( array( $option => $autoload ) );
       
   531 	if ( isset( $result[ $option ] ) ) {
       
   532 		return $result[ $option ];
       
   533 	}
       
   534 	return false;
   230 }
   535 }
   231 
   536 
   232 /**
   537 /**
   233  * Protects WordPress special option from being modified.
   538  * Protects WordPress special option from being modified.
   234  *
   539  *
   275  * @return array List of all options.
   580  * @return array List of all options.
   276  */
   581  */
   277 function wp_load_alloptions( $force_cache = false ) {
   582 function wp_load_alloptions( $force_cache = false ) {
   278 	global $wpdb;
   583 	global $wpdb;
   279 
   584 
       
   585 	/**
       
   586 	 * Filters the array of alloptions before it is populated.
       
   587 	 *
       
   588 	 * Returning an array from the filter will effectively short circuit
       
   589 	 * wp_load_alloptions(), returning that value instead.
       
   590 	 *
       
   591 	 * @since 6.2.0
       
   592 	 *
       
   593 	 * @param array|null $alloptions  An array of alloptions. Default null.
       
   594 	 * @param bool       $force_cache Whether to force an update of the local cache from the persistent cache. Default false.
       
   595 	 */
       
   596 	$alloptions = apply_filters( 'pre_wp_load_alloptions', null, $force_cache );
       
   597 	if ( is_array( $alloptions ) ) {
       
   598 		return $alloptions;
       
   599 	}
       
   600 
   280 	if ( ! wp_installing() || ! is_multisite() ) {
   601 	if ( ! wp_installing() || ! is_multisite() ) {
   281 		$alloptions = wp_cache_get( 'alloptions', 'options', $force_cache );
   602 		$alloptions = wp_cache_get( 'alloptions', 'options', $force_cache );
   282 	} else {
   603 	} else {
   283 		$alloptions = false;
   604 		$alloptions = false;
   284 	}
   605 	}
   285 
   606 
   286 	if ( ! $alloptions ) {
   607 	if ( ! $alloptions ) {
   287 		$suppress      = $wpdb->suppress_errors();
   608 		$suppress      = $wpdb->suppress_errors();
   288 		$alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE autoload = 'yes'" );
   609 		$alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE autoload IN ( '" . implode( "', '", esc_sql( wp_autoload_values_to_autoload() ) ) . "' )" );
       
   610 
   289 		if ( ! $alloptions_db ) {
   611 		if ( ! $alloptions_db ) {
   290 			$alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" );
   612 			$alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" );
   291 		}
   613 		}
   292 		$wpdb->suppress_errors( $suppress );
   614 		$wpdb->suppress_errors( $suppress );
   293 
   615 
   319 	 */
   641 	 */
   320 	return apply_filters( 'alloptions', $alloptions );
   642 	return apply_filters( 'alloptions', $alloptions );
   321 }
   643 }
   322 
   644 
   323 /**
   645 /**
   324  * Loads and caches certain often requested site options if is_multisite() and a persistent cache is not being used.
   646  * Primes specific network options for the current network into the cache with a single database query.
       
   647  *
       
   648  * Only network options that do not already exist in cache will be loaded.
       
   649  *
       
   650  * If site is not multisite, then call wp_prime_option_caches().
       
   651  *
       
   652  * @since 6.6.0
       
   653  *
       
   654  * @see wp_prime_network_option_caches()
       
   655  *
       
   656  * @param string[] $options An array of option names to be loaded.
       
   657  */
       
   658 function wp_prime_site_option_caches( array $options ) {
       
   659 	wp_prime_network_option_caches( null, $options );
       
   660 }
       
   661 
       
   662 /**
       
   663  * Primes specific network options into the cache with a single database query.
       
   664  *
       
   665  * Only network options that do not already exist in cache will be loaded.
       
   666  *
       
   667  * If site is not multisite, then call wp_prime_option_caches().
       
   668  *
       
   669  * @since 6.6.0
       
   670  *
       
   671  * @global wpdb $wpdb WordPress database abstraction object.
       
   672  *
       
   673  * @param int      $network_id ID of the network. Can be null to default to the current network ID.
       
   674  * @param string[] $options    An array of option names to be loaded.
       
   675  */
       
   676 function wp_prime_network_option_caches( $network_id, array $options ) {
       
   677 	global $wpdb;
       
   678 
       
   679 	if ( wp_installing() ) {
       
   680 		return;
       
   681 	}
       
   682 
       
   683 	if ( ! is_multisite() ) {
       
   684 		wp_prime_option_caches( $options );
       
   685 		return;
       
   686 	}
       
   687 
       
   688 	if ( $network_id && ! is_numeric( $network_id ) ) {
       
   689 		return;
       
   690 	}
       
   691 
       
   692 	$network_id = (int) $network_id;
       
   693 
       
   694 	// Fallback to the current network if a network ID is not specified.
       
   695 	if ( ! $network_id ) {
       
   696 		$network_id = get_current_network_id();
       
   697 	}
       
   698 
       
   699 	$cache_keys = array();
       
   700 	foreach ( $options as $option ) {
       
   701 		$cache_keys[ $option ] = "{$network_id}:{$option}";
       
   702 	}
       
   703 
       
   704 	$cache_group    = 'site-options';
       
   705 	$cached_options = wp_cache_get_multiple( array_values( $cache_keys ), $cache_group );
       
   706 
       
   707 	$notoptions_key = "$network_id:notoptions";
       
   708 	$notoptions     = wp_cache_get( $notoptions_key, $cache_group );
       
   709 
       
   710 	if ( ! is_array( $notoptions ) ) {
       
   711 		$notoptions = array();
       
   712 	}
       
   713 
       
   714 	// Filter options that are not in the cache.
       
   715 	$options_to_prime = array();
       
   716 	foreach ( $cache_keys as $option => $cache_key ) {
       
   717 		if (
       
   718 			( ! isset( $cached_options[ $cache_key ] ) || false === $cached_options[ $cache_key ] )
       
   719 			&& ! isset( $notoptions[ $option ] )
       
   720 		) {
       
   721 			$options_to_prime[] = $option;
       
   722 		}
       
   723 	}
       
   724 
       
   725 	// Bail early if there are no options to be loaded.
       
   726 	if ( empty( $options_to_prime ) ) {
       
   727 		return;
       
   728 	}
       
   729 
       
   730 	$query_args   = $options_to_prime;
       
   731 	$query_args[] = $network_id;
       
   732 	$results      = $wpdb->get_results(
       
   733 		$wpdb->prepare(
       
   734 			sprintf(
       
   735 				"SELECT meta_key, meta_value FROM $wpdb->sitemeta WHERE meta_key IN (%s) AND site_id = %s",
       
   736 				implode( ',', array_fill( 0, count( $options_to_prime ), '%s' ) ),
       
   737 				'%d'
       
   738 			),
       
   739 			$query_args
       
   740 		)
       
   741 	);
       
   742 
       
   743 	$data          = array();
       
   744 	$options_found = array();
       
   745 	foreach ( $results as $result ) {
       
   746 		$key                = $result->meta_key;
       
   747 		$cache_key          = $cache_keys[ $key ];
       
   748 		$data[ $cache_key ] = maybe_unserialize( $result->meta_value );
       
   749 		$options_found[]    = $key;
       
   750 	}
       
   751 	wp_cache_set_multiple( $data, $cache_group );
       
   752 	// If all options were found, no need to update `notoptions` cache.
       
   753 	if ( count( $options_found ) === count( $options_to_prime ) ) {
       
   754 		return;
       
   755 	}
       
   756 
       
   757 	$options_not_found = array_diff( $options_to_prime, $options_found );
       
   758 
       
   759 	// Add the options that were not found to the cache.
       
   760 	$update_notoptions = false;
       
   761 	foreach ( $options_not_found as $option_name ) {
       
   762 		if ( ! isset( $notoptions[ $option_name ] ) ) {
       
   763 			$notoptions[ $option_name ] = true;
       
   764 			$update_notoptions          = true;
       
   765 		}
       
   766 	}
       
   767 
       
   768 	// Only update the cache if it was modified.
       
   769 	if ( $update_notoptions ) {
       
   770 		wp_cache_set( $notoptions_key, $notoptions, $cache_group );
       
   771 	}
       
   772 }
       
   773 
       
   774 /**
       
   775  * Loads and primes caches of certain often requested network options if is_multisite().
   325  *
   776  *
   326  * @since 3.0.0
   777  * @since 3.0.0
   327  *
   778  * @since 6.3.0 Also prime caches for network options when persistent object cache is enabled.
   328  * @global wpdb $wpdb WordPress database abstraction object.
   779  * @since 6.6.0 Uses wp_prime_network_option_caches().
   329  *
   780  *
   330  * @param int $network_id Optional site ID for which to query the options. Defaults to the current site.
   781  * @param int $network_id Optional. Network ID of network for which to prime network options cache. Defaults to current network.
   331  */
   782  */
   332 function wp_load_core_site_options( $network_id = null ) {
   783 function wp_load_core_site_options( $network_id = null ) {
   333 	global $wpdb;
   784 	if ( ! is_multisite() || wp_installing() ) {
   334 
       
   335 	if ( ! is_multisite() || wp_using_ext_object_cache() || wp_installing() ) {
       
   336 		return;
   785 		return;
   337 	}
   786 	}
   338 
   787 	$core_options = array( 'site_name', 'siteurl', 'active_sitewide_plugins', '_site_transient_timeout_theme_roots', '_site_transient_theme_roots', 'site_admins', 'can_compress_scripts', 'global_terms_enabled', 'ms_files_rewriting', 'WPLANG' );
   339 	if ( empty( $network_id ) ) {
   788 
   340 		$network_id = get_current_network_id();
   789 	wp_prime_network_option_caches( $network_id, $core_options );
   341 	}
       
   342 
       
   343 	$core_options = array( 'site_name', 'siteurl', 'active_sitewide_plugins', '_site_transient_timeout_theme_roots', '_site_transient_theme_roots', 'site_admins', 'can_compress_scripts', 'global_terms_enabled', 'ms_files_rewriting' );
       
   344 
       
   345 	$core_options_in = "'" . implode( "', '", $core_options ) . "'";
       
   346 	$options         = $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value FROM $wpdb->sitemeta WHERE meta_key IN ($core_options_in) AND site_id = %d", $network_id ) );
       
   347 
       
   348 	$data = array();
       
   349 	foreach ( $options as $option ) {
       
   350 		$key                = $option->meta_key;
       
   351 		$cache_key          = "{$network_id}:$key";
       
   352 		$option->meta_value = maybe_unserialize( $option->meta_value );
       
   353 
       
   354 		$data[ $cache_key ] = $option->meta_value;
       
   355 	}
       
   356 	wp_cache_set_multiple( $data, 'site-options' );
       
   357 }
   790 }
   358 
   791 
   359 /**
   792 /**
   360  * Updates the value of an option that was already added.
   793  * Updates the value of an option that was already added.
   361  *
   794  *
   371  * @since 1.0.0
   804  * @since 1.0.0
   372  * @since 4.2.0 The `$autoload` parameter was added.
   805  * @since 4.2.0 The `$autoload` parameter was added.
   373  *
   806  *
   374  * @global wpdb $wpdb WordPress database abstraction object.
   807  * @global wpdb $wpdb WordPress database abstraction object.
   375  *
   808  *
   376  * @param string      $option   Name of the option to update. Expected to not be SQL-escaped.
   809  * @param string    $option   Name of the option to update. Expected to not be SQL-escaped.
   377  * @param mixed       $value    Option value. Must be serializable if non-scalar. Expected to not be SQL-escaped.
   810  * @param mixed     $value    Option value. Must be serializable if non-scalar. Expected to not be SQL-escaped.
   378  * @param string|bool $autoload Optional. Whether to load the option when WordPress starts up. For existing options,
   811  * @param bool|null $autoload Optional. Whether to load the option when WordPress starts up.
   379  *                              `$autoload` can only be updated using `update_option()` if `$value` is also changed.
   812  *                            Accepts a boolean, or `null` to stick with the initial value or, if no initial value is set,
   380  *                              Accepts 'yes'|true to enable or 'no'|false to disable. For non-existent options,
   813  *                            to leave the decision up to default heuristics in WordPress.
   381  *                              the default value is 'yes'. Default null.
   814  *                            For existing options,
       
   815  *                            `$autoload` can only be updated using `update_option()` if `$value` is also changed.
       
   816  *                            For backward compatibility 'yes' and 'no' are also accepted.
       
   817  *                            Autoloading too many options can lead to performance problems, especially if the
       
   818  *                            options are not frequently used. For options which are accessed across several places
       
   819  *                            in the frontend, it is recommended to autoload them, by using true.
       
   820  *                            For options which are accessed only on few specific URLs, it is recommended
       
   821  *                            to not autoload them, by using false.
       
   822  *                            For non-existent options, the default is null, which means WordPress will determine
       
   823  *                            the autoload value.
   382  * @return bool True if the value was updated, false otherwise.
   824  * @return bool True if the value was updated, false otherwise.
   383  */
   825  */
   384 function update_option( $option, $value, $autoload = null ) {
   826 function update_option( $option, $value, $autoload = null ) {
   385 	global $wpdb;
   827 	global $wpdb;
   386 
   828 
   399 	$deprecated_keys = array(
   841 	$deprecated_keys = array(
   400 		'blacklist_keys'    => 'disallowed_keys',
   842 		'blacklist_keys'    => 'disallowed_keys',
   401 		'comment_whitelist' => 'comment_previously_approved',
   843 		'comment_whitelist' => 'comment_previously_approved',
   402 	);
   844 	);
   403 
   845 
   404 	if ( ! wp_installing() && isset( $deprecated_keys[ $option ] ) ) {
   846 	if ( isset( $deprecated_keys[ $option ] ) && ! wp_installing() ) {
   405 		_deprecated_argument(
   847 		_deprecated_argument(
   406 			__FUNCTION__,
   848 			__FUNCTION__,
   407 			'5.5.0',
   849 			'5.5.0',
   408 			sprintf(
   850 			sprintf(
   409 				/* translators: 1: Deprecated option key, 2: New option key. */
   851 				/* translators: 1: Deprecated option key, 2: New option key. */
   462 		return false;
   904 		return false;
   463 	}
   905 	}
   464 
   906 
   465 	/** This filter is documented in wp-includes/option.php */
   907 	/** This filter is documented in wp-includes/option.php */
   466 	if ( apply_filters( "default_option_{$option}", false, $option, false ) === $old_value ) {
   908 	if ( apply_filters( "default_option_{$option}", false, $option, false ) === $old_value ) {
   467 		// Default setting for new options is 'yes'.
       
   468 		if ( null === $autoload ) {
       
   469 			$autoload = 'yes';
       
   470 		}
       
   471 
       
   472 		return add_option( $option, $value, '', $autoload );
   909 		return add_option( $option, $value, '', $autoload );
   473 	}
   910 	}
   474 
   911 
   475 	$serialized_value = maybe_serialize( $value );
   912 	$serialized_value = maybe_serialize( $value );
   476 
   913 
   488 	$update_args = array(
   925 	$update_args = array(
   489 		'option_value' => $serialized_value,
   926 		'option_value' => $serialized_value,
   490 	);
   927 	);
   491 
   928 
   492 	if ( null !== $autoload ) {
   929 	if ( null !== $autoload ) {
   493 		$update_args['autoload'] = ( 'no' === $autoload || false === $autoload ) ? 'no' : 'yes';
   930 		$update_args['autoload'] = wp_determine_option_autoload_value( $option, $value, $serialized_value, $autoload );
       
   931 	} else {
       
   932 		// Retrieve the current autoload value to reevaluate it in case it was set automatically.
       
   933 		$raw_autoload = $wpdb->get_var( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
       
   934 		$allow_values = array( 'auto-on', 'auto-off', 'auto' );
       
   935 		if ( in_array( $raw_autoload, $allow_values, true ) ) {
       
   936 			$autoload = wp_determine_option_autoload_value( $option, $value, $serialized_value, $autoload );
       
   937 			if ( $autoload !== $raw_autoload ) {
       
   938 				$update_args['autoload'] = $autoload;
       
   939 			}
       
   940 		}
   494 	}
   941 	}
   495 
   942 
   496 	$result = $wpdb->update( $wpdb->options, $update_args, array( 'option_name' => $option ) );
   943 	$result = $wpdb->update( $wpdb->options, $update_args, array( 'option_name' => $option ) );
   497 	if ( ! $result ) {
   944 	if ( ! $result ) {
   498 		return false;
   945 		return false;
   504 		unset( $notoptions[ $option ] );
   951 		unset( $notoptions[ $option ] );
   505 		wp_cache_set( 'notoptions', $notoptions, 'options' );
   952 		wp_cache_set( 'notoptions', $notoptions, 'options' );
   506 	}
   953 	}
   507 
   954 
   508 	if ( ! wp_installing() ) {
   955 	if ( ! wp_installing() ) {
   509 		$alloptions = wp_load_alloptions( true );
   956 		if ( ! isset( $update_args['autoload'] ) ) {
   510 		if ( isset( $alloptions[ $option ] ) ) {
   957 			// Update the cached value based on where it is currently cached.
       
   958 			$alloptions = wp_load_alloptions( true );
       
   959 
       
   960 			if ( isset( $alloptions[ $option ] ) ) {
       
   961 				$alloptions[ $option ] = $serialized_value;
       
   962 				wp_cache_set( 'alloptions', $alloptions, 'options' );
       
   963 			} else {
       
   964 				wp_cache_set( $option, $serialized_value, 'options' );
       
   965 			}
       
   966 		} elseif ( in_array( $update_args['autoload'], wp_autoload_values_to_autoload(), true ) ) {
       
   967 			// Delete the individual cache, then set in alloptions cache.
       
   968 			wp_cache_delete( $option, 'options' );
       
   969 
       
   970 			$alloptions = wp_load_alloptions( true );
       
   971 
   511 			$alloptions[ $option ] = $serialized_value;
   972 			$alloptions[ $option ] = $serialized_value;
   512 			wp_cache_set( 'alloptions', $alloptions, 'options' );
   973 			wp_cache_set( 'alloptions', $alloptions, 'options' );
   513 		} else {
   974 		} else {
       
   975 			// Delete the alloptions cache, then set the individual cache.
       
   976 			$alloptions = wp_load_alloptions( true );
       
   977 
       
   978 			if ( isset( $alloptions[ $option ] ) ) {
       
   979 				unset( $alloptions[ $option ] );
       
   980 				wp_cache_set( 'alloptions', $alloptions, 'options' );
       
   981 			}
       
   982 
   514 			wp_cache_set( $option, $serialized_value, 'options' );
   983 			wp_cache_set( $option, $serialized_value, 'options' );
   515 		}
   984 		}
   516 	}
   985 	}
   517 
   986 
   518 	/**
   987 	/**
   554  * Existing options will not be updated and checks are performed to ensure that you
  1023  * Existing options will not be updated and checks are performed to ensure that you
   555  * aren't adding a protected WordPress option. Care should be taken to not name
  1024  * aren't adding a protected WordPress option. Care should be taken to not name
   556  * options the same as the ones which are protected.
  1025  * options the same as the ones which are protected.
   557  *
  1026  *
   558  * @since 1.0.0
  1027  * @since 1.0.0
       
  1028  * @since 6.6.0 The $autoload parameter's default value was changed to null.
   559  *
  1029  *
   560  * @global wpdb $wpdb WordPress database abstraction object.
  1030  * @global wpdb $wpdb WordPress database abstraction object.
   561  *
  1031  *
   562  * @param string      $option     Name of the option to add. Expected to not be SQL-escaped.
  1032  * @param string    $option     Name of the option to add. Expected to not be SQL-escaped.
   563  * @param mixed       $value      Optional. Option value. Must be serializable if non-scalar.
  1033  * @param mixed     $value      Optional. Option value. Must be serializable if non-scalar.
   564  *                                Expected to not be SQL-escaped.
  1034  *                              Expected to not be SQL-escaped.
   565  * @param string      $deprecated Optional. Description. Not used anymore.
  1035  * @param string    $deprecated Optional. Description. Not used anymore.
   566  * @param string|bool $autoload   Optional. Whether to load the option when WordPress starts up.
  1036  * @param bool|null $autoload   Optional. Whether to load the option when WordPress starts up.
   567  *                                Default is enabled. Accepts 'no' to disable for legacy reasons.
  1037  *                              Accepts a boolean, or `null` to leave the decision up to default heuristics in WordPress.
       
  1038  *                              For backward compatibility 'yes' and 'no' are also accepted.
       
  1039  *                              Autoloading too many options can lead to performance problems, especially if the
       
  1040  *                              options are not frequently used. For options which are accessed across several places
       
  1041  *                              in the frontend, it is recommended to autoload them, by using 'yes'|true.
       
  1042  *                              For options which are accessed only on few specific URLs, it is recommended
       
  1043  *                              to not autoload them, by using false.
       
  1044  *                              Default is null, which means WordPress will determine the autoload value.
   568  * @return bool True if the option was added, false otherwise.
  1045  * @return bool True if the option was added, false otherwise.
   569  */
  1046  */
   570 function add_option( $option, $value = '', $deprecated = '', $autoload = 'yes' ) {
  1047 function add_option( $option, $value = '', $deprecated = '', $autoload = null ) {
   571 	global $wpdb;
  1048 	global $wpdb;
   572 
  1049 
   573 	if ( ! empty( $deprecated ) ) {
  1050 	if ( ! empty( $deprecated ) ) {
   574 		_deprecated_argument( __FUNCTION__, '2.3.0' );
  1051 		_deprecated_argument( __FUNCTION__, '2.3.0' );
   575 	}
  1052 	}
   589 	$deprecated_keys = array(
  1066 	$deprecated_keys = array(
   590 		'blacklist_keys'    => 'disallowed_keys',
  1067 		'blacklist_keys'    => 'disallowed_keys',
   591 		'comment_whitelist' => 'comment_previously_approved',
  1068 		'comment_whitelist' => 'comment_previously_approved',
   592 	);
  1069 	);
   593 
  1070 
   594 	if ( ! wp_installing() && isset( $deprecated_keys[ $option ] ) ) {
  1071 	if ( isset( $deprecated_keys[ $option ] ) && ! wp_installing() ) {
   595 		_deprecated_argument(
  1072 		_deprecated_argument(
   596 			__FUNCTION__,
  1073 			__FUNCTION__,
   597 			'5.5.0',
  1074 			'5.5.0',
   598 			sprintf(
  1075 			sprintf(
   599 				/* translators: 1: Deprecated option key, 2: New option key. */
  1076 				/* translators: 1: Deprecated option key, 2: New option key. */
   611 		$value = clone $value;
  1088 		$value = clone $value;
   612 	}
  1089 	}
   613 
  1090 
   614 	$value = sanitize_option( $option, $value );
  1091 	$value = sanitize_option( $option, $value );
   615 
  1092 
   616 	// Make sure the option doesn't already exist.
  1093 	/*
   617 	// We can check the 'notoptions' cache before we ask for a DB query.
  1094 	 * Make sure the option doesn't already exist.
       
  1095 	 * We can check the 'notoptions' cache before we ask for a DB query.
       
  1096 	 */
   618 	$notoptions = wp_cache_get( 'notoptions', 'options' );
  1097 	$notoptions = wp_cache_get( 'notoptions', 'options' );
   619 
  1098 
   620 	if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) {
  1099 	if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) {
   621 		/** This filter is documented in wp-includes/option.php */
  1100 		/** This filter is documented in wp-includes/option.php */
   622 		if ( apply_filters( "default_option_{$option}", false, $option, false ) !== get_option( $option ) ) {
  1101 		if ( apply_filters( "default_option_{$option}", false, $option, false ) !== get_option( $option ) ) {
   623 			return false;
  1102 			return false;
   624 		}
  1103 		}
   625 	}
  1104 	}
   626 
  1105 
   627 	$serialized_value = maybe_serialize( $value );
  1106 	$serialized_value = maybe_serialize( $value );
   628 	$autoload         = ( 'no' === $autoload || false === $autoload ) ? 'no' : 'yes';
  1107 
       
  1108 	$autoload = wp_determine_option_autoload_value( $option, $value, $serialized_value, $autoload );
   629 
  1109 
   630 	/**
  1110 	/**
   631 	 * Fires before an option is added.
  1111 	 * Fires before an option is added.
   632 	 *
  1112 	 *
   633 	 * @since 2.9.0
  1113 	 * @since 2.9.0
   641 	if ( ! $result ) {
  1121 	if ( ! $result ) {
   642 		return false;
  1122 		return false;
   643 	}
  1123 	}
   644 
  1124 
   645 	if ( ! wp_installing() ) {
  1125 	if ( ! wp_installing() ) {
   646 		if ( 'yes' === $autoload ) {
  1126 		if ( in_array( $autoload, wp_autoload_values_to_autoload(), true ) ) {
   647 			$alloptions            = wp_load_alloptions( true );
  1127 			$alloptions            = wp_load_alloptions( true );
   648 			$alloptions[ $option ] = $serialized_value;
  1128 			$alloptions[ $option ] = $serialized_value;
   649 			wp_cache_set( 'alloptions', $alloptions, 'options' );
  1129 			wp_cache_set( 'alloptions', $alloptions, 'options' );
   650 		} else {
  1130 		} else {
   651 			wp_cache_set( $option, $serialized_value, 'options' );
  1131 			wp_cache_set( $option, $serialized_value, 'options' );
   685 
  1165 
   686 	return true;
  1166 	return true;
   687 }
  1167 }
   688 
  1168 
   689 /**
  1169 /**
   690  * Removes option by name. Prevents removal of protected WordPress options.
  1170  * Removes an option by name. Prevents removal of protected WordPress options.
   691  *
  1171  *
   692  * @since 1.2.0
  1172  * @since 1.2.0
   693  *
  1173  *
   694  * @global wpdb $wpdb WordPress database abstraction object.
  1174  * @global wpdb $wpdb WordPress database abstraction object.
   695  *
  1175  *
   725 	do_action( 'delete_option', $option );
  1205 	do_action( 'delete_option', $option );
   726 
  1206 
   727 	$result = $wpdb->delete( $wpdb->options, array( 'option_name' => $option ) );
  1207 	$result = $wpdb->delete( $wpdb->options, array( 'option_name' => $option ) );
   728 
  1208 
   729 	if ( ! wp_installing() ) {
  1209 	if ( ! wp_installing() ) {
   730 		if ( 'yes' === $row->autoload ) {
  1210 		if ( in_array( $row->autoload, wp_autoload_values_to_autoload(), true ) ) {
   731 			$alloptions = wp_load_alloptions( true );
  1211 			$alloptions = wp_load_alloptions( true );
       
  1212 
   732 			if ( is_array( $alloptions ) && isset( $alloptions[ $option ] ) ) {
  1213 			if ( is_array( $alloptions ) && isset( $alloptions[ $option ] ) ) {
   733 				unset( $alloptions[ $option ] );
  1214 				unset( $alloptions[ $option ] );
   734 				wp_cache_set( 'alloptions', $alloptions, 'options' );
  1215 				wp_cache_set( 'alloptions', $alloptions, 'options' );
   735 			}
  1216 			}
   736 		} else {
  1217 		} else {
   765 
  1246 
   766 	return false;
  1247 	return false;
   767 }
  1248 }
   768 
  1249 
   769 /**
  1250 /**
       
  1251  *  Determines the appropriate autoload value for an option based on input.
       
  1252  *
       
  1253  *  This function checks the provided autoload value and returns a standardized value
       
  1254  *  ('on', 'off', 'auto-on', 'auto-off', or 'auto') based on specific conditions.
       
  1255  *
       
  1256  * If no explicit autoload value is provided, the function will check for certain heuristics around the given option.
       
  1257  * It will return `auto-on` to indicate autoloading, `auto-off` to indicate not autoloading, or `auto` if no clear
       
  1258  * decision could be made.
       
  1259  *
       
  1260  * @since 6.6.0
       
  1261  * @access private
       
  1262  *
       
  1263  * @param string $option          The name of the option.
       
  1264  * @param mixed $value            The value of the option to check its autoload value.
       
  1265  * @param mixed $serialized_value The serialized value of the option to check its autoload value.
       
  1266  * @param bool|null $autoload     The autoload value to check.
       
  1267  *                                Accepts 'on'|true to enable or 'off'|false to disable, or
       
  1268  *                                'auto-on', 'auto-off', or 'auto' for internal purposes.
       
  1269  *                                Any other autoload value will be forced to either 'auto-on',
       
  1270  *                                'auto-off', or 'auto'.
       
  1271  *                                'yes' and 'no' are supported for backward compatibility.
       
  1272  * @return string Returns the original $autoload value if explicit, or 'auto-on', 'auto-off',
       
  1273  *                or 'auto' depending on default heuristics.
       
  1274  */
       
  1275 function wp_determine_option_autoload_value( $option, $value, $serialized_value, $autoload ) {
       
  1276 
       
  1277 	// Check if autoload is a boolean.
       
  1278 	if ( is_bool( $autoload ) ) {
       
  1279 		return $autoload ? 'on' : 'off';
       
  1280 	}
       
  1281 
       
  1282 	switch ( $autoload ) {
       
  1283 		case 'on':
       
  1284 		case 'yes':
       
  1285 			return 'on';
       
  1286 		case 'off':
       
  1287 		case 'no':
       
  1288 			return 'off';
       
  1289 	}
       
  1290 
       
  1291 	/**
       
  1292 	 * Allows to determine the default autoload value for an option where no explicit value is passed.
       
  1293 	 *
       
  1294 	 * @since 6.6.0
       
  1295 	 *
       
  1296 	 * @param bool|null $autoload The default autoload value to set. Returning true will be set as 'auto-on' in the
       
  1297 	 *                            database, false will be set as 'auto-off', and null will be set as 'auto'.
       
  1298 	 * @param string    $option   The passed option name.
       
  1299 	 * @param mixed     $value    The passed option value to be saved.
       
  1300 	 */
       
  1301 	$autoload = apply_filters( 'wp_default_autoload_value', null, $option, $value, $serialized_value );
       
  1302 	if ( is_bool( $autoload ) ) {
       
  1303 		return $autoload ? 'auto-on' : 'auto-off';
       
  1304 	}
       
  1305 
       
  1306 	return 'auto';
       
  1307 }
       
  1308 
       
  1309 /**
       
  1310  * Filters the default autoload value to disable autoloading if the option value is too large.
       
  1311  *
       
  1312  * @since 6.6.0
       
  1313  * @access private
       
  1314  *
       
  1315  * @param bool|null $autoload         The default autoload value to set.
       
  1316  * @param string    $option           The passed option name.
       
  1317  * @param mixed     $value            The passed option value to be saved.
       
  1318  * @param mixed     $serialized_value The passed option value to be saved, in serialized form.
       
  1319  * @return bool|null Potentially modified $default.
       
  1320  */
       
  1321 function wp_filter_default_autoload_value_via_option_size( $autoload, $option, $value, $serialized_value ) {
       
  1322 	/**
       
  1323 	 * Filters the maximum size of option value in bytes.
       
  1324 	 *
       
  1325 	 * @since 6.6.0
       
  1326 	 *
       
  1327 	 * @param int    $max_option_size The option-size threshold, in bytes. Default 150000.
       
  1328 	 * @param string $option          The name of the option.
       
  1329 	 */
       
  1330 	$max_option_size = (int) apply_filters( 'wp_max_autoloaded_option_size', 150000, $option );
       
  1331 	$size            = ! empty( $serialized_value ) ? strlen( $serialized_value ) : 0;
       
  1332 
       
  1333 	if ( $size > $max_option_size ) {
       
  1334 		return false;
       
  1335 	}
       
  1336 
       
  1337 	return $autoload;
       
  1338 }
       
  1339 
       
  1340 /**
   770  * Deletes a transient.
  1341  * Deletes a transient.
   771  *
  1342  *
   772  * @since 2.8.0
  1343  * @since 2.8.0
   773  *
  1344  *
   774  * @param string $transient Transient name. Expected to not be SQL-escaped.
  1345  * @param string $transient Transient name. Expected to not be SQL-escaped.
   830 	/**
  1401 	/**
   831 	 * Filters the value of an existing transient before it is retrieved.
  1402 	 * Filters the value of an existing transient before it is retrieved.
   832 	 *
  1403 	 *
   833 	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
  1404 	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
   834 	 *
  1405 	 *
   835 	 * Returning a truthy value from the filter will effectively short-circuit retrieval
  1406 	 * Returning a value other than false from the filter will short-circuit retrieval
   836 	 * and return the passed value instead.
  1407 	 * and return that value instead.
   837 	 *
  1408 	 *
   838 	 * @since 2.8.0
  1409 	 * @since 2.8.0
   839 	 * @since 4.4.0 The `$transient` parameter was added
  1410 	 * @since 4.4.0 The `$transient` parameter was added
   840 	 *
  1411 	 *
   841 	 * @param mixed  $pre_transient The default value to return if the transient does not exist.
  1412 	 * @param mixed  $pre_transient The default value to return if the transient does not exist.
   854 	} else {
  1425 	} else {
   855 		$transient_option = '_transient_' . $transient;
  1426 		$transient_option = '_transient_' . $transient;
   856 		if ( ! wp_installing() ) {
  1427 		if ( ! wp_installing() ) {
   857 			// If option is not in alloptions, it is not autoloaded and thus has a timeout.
  1428 			// If option is not in alloptions, it is not autoloaded and thus has a timeout.
   858 			$alloptions = wp_load_alloptions();
  1429 			$alloptions = wp_load_alloptions();
       
  1430 
   859 			if ( ! isset( $alloptions[ $transient_option ] ) ) {
  1431 			if ( ! isset( $alloptions[ $transient_option ] ) ) {
   860 				$transient_timeout = '_transient_timeout_' . $transient;
  1432 				$transient_timeout = '_transient_timeout_' . $transient;
   861 				$timeout           = get_option( $transient_timeout );
  1433 				wp_prime_option_caches( array( $transient_option, $transient_timeout ) );
       
  1434 				$timeout = get_option( $transient_timeout );
   862 				if ( false !== $timeout && $timeout < time() ) {
  1435 				if ( false !== $timeout && $timeout < time() ) {
   863 					delete_option( $transient_option );
  1436 					delete_option( $transient_option );
   864 					delete_option( $transient_timeout );
  1437 					delete_option( $transient_timeout );
   865 					$value = false;
  1438 					$value = false;
   866 				}
  1439 				}
   936 	if ( wp_using_ext_object_cache() || wp_installing() ) {
  1509 	if ( wp_using_ext_object_cache() || wp_installing() ) {
   937 		$result = wp_cache_set( $transient, $value, 'transient', $expiration );
  1510 		$result = wp_cache_set( $transient, $value, 'transient', $expiration );
   938 	} else {
  1511 	} else {
   939 		$transient_timeout = '_transient_timeout_' . $transient;
  1512 		$transient_timeout = '_transient_timeout_' . $transient;
   940 		$transient_option  = '_transient_' . $transient;
  1513 		$transient_option  = '_transient_' . $transient;
       
  1514 		wp_prime_option_caches( array( $transient_option, $transient_timeout ) );
   941 
  1515 
   942 		if ( false === get_option( $transient_option ) ) {
  1516 		if ( false === get_option( $transient_option ) ) {
   943 			$autoload = 'yes';
  1517 			$autoload = true;
   944 			if ( $expiration ) {
  1518 			if ( $expiration ) {
   945 				$autoload = 'no';
  1519 				$autoload = false;
   946 				add_option( $transient_timeout, time() + $expiration, '', 'no' );
  1520 				add_option( $transient_timeout, time() + $expiration, '', false );
   947 			}
  1521 			}
   948 			$result = add_option( $transient_option, $value, '', $autoload );
  1522 			$result = add_option( $transient_option, $value, '', $autoload );
   949 		} else {
  1523 		} else {
   950 			// If expiration is requested, but the transient has no timeout option,
  1524 			/*
   951 			// delete, then re-create transient rather than update.
  1525 			 * If expiration is requested, but the transient has no timeout option,
       
  1526 			 * delete, then re-create transient rather than update.
       
  1527 			 */
   952 			$update = true;
  1528 			$update = true;
   953 
  1529 
   954 			if ( $expiration ) {
  1530 			if ( $expiration ) {
   955 				if ( false === get_option( $transient_timeout ) ) {
  1531 				if ( false === get_option( $transient_timeout ) ) {
   956 					delete_option( $transient_option );
  1532 					delete_option( $transient_option );
   957 					add_option( $transient_timeout, time() + $expiration, '', 'no' );
  1533 					add_option( $transient_timeout, time() + $expiration, '', false );
   958 					$result = add_option( $transient_option, $value, '', 'no' );
  1534 					$result = add_option( $transient_option, $value, '', false );
   959 					$update = false;
  1535 					$update = false;
   960 				} else {
  1536 				} else {
   961 					update_option( $transient_timeout, time() + $expiration );
  1537 					update_option( $transient_timeout, time() + $expiration );
   962 				}
  1538 				}
   963 			}
  1539 			}
  1002 }
  1578 }
  1003 
  1579 
  1004 /**
  1580 /**
  1005  * Deletes all expired transients.
  1581  * Deletes all expired transients.
  1006  *
  1582  *
       
  1583  * Note that this function won't do anything if an external object cache is in use.
       
  1584  *
  1007  * The multi-table delete syntax is used to delete the transient record
  1585  * The multi-table delete syntax is used to delete the transient record
  1008  * from table a, and the corresponding transient_timeout record from table b.
  1586  * from table a, and the corresponding transient_timeout record from table b.
       
  1587  *
       
  1588  * @global wpdb $wpdb WordPress database abstraction object.
  1009  *
  1589  *
  1010  * @since 4.9.0
  1590  * @since 4.9.0
  1011  *
  1591  *
  1012  * @param bool $force_db Optional. Force cleanup to run against the database even when an external object cache is used.
  1592  * @param bool $force_db Optional. Force cleanup to run against the database even when an external object cache is used.
  1013  */
  1593  */
  1090 
  1670 
  1091 	if ( isset( $_COOKIE[ 'wp-settings-' . $user_id ] ) ) {
  1671 	if ( isset( $_COOKIE[ 'wp-settings-' . $user_id ] ) ) {
  1092 		$cookie = preg_replace( '/[^A-Za-z0-9=&_]/', '', $_COOKIE[ 'wp-settings-' . $user_id ] );
  1672 		$cookie = preg_replace( '/[^A-Za-z0-9=&_]/', '', $_COOKIE[ 'wp-settings-' . $user_id ] );
  1093 
  1673 
  1094 		// No change or both empty.
  1674 		// No change or both empty.
  1095 		if ( $cookie == $settings ) {
  1675 		if ( $cookie === $settings ) {
  1096 			return;
  1676 			return;
  1097 		}
  1677 		}
  1098 
  1678 
  1099 		$last_saved = (int) get_user_option( 'user-settings-time', $user_id );
  1679 		$last_saved = (int) get_user_option( 'user-settings-time', $user_id );
  1100 		$current    = isset( $_COOKIE[ 'wp-settings-time-' . $user_id ] ) ? preg_replace( '/[^0-9]/', '', $_COOKIE[ 'wp-settings-time-' . $user_id ] ) : 0;
  1680 		$current    = isset( $_COOKIE[ 'wp-settings-time-' . $user_id ] ) ? preg_replace( '/[^0-9]/', '', $_COOKIE[ 'wp-settings-time-' . $user_id ] ) : 0;
  1107 		}
  1687 		}
  1108 	}
  1688 	}
  1109 
  1689 
  1110 	// The cookie is not set in the current browser or the saved value is newer.
  1690 	// The cookie is not set in the current browser or the saved value is newer.
  1111 	$secure = ( 'https' === parse_url( admin_url(), PHP_URL_SCHEME ) );
  1691 	$secure = ( 'https' === parse_url( admin_url(), PHP_URL_SCHEME ) );
  1112 	setcookie( 'wp-settings-' . $user_id, $settings, time() + YEAR_IN_SECONDS, SITECOOKIEPATH, null, $secure );
  1692 	setcookie( 'wp-settings-' . $user_id, $settings, time() + YEAR_IN_SECONDS, SITECOOKIEPATH, '', $secure );
  1113 	setcookie( 'wp-settings-time-' . $user_id, time(), time() + YEAR_IN_SECONDS, SITECOOKIEPATH, null, $secure );
  1693 	setcookie( 'wp-settings-time-' . $user_id, time(), time() + YEAR_IN_SECONDS, SITECOOKIEPATH, '', $secure );
  1114 	$_COOKIE[ 'wp-settings-' . $user_id ] = $settings;
  1694 	$_COOKIE[ 'wp-settings-' . $user_id ] = $settings;
  1115 }
  1695 }
  1116 
  1696 
  1117 /**
  1697 /**
  1118  * Retrieves user interface setting value based on setting name.
  1698  * Retrieves user interface setting value based on setting name.
  1119  *
  1699  *
  1120  * @since 2.7.0
  1700  * @since 2.7.0
  1121  *
  1701  *
  1122  * @param string       $name    The name of the setting.
  1702  * @param string       $name          The name of the setting.
  1123  * @param string|false $default Optional. Default value to return when $name is not set. Default false.
  1703  * @param string|false $default_value Optional. Default value to return when $name is not set. Default false.
  1124  * @return mixed The last saved user setting or the default value/false if it doesn't exist.
  1704  * @return mixed The last saved user setting or the default value/false if it doesn't exist.
  1125  */
  1705  */
  1126 function get_user_setting( $name, $default = false ) {
  1706 function get_user_setting( $name, $default_value = false ) {
  1127 	$all_user_settings = get_all_user_settings();
  1707 	$all_user_settings = get_all_user_settings();
  1128 
  1708 
  1129 	return isset( $all_user_settings[ $name ] ) ? $all_user_settings[ $name ] : $default;
  1709 	return isset( $all_user_settings[ $name ] ) ? $all_user_settings[ $name ] : $default_value;
  1130 }
  1710 }
  1131 
  1711 
  1132 /**
  1712 /**
  1133  * Adds or updates user interface setting.
  1713  * Adds or updates user interface setting.
  1134  *
  1714  *
  1135  * Both $name and $value can contain only ASCII letters, numbers, hyphens, and underscores.
  1715  * Both `$name` and `$value` can contain only ASCII letters, numbers, hyphens, and underscores.
  1136  *
  1716  *
  1137  * This function has to be used before any output has started as it calls setcookie().
  1717  * This function has to be used before any output has started as it calls `setcookie()`.
  1138  *
  1718  *
  1139  * @since 2.8.0
  1719  * @since 2.8.0
  1140  *
  1720  *
  1141  * @param string $name  The name of the setting.
  1721  * @param string $name  The name of the setting.
  1142  * @param string $value The value for the setting.
  1722  * @param string $value The value for the setting.
  1157 /**
  1737 /**
  1158  * Deletes user interface settings.
  1738  * Deletes user interface settings.
  1159  *
  1739  *
  1160  * Deleting settings would reset them to the defaults.
  1740  * Deleting settings would reset them to the defaults.
  1161  *
  1741  *
  1162  * This function has to be used before any output has started as it calls setcookie().
  1742  * This function has to be used before any output has started as it calls `setcookie()`.
  1163  *
  1743  *
  1164  * @since 2.7.0
  1744  * @since 2.7.0
  1165  *
  1745  *
  1166  * @param string $names The name or array of names of the setting to be deleted.
  1746  * @param string $names The name or array of names of the setting to be deleted.
  1167  * @return bool|null True if deleted successfully, false otherwise.
  1747  * @return bool|null True if deleted successfully, false otherwise.
  1296  * @since 4.4.0 The `$use_cache` parameter was deprecated.
  1876  * @since 4.4.0 The `$use_cache` parameter was deprecated.
  1297  * @since 4.4.0 Modified into wrapper for get_network_option()
  1877  * @since 4.4.0 Modified into wrapper for get_network_option()
  1298  *
  1878  *
  1299  * @see get_network_option()
  1879  * @see get_network_option()
  1300  *
  1880  *
  1301  * @param string $option     Name of the option to retrieve. Expected to not be SQL-escaped.
  1881  * @param string $option        Name of the option to retrieve. Expected to not be SQL-escaped.
  1302  * @param mixed  $default    Optional. Value to return if the option doesn't exist. Default false.
  1882  * @param mixed  $default_value Optional. Value to return if the option doesn't exist. Default false.
  1303  * @param bool   $deprecated Whether to use cache. Multisite only. Always set to true.
  1883  * @param bool   $deprecated    Whether to use cache. Multisite only. Always set to true.
  1304  * @return mixed Value set for the option.
  1884  * @return mixed Value set for the option.
  1305  */
  1885  */
  1306 function get_site_option( $option, $default = false, $deprecated = true ) {
  1886 function get_site_option( $option, $default_value = false, $deprecated = true ) {
  1307 	return get_network_option( null, $option, $default );
  1887 	return get_network_option( null, $option, $default_value );
  1308 }
  1888 }
  1309 
  1889 
  1310 /**
  1890 /**
  1311  * Adds a new option for the current network.
  1891  * Adds a new option for the current network.
  1312  *
  1892  *
  1324 function add_site_option( $option, $value ) {
  1904 function add_site_option( $option, $value ) {
  1325 	return add_network_option( null, $option, $value );
  1905 	return add_network_option( null, $option, $value );
  1326 }
  1906 }
  1327 
  1907 
  1328 /**
  1908 /**
  1329  * Removes a option by name for the current network.
  1909  * Removes an option by name for the current network.
  1330  *
  1910  *
  1331  * @since 2.8.0
  1911  * @since 2.8.0
  1332  * @since 4.4.0 Modified into wrapper for delete_network_option()
  1912  * @since 4.4.0 Modified into wrapper for delete_network_option()
  1333  *
  1913  *
  1334  * @see delete_network_option()
  1914  * @see delete_network_option()
  1363  *
  1943  *
  1364  * @see get_option()
  1944  * @see get_option()
  1365  *
  1945  *
  1366  * @global wpdb $wpdb WordPress database abstraction object.
  1946  * @global wpdb $wpdb WordPress database abstraction object.
  1367  *
  1947  *
  1368  * @param int    $network_id ID of the network. Can be null to default to the current network ID.
  1948  * @param int    $network_id    ID of the network. Can be null to default to the current network ID.
  1369  * @param string $option     Name of the option to retrieve. Expected to not be SQL-escaped.
  1949  * @param string $option        Name of the option to retrieve. Expected to not be SQL-escaped.
  1370  * @param mixed  $default    Optional. Value to return if the option doesn't exist. Default false.
  1950  * @param mixed  $default_value Optional. Value to return if the option doesn't exist. Default false.
  1371  * @return mixed Value set for the option.
  1951  * @return mixed Value set for the option.
  1372  */
  1952  */
  1373 function get_network_option( $network_id, $option, $default = false ) {
  1953 function get_network_option( $network_id, $option, $default_value = false ) {
  1374 	global $wpdb;
  1954 	global $wpdb;
  1375 
  1955 
  1376 	if ( $network_id && ! is_numeric( $network_id ) ) {
  1956 	if ( $network_id && ! is_numeric( $network_id ) ) {
  1377 		return false;
  1957 		return false;
  1378 	}
  1958 	}
  1387 	/**
  1967 	/**
  1388 	 * Filters the value of an existing network option before it is retrieved.
  1968 	 * Filters the value of an existing network option before it is retrieved.
  1389 	 *
  1969 	 *
  1390 	 * The dynamic portion of the hook name, `$option`, refers to the option name.
  1970 	 * The dynamic portion of the hook name, `$option`, refers to the option name.
  1391 	 *
  1971 	 *
  1392 	 * Returning a truthy value from the filter will effectively short-circuit retrieval
  1972 	 * Returning a value other than false from the filter will short-circuit retrieval
  1393 	 * and return the passed value instead.
  1973 	 * and return that value instead.
  1394 	 *
  1974 	 *
  1395 	 * @since 2.9.0 As 'pre_site_option_' . $key
  1975 	 * @since 2.9.0 As 'pre_site_option_' . $key
  1396 	 * @since 3.0.0
  1976 	 * @since 3.0.0
  1397 	 * @since 4.4.0 The `$option` parameter was added.
  1977 	 * @since 4.4.0 The `$option` parameter was added.
  1398 	 * @since 4.7.0 The `$network_id` parameter was added.
  1978 	 * @since 4.7.0 The `$network_id` parameter was added.
  1399 	 * @since 4.9.0 The `$default` parameter was added.
  1979 	 * @since 4.9.0 The `$default_value` parameter was added.
  1400 	 *
  1980 	 *
  1401 	 * @param mixed  $pre_option The value to return instead of the option value. This differs
  1981 	 * @param mixed  $pre_option    The value to return instead of the option value. This differs from
  1402 	 *                           from `$default`, which is used as the fallback value in the event
  1982 	 *                              `$default_value`, which is used as the fallback value in the event
  1403 	 *                           the option doesn't exist elsewhere in get_network_option().
  1983 	 *                              the option doesn't exist elsewhere in get_network_option().
  1404 	 *                           Default false (to skip past the short-circuit).
  1984 	 *                              Default false (to skip past the short-circuit).
  1405 	 * @param string $option     Option name.
  1985 	 * @param string $option        Option name.
  1406 	 * @param int    $network_id ID of the network.
  1986 	 * @param int    $network_id    ID of the network.
  1407 	 * @param mixed  $default    The fallback value to return if the option does not exist.
  1987 	 * @param mixed  $default_value The fallback value to return if the option does not exist.
  1408 	 *                           Default false.
  1988 	 *                              Default false.
  1409 	 */
  1989 	 */
  1410 	$pre = apply_filters( "pre_site_option_{$option}", false, $option, $network_id, $default );
  1990 	$pre = apply_filters( "pre_site_option_{$option}", false, $option, $network_id, $default_value );
  1411 
  1991 
  1412 	if ( false !== $pre ) {
  1992 	if ( false !== $pre ) {
  1413 		return $pre;
  1993 		return $pre;
  1414 	}
  1994 	}
  1415 
  1995 
  1418 	$notoptions     = wp_cache_get( $notoptions_key, 'site-options' );
  1998 	$notoptions     = wp_cache_get( $notoptions_key, 'site-options' );
  1419 
  1999 
  1420 	if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
  2000 	if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
  1421 
  2001 
  1422 		/**
  2002 		/**
  1423 		 * Filters a specific default network option.
  2003 		 * Filters the value of a specific default network option.
  1424 		 *
  2004 		 *
  1425 		 * The dynamic portion of the hook name, `$option`, refers to the option name.
  2005 		 * The dynamic portion of the hook name, `$option`, refers to the option name.
  1426 		 *
  2006 		 *
  1427 		 * @since 3.4.0
  2007 		 * @since 3.4.0
  1428 		 * @since 4.4.0 The `$option` parameter was added.
  2008 		 * @since 4.4.0 The `$option` parameter was added.
  1429 		 * @since 4.7.0 The `$network_id` parameter was added.
  2009 		 * @since 4.7.0 The `$network_id` parameter was added.
  1430 		 *
  2010 		 *
  1431 		 * @param mixed  $default    The value to return if the site option does not exist
  2011 		 * @param mixed  $default_value The value to return if the site option does not exist
  1432 		 *                           in the database.
  2012 		 *                              in the database.
  1433 		 * @param string $option     Option name.
  2013 		 * @param string $option        Option name.
  1434 		 * @param int    $network_id ID of the network.
  2014 		 * @param int    $network_id    ID of the network.
  1435 		 */
  2015 		 */
  1436 		return apply_filters( "default_site_option_{$option}", $default, $option, $network_id );
  2016 		return apply_filters( "default_site_option_{$option}", $default_value, $option, $network_id );
  1437 	}
  2017 	}
  1438 
  2018 
  1439 	if ( ! is_multisite() ) {
  2019 	if ( ! is_multisite() ) {
  1440 		/** This filter is documented in wp-includes/option.php */
  2020 		/** This filter is documented in wp-includes/option.php */
  1441 		$default = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id );
  2021 		$default_value = apply_filters( 'default_site_option_' . $option, $default_value, $option, $network_id );
  1442 		$value   = get_option( $option, $default );
  2022 		$value         = get_option( $option, $default_value );
  1443 	} else {
  2023 	} else {
  1444 		$cache_key = "$network_id:$option";
  2024 		$cache_key = "$network_id:$option";
  1445 		$value     = wp_cache_get( $cache_key, 'site-options' );
  2025 		$value     = wp_cache_get( $cache_key, 'site-options' );
  1446 
  2026 
  1447 		if ( ! isset( $value ) || false === $value ) {
  2027 		if ( ! isset( $value ) || false === $value ) {
  1459 
  2039 
  1460 				$notoptions[ $option ] = true;
  2040 				$notoptions[ $option ] = true;
  1461 				wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
  2041 				wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
  1462 
  2042 
  1463 				/** This filter is documented in wp-includes/option.php */
  2043 				/** This filter is documented in wp-includes/option.php */
  1464 				$value = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id );
  2044 				$value = apply_filters( 'default_site_option_' . $option, $default_value, $option, $network_id );
  1465 			}
  2045 			}
  1466 		}
  2046 		}
  1467 	}
  2047 	}
  1468 
  2048 
  1469 	if ( ! is_array( $notoptions ) ) {
  2049 	if ( ! is_array( $notoptions ) ) {
  1537 	$value = apply_filters( "pre_add_site_option_{$option}", $value, $option, $network_id );
  2117 	$value = apply_filters( "pre_add_site_option_{$option}", $value, $option, $network_id );
  1538 
  2118 
  1539 	$notoptions_key = "$network_id:notoptions";
  2119 	$notoptions_key = "$network_id:notoptions";
  1540 
  2120 
  1541 	if ( ! is_multisite() ) {
  2121 	if ( ! is_multisite() ) {
  1542 		$result = add_option( $option, $value, '', 'no' );
  2122 		$result = add_option( $option, $value, '', false );
  1543 	} else {
  2123 	} else {
  1544 		$cache_key = "$network_id:$option";
  2124 		$cache_key = "$network_id:$option";
  1545 
  2125 
  1546 		// Make sure the option doesn't already exist.
  2126 		/*
  1547 		// We can check the 'notoptions' cache before we ask for a DB query.
  2127 		 * Make sure the option doesn't already exist.
       
  2128 		 * We can check the 'notoptions' cache before we ask for a DB query.
       
  2129 		 */
  1548 		$notoptions = wp_cache_get( $notoptions_key, 'site-options' );
  2130 		$notoptions = wp_cache_get( $notoptions_key, 'site-options' );
  1549 
  2131 
  1550 		if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) {
  2132 		if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) {
  1551 			if ( false !== get_network_option( $network_id, $option, false ) ) {
  2133 			if ( false !== get_network_option( $network_id, $option, false ) ) {
  1552 				return false;
  2134 				return false;
  1736 		$network_id = get_current_network_id();
  2318 		$network_id = get_current_network_id();
  1737 	}
  2319 	}
  1738 
  2320 
  1739 	wp_protect_special_option( $option );
  2321 	wp_protect_special_option( $option );
  1740 
  2322 
  1741 	$old_value = get_network_option( $network_id, $option, false );
  2323 	$old_value = get_network_option( $network_id, $option );
  1742 
  2324 
  1743 	/**
  2325 	/**
  1744 	 * Filters a specific network option before its value is updated.
  2326 	 * Filters a specific network option before its value is updated.
  1745 	 *
  2327 	 *
  1746 	 * The dynamic portion of the hook name, `$option`, refers to the option name.
  2328 	 * The dynamic portion of the hook name, `$option`, refers to the option name.
  1781 		unset( $notoptions[ $option ] );
  2363 		unset( $notoptions[ $option ] );
  1782 		wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
  2364 		wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
  1783 	}
  2365 	}
  1784 
  2366 
  1785 	if ( ! is_multisite() ) {
  2367 	if ( ! is_multisite() ) {
  1786 		$result = update_option( $option, $value, 'no' );
  2368 		$result = update_option( $option, $value, false );
  1787 	} else {
  2369 	} else {
  1788 		$value = sanitize_option( $option, $value );
  2370 		$value = sanitize_option( $option, $value );
  1789 
  2371 
  1790 		$serialized_value = maybe_serialize( $value );
  2372 		$serialized_value = maybe_serialize( $value );
  1791 		$result           = $wpdb->update(
  2373 		$result           = $wpdb->update(
  1906 	/**
  2488 	/**
  1907 	 * Filters the value of an existing site transient before it is retrieved.
  2489 	 * Filters the value of an existing site transient before it is retrieved.
  1908 	 *
  2490 	 *
  1909 	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
  2491 	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
  1910 	 *
  2492 	 *
  1911 	 * Returning a truthy value from the filter will effectively short-circuit retrieval
  2493 	 * Returning a value other than boolean false will short-circuit retrieval and
  1912 	 * and return the passed value instead.
  2494 	 * return that value instead.
  1913 	 *
  2495 	 *
  1914 	 * @since 2.9.0
  2496 	 * @since 2.9.0
  1915 	 * @since 4.4.0 The `$transient` parameter was added.
  2497 	 * @since 4.4.0 The `$transient` parameter was added.
  1916 	 *
  2498 	 *
  1917 	 * @param mixed  $pre_site_transient The default value to return if the site transient does not exist.
  2499 	 * @param mixed  $pre_site_transient The default value to return if the site transient does not exist.
  1931 		// Core transients that do not have a timeout. Listed here so querying timeouts can be avoided.
  2513 		// Core transients that do not have a timeout. Listed here so querying timeouts can be avoided.
  1932 		$no_timeout       = array( 'update_core', 'update_plugins', 'update_themes' );
  2514 		$no_timeout       = array( 'update_core', 'update_plugins', 'update_themes' );
  1933 		$transient_option = '_site_transient_' . $transient;
  2515 		$transient_option = '_site_transient_' . $transient;
  1934 		if ( ! in_array( $transient, $no_timeout, true ) ) {
  2516 		if ( ! in_array( $transient, $no_timeout, true ) ) {
  1935 			$transient_timeout = '_site_transient_timeout_' . $transient;
  2517 			$transient_timeout = '_site_transient_timeout_' . $transient;
  1936 			$timeout           = get_site_option( $transient_timeout );
  2518 			wp_prime_site_option_caches( array( $transient_option, $transient_timeout ) );
       
  2519 
       
  2520 			$timeout = get_site_option( $transient_timeout );
  1937 			if ( false !== $timeout && $timeout < time() ) {
  2521 			if ( false !== $timeout && $timeout < time() ) {
  1938 				delete_site_option( $transient_option );
  2522 				delete_site_option( $transient_option );
  1939 				delete_site_option( $transient_timeout );
  2523 				delete_site_option( $transient_timeout );
  1940 				$value = false;
  2524 				$value = false;
  1941 			}
  2525 			}
  2009 	if ( wp_using_ext_object_cache() || wp_installing() ) {
  2593 	if ( wp_using_ext_object_cache() || wp_installing() ) {
  2010 		$result = wp_cache_set( $transient, $value, 'site-transient', $expiration );
  2594 		$result = wp_cache_set( $transient, $value, 'site-transient', $expiration );
  2011 	} else {
  2595 	} else {
  2012 		$transient_timeout = '_site_transient_timeout_' . $transient;
  2596 		$transient_timeout = '_site_transient_timeout_' . $transient;
  2013 		$option            = '_site_transient_' . $transient;
  2597 		$option            = '_site_transient_' . $transient;
       
  2598 		wp_prime_site_option_caches( array( $option, $transient_timeout ) );
  2014 
  2599 
  2015 		if ( false === get_site_option( $option ) ) {
  2600 		if ( false === get_site_option( $option ) ) {
  2016 			if ( $expiration ) {
  2601 			if ( $expiration ) {
  2017 				add_site_option( $transient_timeout, time() + $expiration );
  2602 				add_site_option( $transient_timeout, time() + $expiration );
  2018 			}
  2603 			}
  2072 		array(
  2657 		array(
  2073 			'show_in_rest' => array(
  2658 			'show_in_rest' => array(
  2074 				'name' => 'title',
  2659 				'name' => 'title',
  2075 			),
  2660 			),
  2076 			'type'         => 'string',
  2661 			'type'         => 'string',
       
  2662 			'label'        => __( 'Title' ),
  2077 			'description'  => __( 'Site title.' ),
  2663 			'description'  => __( 'Site title.' ),
  2078 		)
  2664 		)
  2079 	);
  2665 	);
  2080 
  2666 
  2081 	register_setting(
  2667 	register_setting(
  2084 		array(
  2670 		array(
  2085 			'show_in_rest' => array(
  2671 			'show_in_rest' => array(
  2086 				'name' => 'description',
  2672 				'name' => 'description',
  2087 			),
  2673 			),
  2088 			'type'         => 'string',
  2674 			'type'         => 'string',
       
  2675 			'label'        => __( 'Tagline' ),
  2089 			'description'  => __( 'Site tagline.' ),
  2676 			'description'  => __( 'Site tagline.' ),
  2090 		)
  2677 		)
  2091 	);
  2678 	);
  2092 
  2679 
  2093 	if ( ! is_multisite() ) {
  2680 	if ( ! is_multisite() ) {
  2214 		'reading',
  2801 		'reading',
  2215 		'posts_per_page',
  2802 		'posts_per_page',
  2216 		array(
  2803 		array(
  2217 			'show_in_rest' => true,
  2804 			'show_in_rest' => true,
  2218 			'type'         => 'integer',
  2805 			'type'         => 'integer',
       
  2806 			'label'        => __( 'Maximum posts per page' ),
  2219 			'description'  => __( 'Blog pages show at most.' ),
  2807 			'description'  => __( 'Blog pages show at most.' ),
  2220 			'default'      => 10,
  2808 			'default'      => 10,
  2221 		)
  2809 		)
  2222 	);
  2810 	);
  2223 
  2811 
  2225 		'reading',
  2813 		'reading',
  2226 		'show_on_front',
  2814 		'show_on_front',
  2227 		array(
  2815 		array(
  2228 			'show_in_rest' => true,
  2816 			'show_in_rest' => true,
  2229 			'type'         => 'string',
  2817 			'type'         => 'string',
       
  2818 			'label'        => __( 'Show on front' ),
  2230 			'description'  => __( 'What to show on the front page' ),
  2819 			'description'  => __( 'What to show on the front page' ),
  2231 		)
  2820 		)
  2232 	);
  2821 	);
  2233 
  2822 
  2234 	register_setting(
  2823 	register_setting(
  2235 		'reading',
  2824 		'reading',
  2236 		'page_on_front',
  2825 		'page_on_front',
  2237 		array(
  2826 		array(
  2238 			'show_in_rest' => true,
  2827 			'show_in_rest' => true,
  2239 			'type'         => 'integer',
  2828 			'type'         => 'integer',
       
  2829 			'label'        => __( 'Page on front' ),
  2240 			'description'  => __( 'The ID of the page that should be displayed on the front page' ),
  2830 			'description'  => __( 'The ID of the page that should be displayed on the front page' ),
  2241 		)
  2831 		)
  2242 	);
  2832 	);
  2243 
  2833 
  2244 	register_setting(
  2834 	register_setting(
  2273 				'schema' => array(
  2863 				'schema' => array(
  2274 					'enum' => array( 'open', 'closed' ),
  2864 					'enum' => array( 'open', 'closed' ),
  2275 				),
  2865 				),
  2276 			),
  2866 			),
  2277 			'type'         => 'string',
  2867 			'type'         => 'string',
       
  2868 			'label'        => __( 'Allow comments on new posts' ),
  2278 			'description'  => __( 'Allow people to submit comments on new posts.' ),
  2869 			'description'  => __( 'Allow people to submit comments on new posts.' ),
  2279 		)
  2870 		)
  2280 	);
  2871 	);
  2281 }
  2872 }
  2282 
  2873 
  2287  * @since 3.0.0 The `misc` option group was deprecated.
  2878  * @since 3.0.0 The `misc` option group was deprecated.
  2288  * @since 3.5.0 The `privacy` option group was deprecated.
  2879  * @since 3.5.0 The `privacy` option group was deprecated.
  2289  * @since 4.7.0 `$args` can be passed to set flags on the setting, similar to `register_meta()`.
  2880  * @since 4.7.0 `$args` can be passed to set flags on the setting, similar to `register_meta()`.
  2290  * @since 5.5.0 `$new_whitelist_options` was renamed to `$new_allowed_options`.
  2881  * @since 5.5.0 `$new_whitelist_options` was renamed to `$new_allowed_options`.
  2291  *              Please consider writing more inclusive code.
  2882  *              Please consider writing more inclusive code.
       
  2883  * @since 6.6.0 Added the `label` argument.
  2292  *
  2884  *
  2293  * @global array $new_allowed_options
  2885  * @global array $new_allowed_options
  2294  * @global array $wp_registered_settings
  2886  * @global array $wp_registered_settings
  2295  *
  2887  *
  2296  * @param string $option_group A settings group name. Should correspond to an allowed option key name.
  2888  * @param string $option_group A settings group name. Should correspond to an allowed option key name.
  2300  * @param array  $args {
  2892  * @param array  $args {
  2301  *     Data used to describe the setting when registered.
  2893  *     Data used to describe the setting when registered.
  2302  *
  2894  *
  2303  *     @type string     $type              The type of data associated with this setting.
  2895  *     @type string     $type              The type of data associated with this setting.
  2304  *                                         Valid values are 'string', 'boolean', 'integer', 'number', 'array', and 'object'.
  2896  *                                         Valid values are 'string', 'boolean', 'integer', 'number', 'array', and 'object'.
       
  2897  *     @type string     $label             A label of the data attached to this setting.
  2305  *     @type string     $description       A description of the data attached to this setting.
  2898  *     @type string     $description       A description of the data attached to this setting.
  2306  *     @type callable   $sanitize_callback A callback function that sanitizes the option's value.
  2899  *     @type callable   $sanitize_callback A callback function that sanitizes the option's value.
  2307  *     @type bool|array $show_in_rest      Whether data associated with this setting should be included in the REST API.
  2900  *     @type bool|array $show_in_rest      Whether data associated with this setting should be included in the REST API.
  2308  *                                         When registering complex settings, this argument may optionally be an
  2901  *                                         When registering complex settings, this argument may optionally be an
  2309  *                                         array with a 'schema' key.
  2902  *                                         array with a 'schema' key.
  2320 	$GLOBALS['new_whitelist_options'] = &$new_allowed_options;
  2913 	$GLOBALS['new_whitelist_options'] = &$new_allowed_options;
  2321 
  2914 
  2322 	$defaults = array(
  2915 	$defaults = array(
  2323 		'type'              => 'string',
  2916 		'type'              => 'string',
  2324 		'group'             => $option_group,
  2917 		'group'             => $option_group,
       
  2918 		'label'             => '',
  2325 		'description'       => '',
  2919 		'description'       => '',
  2326 		'sanitize_callback' => null,
  2920 		'sanitize_callback' => null,
  2327 		'show_in_rest'      => false,
  2921 		'show_in_rest'      => false,
  2328 	);
  2922 	);
  2329 
  2923 
  2454 			)
  3048 			)
  2455 		);
  3049 		);
  2456 		$option_group = 'reading';
  3050 		$option_group = 'reading';
  2457 	}
  3051 	}
  2458 
  3052 
  2459 	$pos = array_search( $option_name, (array) $new_allowed_options[ $option_group ], true );
  3053 	$pos = false;
       
  3054 	if ( isset( $new_allowed_options[ $option_group ] ) ) {
       
  3055 		$pos = array_search( $option_name, (array) $new_allowed_options[ $option_group ], true );
       
  3056 	}
  2460 
  3057 
  2461 	if ( false !== $pos ) {
  3058 	if ( false !== $pos ) {
  2462 		unset( $new_allowed_options[ $option_group ][ $pos ] );
  3059 		unset( $new_allowed_options[ $option_group ][ $pos ] );
  2463 	}
  3060 	}
  2464 
  3061 
  2526  * For settings which register a default setting in `register_setting()`, this
  3123  * For settings which register a default setting in `register_setting()`, this
  2527  * function is added as a filter to `default_option_{$option}`.
  3124  * function is added as a filter to `default_option_{$option}`.
  2528  *
  3125  *
  2529  * @since 4.7.0
  3126  * @since 4.7.0
  2530  *
  3127  *
  2531  * @param mixed  $default        Existing default value to return.
  3128  * @param mixed  $default_value  Existing default value to return.
  2532  * @param string $option         Option name.
  3129  * @param string $option         Option name.
  2533  * @param bool   $passed_default Was `get_option()` passed a default value?
  3130  * @param bool   $passed_default Was `get_option()` passed a default value?
  2534  * @return mixed Filtered default value.
  3131  * @return mixed Filtered default value.
  2535  */
  3132  */
  2536 function filter_default_option( $default, $option, $passed_default ) {
  3133 function filter_default_option( $default_value, $option, $passed_default ) {
  2537 	if ( $passed_default ) {
  3134 	if ( $passed_default ) {
  2538 		return $default;
  3135 		return $default_value;
  2539 	}
  3136 	}
  2540 
  3137 
  2541 	$registered = get_registered_settings();
  3138 	$registered = get_registered_settings();
  2542 	if ( empty( $registered[ $option ] ) ) {
  3139 	if ( empty( $registered[ $option ] ) ) {
  2543 		return $default;
  3140 		return $default_value;
  2544 	}
  3141 	}
  2545 
  3142 
  2546 	return $registered[ $option ]['default'];
  3143 	return $registered[ $option ]['default'];
  2547 }
  3144 }
       
  3145 
       
  3146 /**
       
  3147  * Returns the values that trigger autoloading from the options table.
       
  3148  *
       
  3149  * @since 6.6.0
       
  3150  *
       
  3151  * @return string[] The values that trigger autoloading.
       
  3152  */
       
  3153 function wp_autoload_values_to_autoload() {
       
  3154 	$autoload_values = array( 'yes', 'on', 'auto-on', 'auto' );
       
  3155 
       
  3156 	/**
       
  3157 	 * Filters the autoload values that should be considered for autoloading from the options table.
       
  3158 	 *
       
  3159 	 * The filter can only be used to remove autoload values from the default list.
       
  3160 	 *
       
  3161 	 * @since 6.6.0
       
  3162 	 *
       
  3163 	 * @param string[] $autoload_values Autoload values used to autoload option.
       
  3164 	 *                               Default list contains 'yes', 'on', 'auto-on', and 'auto'.
       
  3165 	 */
       
  3166 	$filtered_values = apply_filters( 'wp_autoload_values_to_autoload', $autoload_values );
       
  3167 
       
  3168 	return array_intersect( $filtered_values, $autoload_values );
       
  3169 }