ru-se.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

option.php (76561B)


      1 <?php
      2 /**
      3  * Option API
      4  *
      5  * @package WordPress
      6  * @subpackage Option
      7  */
      8 
      9 /**
     10  * Retrieves an option value based on an option name.
     11  *
     12  * If the option does not exist, and a default value is not provided,
     13  * boolean false is returned. This could be used to check whether you need
     14  * to initialize an option during installation of a plugin, however that
     15  * can be done better by using add_option() which will not overwrite
     16  * existing options.
     17  *
     18  * Not initializing an option and using boolean `false` as a return value
     19  * is a bad practice as it triggers an additional database query.
     20  *
     21  * The type of the returned value can be different from the type that was passed
     22  * when saving or updating the option. If the option value was serialized,
     23  * then it will be unserialized when it is returned. In this case the type will
     24  * be the same. For example, storing a non-scalar value like an array will
     25  * return the same array.
     26  *
     27  * In most cases non-string scalar and null values will be converted and returned
     28  * as string equivalents.
     29  *
     30  * Exceptions:
     31  * 1. When the option has not been saved in the database, the `$default` value
     32  *    is returned if provided. If not, boolean `false` is returned.
     33  * 2. When one of the Options API filters is used: {@see 'pre_option_{$option}'},
     34  *    {@see 'default_option_{$option}'}, or {@see 'option_{$option}'}, the returned
     35  *    value may not match the expected type.
     36  * 3. When the option has just been saved in the database, and get_option()
     37  *    is used right after, non-string scalar and null values are not converted to
     38  *    string equivalents and the original type is returned.
     39  *
     40  * Examples:
     41  *
     42  * When adding options like this: `add_option( 'my_option_name', 'value' );`
     43  * and then retrieving them with `get_option( 'my_option_name' );`, the returned
     44  * values will be:
     45  *
     46  * `false` returns `string(0) ""`
     47  * `true`  returns `string(1) "1"`
     48  * `0`     returns `string(1) "0"`
     49  * `1`     returns `string(1) "1"`
     50  * `'0'`   returns `string(1) "0"`
     51  * `'1'`   returns `string(1) "1"`
     52  * `null`  returns `string(0) ""`
     53  *
     54  * When adding options with non-scalar values like
     55  * `add_option( 'my_array', array( false, 'str', null ) );`, the returned value
     56  * will be identical to the original as it is serialized before saving
     57  * it in the database:
     58  *
     59  *    array(3) {
     60  *        [0] => bool(false)
     61  *        [1] => string(3) "str"
     62  *        [2] => NULL
     63  *    }
     64  *
     65  * @since 1.5.0
     66  *
     67  * @global wpdb $wpdb WordPress database abstraction object.
     68  *
     69  * @param string $option  Name of the option to retrieve. Expected to not be SQL-escaped.
     70  * @param mixed  $default Optional. Default value to return if the option does not exist.
     71  * @return mixed Value of the option. A value of any type may be returned, including
     72  *               scalar (string, boolean, float, integer), null, array, object.
     73  *               Scalar and null values will be returned as strings as long as they originate
     74  *               from a database stored option value. If there is no option in the database,
     75  *               boolean `false` is returned.
     76  */
     77 function get_option( $option, $default = false ) {
     78 	global $wpdb;
     79 
     80 	$option = trim( $option );
     81 	if ( empty( $option ) ) {
     82 		return false;
     83 	}
     84 
     85 	/*
     86 	 * Until a proper _deprecated_option() function can be introduced,
     87 	 * redirect requests to deprecated keys to the new, correct ones.
     88 	 */
     89 	$deprecated_keys = array(
     90 		'blacklist_keys'    => 'disallowed_keys',
     91 		'comment_whitelist' => 'comment_previously_approved',
     92 	);
     93 
     94 	if ( ! wp_installing() && isset( $deprecated_keys[ $option ] ) ) {
     95 		_deprecated_argument(
     96 			__FUNCTION__,
     97 			'5.5.0',
     98 			sprintf(
     99 				/* translators: 1: Deprecated option key, 2: New option key. */
    100 				__( 'The "%1$s" option key has been renamed to "%2$s".' ),
    101 				$option,
    102 				$deprecated_keys[ $option ]
    103 			)
    104 		);
    105 		return get_option( $deprecated_keys[ $option ], $default );
    106 	}
    107 
    108 	/**
    109 	 * Filters the value of an existing option before it is retrieved.
    110 	 *
    111 	 * The dynamic portion of the hook name, `$option`, refers to the option name.
    112 	 *
    113 	 * Returning a truthy value from the filter will effectively short-circuit retrieval
    114 	 * and return the passed value instead.
    115 	 *
    116 	 * @since 1.5.0
    117 	 * @since 4.4.0 The `$option` parameter was added.
    118 	 * @since 4.9.0 The `$default` parameter was added.
    119 	 *
    120 	 * @param mixed  $pre_option The value to return instead of the option value. This differs
    121 	 *                           from `$default`, which is used as the fallback value in the event
    122 	 *                           the option doesn't exist elsewhere in get_option().
    123 	 *                           Default false (to skip past the short-circuit).
    124 	 * @param string $option     Option name.
    125 	 * @param mixed  $default    The fallback value to return if the option does not exist.
    126 	 *                           Default false.
    127 	 */
    128 	$pre = apply_filters( "pre_option_{$option}", false, $option, $default );
    129 
    130 	if ( false !== $pre ) {
    131 		return $pre;
    132 	}
    133 
    134 	if ( defined( 'WP_SETUP_CONFIG' ) ) {
    135 		return false;
    136 	}
    137 
    138 	// Distinguish between `false` as a default, and not passing one.
    139 	$passed_default = func_num_args() > 1;
    140 
    141 	if ( ! wp_installing() ) {
    142 		// Prevent non-existent options from triggering multiple queries.
    143 		$notoptions = wp_cache_get( 'notoptions', 'options' );
    144 
    145 		if ( isset( $notoptions[ $option ] ) ) {
    146 			/**
    147 			 * Filters the default value for an option.
    148 			 *
    149 			 * The dynamic portion of the hook name, `$option`, refers to the option name.
    150 			 *
    151 			 * @since 3.4.0
    152 			 * @since 4.4.0 The `$option` parameter was added.
    153 			 * @since 4.7.0 The `$passed_default` parameter was added to distinguish between a `false` value and the default parameter value.
    154 			 *
    155 			 * @param mixed  $default The default value to return if the option does not exist
    156 			 *                        in the database.
    157 			 * @param string $option  Option name.
    158 			 * @param bool   $passed_default Was `get_option()` passed a default value?
    159 			 */
    160 			return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
    161 		}
    162 
    163 		$alloptions = wp_load_alloptions();
    164 
    165 		if ( isset( $alloptions[ $option ] ) ) {
    166 			$value = $alloptions[ $option ];
    167 		} else {
    168 			$value = wp_cache_get( $option, 'options' );
    169 
    170 			if ( false === $value ) {
    171 				$row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
    172 
    173 				// Has to be get_row() instead of get_var() because of funkiness with 0, false, null values.
    174 				if ( is_object( $row ) ) {
    175 					$value = $row->option_value;
    176 					wp_cache_add( $option, $value, 'options' );
    177 				} else { // Option does not exist, so we must cache its non-existence.
    178 					if ( ! is_array( $notoptions ) ) {
    179 						$notoptions = array();
    180 					}
    181 
    182 					$notoptions[ $option ] = true;
    183 					wp_cache_set( 'notoptions', $notoptions, 'options' );
    184 
    185 					/** This filter is documented in wp-includes/option.php */
    186 					return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
    187 				}
    188 			}
    189 		}
    190 	} else {
    191 		$suppress = $wpdb->suppress_errors();
    192 		$row      = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
    193 		$wpdb->suppress_errors( $suppress );
    194 
    195 		if ( is_object( $row ) ) {
    196 			$value = $row->option_value;
    197 		} else {
    198 			/** This filter is documented in wp-includes/option.php */
    199 			return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
    200 		}
    201 	}
    202 
    203 	// If home is not set, use siteurl.
    204 	if ( 'home' === $option && '' === $value ) {
    205 		return get_option( 'siteurl' );
    206 	}
    207 
    208 	if ( in_array( $option, array( 'siteurl', 'home', 'category_base', 'tag_base' ), true ) ) {
    209 		$value = untrailingslashit( $value );
    210 	}
    211 
    212 	/**
    213 	 * Filters the value of an existing option.
    214 	 *
    215 	 * The dynamic portion of the hook name, `$option`, refers to the option name.
    216 	 *
    217 	 * @since 1.5.0 As 'option_' . $setting
    218 	 * @since 3.0.0
    219 	 * @since 4.4.0 The `$option` parameter was added.
    220 	 *
    221 	 * @param mixed  $value  Value of the option. If stored serialized, it will be
    222 	 *                       unserialized prior to being returned.
    223 	 * @param string $option Option name.
    224 	 */
    225 	return apply_filters( "option_{$option}", maybe_unserialize( $value ), $option );
    226 }
    227 
    228 /**
    229  * Protects WordPress special option from being modified.
    230  *
    231  * Will die if $option is in protected list. Protected options are 'alloptions'
    232  * and 'notoptions' options.
    233  *
    234  * @since 2.2.0
    235  *
    236  * @param string $option Option name.
    237  */
    238 function wp_protect_special_option( $option ) {
    239 	if ( 'alloptions' === $option || 'notoptions' === $option ) {
    240 		wp_die(
    241 			sprintf(
    242 				/* translators: %s: Option name. */
    243 				__( '%s is a protected WP option and may not be modified' ),
    244 				esc_html( $option )
    245 			)
    246 		);
    247 	}
    248 }
    249 
    250 /**
    251  * Prints option value after sanitizing for forms.
    252  *
    253  * @since 1.5.0
    254  *
    255  * @param string $option Option name.
    256  */
    257 function form_option( $option ) {
    258 	echo esc_attr( get_option( $option ) );
    259 }
    260 
    261 /**
    262  * Loads and caches all autoloaded options, if available or all options.
    263  *
    264  * @since 2.2.0
    265  * @since 5.3.1 The `$force_cache` parameter was added.
    266  *
    267  * @global wpdb $wpdb WordPress database abstraction object.
    268  *
    269  * @param bool $force_cache Optional. Whether to force an update of the local cache
    270  *                          from the persistent cache. Default false.
    271  * @return array List of all options.
    272  */
    273 function wp_load_alloptions( $force_cache = false ) {
    274 	global $wpdb;
    275 
    276 	if ( ! wp_installing() || ! is_multisite() ) {
    277 		$alloptions = wp_cache_get( 'alloptions', 'options', $force_cache );
    278 	} else {
    279 		$alloptions = false;
    280 	}
    281 
    282 	if ( ! $alloptions ) {
    283 		$suppress      = $wpdb->suppress_errors();
    284 		$alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE autoload = 'yes'" );
    285 		if ( ! $alloptions_db ) {
    286 			$alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" );
    287 		}
    288 		$wpdb->suppress_errors( $suppress );
    289 
    290 		$alloptions = array();
    291 		foreach ( (array) $alloptions_db as $o ) {
    292 			$alloptions[ $o->option_name ] = $o->option_value;
    293 		}
    294 
    295 		if ( ! wp_installing() || ! is_multisite() ) {
    296 			/**
    297 			 * Filters all options before caching them.
    298 			 *
    299 			 * @since 4.9.0
    300 			 *
    301 			 * @param array $alloptions Array with all options.
    302 			 */
    303 			$alloptions = apply_filters( 'pre_cache_alloptions', $alloptions );
    304 
    305 			wp_cache_add( 'alloptions', $alloptions, 'options' );
    306 		}
    307 	}
    308 
    309 	/**
    310 	 * Filters all options after retrieving them.
    311 	 *
    312 	 * @since 4.9.0
    313 	 *
    314 	 * @param array $alloptions Array with all options.
    315 	 */
    316 	return apply_filters( 'alloptions', $alloptions );
    317 }
    318 
    319 /**
    320  * Loads and caches certain often requested site options if is_multisite() and a persistent cache is not being used.
    321  *
    322  * @since 3.0.0
    323  *
    324  * @global wpdb $wpdb WordPress database abstraction object.
    325  *
    326  * @param int $network_id Optional site ID for which to query the options. Defaults to the current site.
    327  */
    328 function wp_load_core_site_options( $network_id = null ) {
    329 	global $wpdb;
    330 
    331 	if ( ! is_multisite() || wp_using_ext_object_cache() || wp_installing() ) {
    332 		return;
    333 	}
    334 
    335 	if ( empty( $network_id ) ) {
    336 		$network_id = get_current_network_id();
    337 	}
    338 
    339 	$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' );
    340 
    341 	$core_options_in = "'" . implode( "', '", $core_options ) . "'";
    342 	$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 ) );
    343 
    344 	foreach ( $options as $option ) {
    345 		$key                = $option->meta_key;
    346 		$cache_key          = "{$network_id}:$key";
    347 		$option->meta_value = maybe_unserialize( $option->meta_value );
    348 
    349 		wp_cache_set( $cache_key, $option->meta_value, 'site-options' );
    350 	}
    351 }
    352 
    353 /**
    354  * Updates the value of an option that was already added.
    355  *
    356  * You do not need to serialize values. If the value needs to be serialized,
    357  * then it will be serialized before it is inserted into the database.
    358  * Remember, resources cannot be serialized or added as an option.
    359  *
    360  * If the option does not exist, it will be created.
    361 
    362  * This function is designed to work with or without a logged-in user. In terms of security,
    363  * plugin developers should check the current user's capabilities before updating any options.
    364  *
    365  * @since 1.0.0
    366  * @since 4.2.0 The `$autoload` parameter was added.
    367  *
    368  * @global wpdb $wpdb WordPress database abstraction object.
    369  *
    370  * @param string      $option   Name of the option to update. Expected to not be SQL-escaped.
    371  * @param mixed       $value    Option value. Must be serializable if non-scalar. Expected to not be SQL-escaped.
    372  * @param string|bool $autoload Optional. Whether to load the option when WordPress starts up. For existing options,
    373  *                              `$autoload` can only be updated using `update_option()` if `$value` is also changed.
    374  *                              Accepts 'yes'|true to enable or 'no'|false to disable. For non-existent options,
    375  *                              the default value is 'yes'. Default null.
    376  * @return bool True if the value was updated, false otherwise.
    377  */
    378 function update_option( $option, $value, $autoload = null ) {
    379 	global $wpdb;
    380 
    381 	$option = trim( $option );
    382 	if ( empty( $option ) ) {
    383 		return false;
    384 	}
    385 
    386 	/*
    387 	 * Until a proper _deprecated_option() function can be introduced,
    388 	 * redirect requests to deprecated keys to the new, correct ones.
    389 	 */
    390 	$deprecated_keys = array(
    391 		'blacklist_keys'    => 'disallowed_keys',
    392 		'comment_whitelist' => 'comment_previously_approved',
    393 	);
    394 
    395 	if ( ! wp_installing() && isset( $deprecated_keys[ $option ] ) ) {
    396 		_deprecated_argument(
    397 			__FUNCTION__,
    398 			'5.5.0',
    399 			sprintf(
    400 				/* translators: 1: Deprecated option key, 2: New option key. */
    401 				__( 'The "%1$s" option key has been renamed to "%2$s".' ),
    402 				$option,
    403 				$deprecated_keys[ $option ]
    404 			)
    405 		);
    406 		return update_option( $deprecated_keys[ $option ], $value, $autoload );
    407 	}
    408 
    409 	wp_protect_special_option( $option );
    410 
    411 	if ( is_object( $value ) ) {
    412 		$value = clone $value;
    413 	}
    414 
    415 	$value     = sanitize_option( $option, $value );
    416 	$old_value = get_option( $option );
    417 
    418 	/**
    419 	 * Filters a specific option before its value is (maybe) serialized and updated.
    420 	 *
    421 	 * The dynamic portion of the hook name, `$option`, refers to the option name.
    422 	 *
    423 	 * @since 2.6.0
    424 	 * @since 4.4.0 The `$option` parameter was added.
    425 	 *
    426 	 * @param mixed  $value     The new, unserialized option value.
    427 	 * @param mixed  $old_value The old option value.
    428 	 * @param string $option    Option name.
    429 	 */
    430 	$value = apply_filters( "pre_update_option_{$option}", $value, $old_value, $option );
    431 
    432 	/**
    433 	 * Filters an option before its value is (maybe) serialized and updated.
    434 	 *
    435 	 * @since 3.9.0
    436 	 *
    437 	 * @param mixed  $value     The new, unserialized option value.
    438 	 * @param string $option    Name of the option.
    439 	 * @param mixed  $old_value The old option value.
    440 	 */
    441 	$value = apply_filters( 'pre_update_option', $value, $option, $old_value );
    442 
    443 	/*
    444 	 * If the new and old values are the same, no need to update.
    445 	 *
    446 	 * Unserialized values will be adequate in most cases. If the unserialized
    447 	 * data differs, the (maybe) serialized data is checked to avoid
    448 	 * unnecessary database calls for otherwise identical object instances.
    449 	 *
    450 	 * See https://core.trac.wordpress.org/ticket/38903
    451 	 */
    452 	if ( $value === $old_value || maybe_serialize( $value ) === maybe_serialize( $old_value ) ) {
    453 		return false;
    454 	}
    455 
    456 	/** This filter is documented in wp-includes/option.php */
    457 	if ( apply_filters( "default_option_{$option}", false, $option, false ) === $old_value ) {
    458 		// Default setting for new options is 'yes'.
    459 		if ( null === $autoload ) {
    460 			$autoload = 'yes';
    461 		}
    462 
    463 		return add_option( $option, $value, '', $autoload );
    464 	}
    465 
    466 	$serialized_value = maybe_serialize( $value );
    467 
    468 	/**
    469 	 * Fires immediately before an option value is updated.
    470 	 *
    471 	 * @since 2.9.0
    472 	 *
    473 	 * @param string $option    Name of the option to update.
    474 	 * @param mixed  $old_value The old option value.
    475 	 * @param mixed  $value     The new option value.
    476 	 */
    477 	do_action( 'update_option', $option, $old_value, $value );
    478 
    479 	$update_args = array(
    480 		'option_value' => $serialized_value,
    481 	);
    482 
    483 	if ( null !== $autoload ) {
    484 		$update_args['autoload'] = ( 'no' === $autoload || false === $autoload ) ? 'no' : 'yes';
    485 	}
    486 
    487 	$result = $wpdb->update( $wpdb->options, $update_args, array( 'option_name' => $option ) );
    488 	if ( ! $result ) {
    489 		return false;
    490 	}
    491 
    492 	$notoptions = wp_cache_get( 'notoptions', 'options' );
    493 
    494 	if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
    495 		unset( $notoptions[ $option ] );
    496 		wp_cache_set( 'notoptions', $notoptions, 'options' );
    497 	}
    498 
    499 	if ( ! wp_installing() ) {
    500 		$alloptions = wp_load_alloptions( true );
    501 		if ( isset( $alloptions[ $option ] ) ) {
    502 			$alloptions[ $option ] = $serialized_value;
    503 			wp_cache_set( 'alloptions', $alloptions, 'options' );
    504 		} else {
    505 			wp_cache_set( $option, $serialized_value, 'options' );
    506 		}
    507 	}
    508 
    509 	/**
    510 	 * Fires after the value of a specific option has been successfully updated.
    511 	 *
    512 	 * The dynamic portion of the hook name, `$option`, refers to the option name.
    513 	 *
    514 	 * @since 2.0.1
    515 	 * @since 4.4.0 The `$option` parameter was added.
    516 	 *
    517 	 * @param mixed  $old_value The old option value.
    518 	 * @param mixed  $value     The new option value.
    519 	 * @param string $option    Option name.
    520 	 */
    521 	do_action( "update_option_{$option}", $old_value, $value, $option );
    522 
    523 	/**
    524 	 * Fires after the value of an option has been successfully updated.
    525 	 *
    526 	 * @since 2.9.0
    527 	 *
    528 	 * @param string $option    Name of the updated option.
    529 	 * @param mixed  $old_value The old option value.
    530 	 * @param mixed  $value     The new option value.
    531 	 */
    532 	do_action( 'updated_option', $option, $old_value, $value );
    533 
    534 	return true;
    535 }
    536 
    537 /**
    538  * Adds a new option.
    539  *
    540  * You do not need to serialize values. If the value needs to be serialized,
    541  * then it will be serialized before it is inserted into the database.
    542  * Remember, resources cannot be serialized or added as an option.
    543  *
    544  * You can create options without values and then update the values later.
    545  * Existing options will not be updated and checks are performed to ensure that you
    546  * aren't adding a protected WordPress option. Care should be taken to not name
    547  * options the same as the ones which are protected.
    548  *
    549  * @since 1.0.0
    550  *
    551  * @global wpdb $wpdb WordPress database abstraction object.
    552  *
    553  * @param string      $option     Name of the option to add. Expected to not be SQL-escaped.
    554  * @param mixed       $value      Optional. Option value. Must be serializable if non-scalar.
    555  *                                Expected to not be SQL-escaped.
    556  * @param string      $deprecated Optional. Description. Not used anymore.
    557  * @param string|bool $autoload   Optional. Whether to load the option when WordPress starts up.
    558  *                                Default is enabled. Accepts 'no' to disable for legacy reasons.
    559  * @return bool True if the option was added, false otherwise.
    560  */
    561 function add_option( $option, $value = '', $deprecated = '', $autoload = 'yes' ) {
    562 	global $wpdb;
    563 
    564 	if ( ! empty( $deprecated ) ) {
    565 		_deprecated_argument( __FUNCTION__, '2.3.0' );
    566 	}
    567 
    568 	$option = trim( $option );
    569 	if ( empty( $option ) ) {
    570 		return false;
    571 	}
    572 
    573 	/*
    574 	 * Until a proper _deprecated_option() function can be introduced,
    575 	 * redirect requests to deprecated keys to the new, correct ones.
    576 	 */
    577 	$deprecated_keys = array(
    578 		'blacklist_keys'    => 'disallowed_keys',
    579 		'comment_whitelist' => 'comment_previously_approved',
    580 	);
    581 
    582 	if ( ! wp_installing() && isset( $deprecated_keys[ $option ] ) ) {
    583 		_deprecated_argument(
    584 			__FUNCTION__,
    585 			'5.5.0',
    586 			sprintf(
    587 				/* translators: 1: Deprecated option key, 2: New option key. */
    588 				__( 'The "%1$s" option key has been renamed to "%2$s".' ),
    589 				$option,
    590 				$deprecated_keys[ $option ]
    591 			)
    592 		);
    593 		return add_option( $deprecated_keys[ $option ], $value, $deprecated, $autoload );
    594 	}
    595 
    596 	wp_protect_special_option( $option );
    597 
    598 	if ( is_object( $value ) ) {
    599 		$value = clone $value;
    600 	}
    601 
    602 	$value = sanitize_option( $option, $value );
    603 
    604 	// Make sure the option doesn't already exist.
    605 	// We can check the 'notoptions' cache before we ask for a DB query.
    606 	$notoptions = wp_cache_get( 'notoptions', 'options' );
    607 
    608 	if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) {
    609 		/** This filter is documented in wp-includes/option.php */
    610 		if ( apply_filters( "default_option_{$option}", false, $option, false ) !== get_option( $option ) ) {
    611 			return false;
    612 		}
    613 	}
    614 
    615 	$serialized_value = maybe_serialize( $value );
    616 	$autoload         = ( 'no' === $autoload || false === $autoload ) ? 'no' : 'yes';
    617 
    618 	/**
    619 	 * Fires before an option is added.
    620 	 *
    621 	 * @since 2.9.0
    622 	 *
    623 	 * @param string $option Name of the option to add.
    624 	 * @param mixed  $value  Value of the option.
    625 	 */
    626 	do_action( 'add_option', $option, $value );
    627 
    628 	$result = $wpdb->query( $wpdb->prepare( "INSERT INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE `option_name` = VALUES(`option_name`), `option_value` = VALUES(`option_value`), `autoload` = VALUES(`autoload`)", $option, $serialized_value, $autoload ) );
    629 	if ( ! $result ) {
    630 		return false;
    631 	}
    632 
    633 	if ( ! wp_installing() ) {
    634 		if ( 'yes' === $autoload ) {
    635 			$alloptions            = wp_load_alloptions( true );
    636 			$alloptions[ $option ] = $serialized_value;
    637 			wp_cache_set( 'alloptions', $alloptions, 'options' );
    638 		} else {
    639 			wp_cache_set( $option, $serialized_value, 'options' );
    640 		}
    641 	}
    642 
    643 	// This option exists now.
    644 	$notoptions = wp_cache_get( 'notoptions', 'options' ); // Yes, again... we need it to be fresh.
    645 
    646 	if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
    647 		unset( $notoptions[ $option ] );
    648 		wp_cache_set( 'notoptions', $notoptions, 'options' );
    649 	}
    650 
    651 	/**
    652 	 * Fires after a specific option has been added.
    653 	 *
    654 	 * The dynamic portion of the hook name, `$option`, refers to the option name.
    655 	 *
    656 	 * @since 2.5.0 As "add_option_{$name}"
    657 	 * @since 3.0.0
    658 	 *
    659 	 * @param string $option Name of the option to add.
    660 	 * @param mixed  $value  Value of the option.
    661 	 */
    662 	do_action( "add_option_{$option}", $option, $value );
    663 
    664 	/**
    665 	 * Fires after an option has been added.
    666 	 *
    667 	 * @since 2.9.0
    668 	 *
    669 	 * @param string $option Name of the added option.
    670 	 * @param mixed  $value  Value of the option.
    671 	 */
    672 	do_action( 'added_option', $option, $value );
    673 
    674 	return true;
    675 }
    676 
    677 /**
    678  * Removes option by name. Prevents removal of protected WordPress options.
    679  *
    680  * @since 1.2.0
    681  *
    682  * @global wpdb $wpdb WordPress database abstraction object.
    683  *
    684  * @param string $option Name of the option to delete. Expected to not be SQL-escaped.
    685  * @return bool True if the option was deleted, false otherwise.
    686  */
    687 function delete_option( $option ) {
    688 	global $wpdb;
    689 
    690 	$option = trim( $option );
    691 	if ( empty( $option ) ) {
    692 		return false;
    693 	}
    694 
    695 	wp_protect_special_option( $option );
    696 
    697 	// Get the ID, if no ID then return.
    698 	$row = $wpdb->get_row( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s", $option ) );
    699 	if ( is_null( $row ) ) {
    700 		return false;
    701 	}
    702 
    703 	/**
    704 	 * Fires immediately before an option is deleted.
    705 	 *
    706 	 * @since 2.9.0
    707 	 *
    708 	 * @param string $option Name of the option to delete.
    709 	 */
    710 	do_action( 'delete_option', $option );
    711 
    712 	$result = $wpdb->delete( $wpdb->options, array( 'option_name' => $option ) );
    713 
    714 	if ( ! wp_installing() ) {
    715 		if ( 'yes' === $row->autoload ) {
    716 			$alloptions = wp_load_alloptions( true );
    717 			if ( is_array( $alloptions ) && isset( $alloptions[ $option ] ) ) {
    718 				unset( $alloptions[ $option ] );
    719 				wp_cache_set( 'alloptions', $alloptions, 'options' );
    720 			}
    721 		} else {
    722 			wp_cache_delete( $option, 'options' );
    723 		}
    724 	}
    725 
    726 	if ( $result ) {
    727 
    728 		/**
    729 		 * Fires after a specific option has been deleted.
    730 		 *
    731 		 * The dynamic portion of the hook name, `$option`, refers to the option name.
    732 		 *
    733 		 * @since 3.0.0
    734 		 *
    735 		 * @param string $option Name of the deleted option.
    736 		 */
    737 		do_action( "delete_option_{$option}", $option );
    738 
    739 		/**
    740 		 * Fires after an option has been deleted.
    741 		 *
    742 		 * @since 2.9.0
    743 		 *
    744 		 * @param string $option Name of the deleted option.
    745 		 */
    746 		do_action( 'deleted_option', $option );
    747 
    748 		return true;
    749 	}
    750 
    751 	return false;
    752 }
    753 
    754 /**
    755  * Deletes a transient.
    756  *
    757  * @since 2.8.0
    758  *
    759  * @param string $transient Transient name. Expected to not be SQL-escaped.
    760  * @return bool True if the transient was deleted, false otherwise.
    761  */
    762 function delete_transient( $transient ) {
    763 
    764 	/**
    765 	 * Fires immediately before a specific transient is deleted.
    766 	 *
    767 	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
    768 	 *
    769 	 * @since 3.0.0
    770 	 *
    771 	 * @param string $transient Transient name.
    772 	 */
    773 	do_action( "delete_transient_{$transient}", $transient );
    774 
    775 	if ( wp_using_ext_object_cache() ) {
    776 		$result = wp_cache_delete( $transient, 'transient' );
    777 	} else {
    778 		$option_timeout = '_transient_timeout_' . $transient;
    779 		$option         = '_transient_' . $transient;
    780 		$result         = delete_option( $option );
    781 
    782 		if ( $result ) {
    783 			delete_option( $option_timeout );
    784 		}
    785 	}
    786 
    787 	if ( $result ) {
    788 
    789 		/**
    790 		 * Fires after a transient is deleted.
    791 		 *
    792 		 * @since 3.0.0
    793 		 *
    794 		 * @param string $transient Deleted transient name.
    795 		 */
    796 		do_action( 'deleted_transient', $transient );
    797 	}
    798 
    799 	return $result;
    800 }
    801 
    802 /**
    803  * Retrieves the value of a transient.
    804  *
    805  * If the transient does not exist, does not have a value, or has expired,
    806  * then the return value will be false.
    807  *
    808  * @since 2.8.0
    809  *
    810  * @param string $transient Transient name. Expected to not be SQL-escaped.
    811  * @return mixed Value of transient.
    812  */
    813 function get_transient( $transient ) {
    814 
    815 	/**
    816 	 * Filters the value of an existing transient before it is retrieved.
    817 	 *
    818 	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
    819 	 *
    820 	 * Returning a truthy value from the filter will effectively short-circuit retrieval
    821 	 * and return the passed value instead.
    822 	 *
    823 	 * @since 2.8.0
    824 	 * @since 4.4.0 The `$transient` parameter was added
    825 	 *
    826 	 * @param mixed  $pre_transient The default value to return if the transient does not exist.
    827 	 *                              Any value other than false will short-circuit the retrieval
    828 	 *                              of the transient, and return that value.
    829 	 * @param string $transient     Transient name.
    830 	 */
    831 	$pre = apply_filters( "pre_transient_{$transient}", false, $transient );
    832 
    833 	if ( false !== $pre ) {
    834 		return $pre;
    835 	}
    836 
    837 	if ( wp_using_ext_object_cache() ) {
    838 		$value = wp_cache_get( $transient, 'transient' );
    839 	} else {
    840 		$transient_option = '_transient_' . $transient;
    841 		if ( ! wp_installing() ) {
    842 			// If option is not in alloptions, it is not autoloaded and thus has a timeout.
    843 			$alloptions = wp_load_alloptions();
    844 			if ( ! isset( $alloptions[ $transient_option ] ) ) {
    845 				$transient_timeout = '_transient_timeout_' . $transient;
    846 				$timeout           = get_option( $transient_timeout );
    847 				if ( false !== $timeout && $timeout < time() ) {
    848 					delete_option( $transient_option );
    849 					delete_option( $transient_timeout );
    850 					$value = false;
    851 				}
    852 			}
    853 		}
    854 
    855 		if ( ! isset( $value ) ) {
    856 			$value = get_option( $transient_option );
    857 		}
    858 	}
    859 
    860 	/**
    861 	 * Filters an existing transient's value.
    862 	 *
    863 	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
    864 	 *
    865 	 * @since 2.8.0
    866 	 * @since 4.4.0 The `$transient` parameter was added
    867 	 *
    868 	 * @param mixed  $value     Value of transient.
    869 	 * @param string $transient Transient name.
    870 	 */
    871 	return apply_filters( "transient_{$transient}", $value, $transient );
    872 }
    873 
    874 /**
    875  * Sets/updates the value of a transient.
    876  *
    877  * You do not need to serialize values. If the value needs to be serialized,
    878  * then it will be serialized before it is set.
    879  *
    880  * @since 2.8.0
    881  *
    882  * @param string $transient  Transient name. Expected to not be SQL-escaped.
    883  *                           Must be 172 characters or fewer in length.
    884  * @param mixed  $value      Transient value. Must be serializable if non-scalar.
    885  *                           Expected to not be SQL-escaped.
    886  * @param int    $expiration Optional. Time until expiration in seconds. Default 0 (no expiration).
    887  * @return bool True if the value was set, false otherwise.
    888  */
    889 function set_transient( $transient, $value, $expiration = 0 ) {
    890 
    891 	$expiration = (int) $expiration;
    892 
    893 	/**
    894 	 * Filters a specific transient before its value is set.
    895 	 *
    896 	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
    897 	 *
    898 	 * @since 3.0.0
    899 	 * @since 4.2.0 The `$expiration` parameter was added.
    900 	 * @since 4.4.0 The `$transient` parameter was added.
    901 	 *
    902 	 * @param mixed  $value      New value of transient.
    903 	 * @param int    $expiration Time until expiration in seconds.
    904 	 * @param string $transient  Transient name.
    905 	 */
    906 	$value = apply_filters( "pre_set_transient_{$transient}", $value, $expiration, $transient );
    907 
    908 	/**
    909 	 * Filters the expiration for a transient before its value is set.
    910 	 *
    911 	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
    912 	 *
    913 	 * @since 4.4.0
    914 	 *
    915 	 * @param int    $expiration Time until expiration in seconds. Use 0 for no expiration.
    916 	 * @param mixed  $value      New value of transient.
    917 	 * @param string $transient  Transient name.
    918 	 */
    919 	$expiration = apply_filters( "expiration_of_transient_{$transient}", $expiration, $value, $transient );
    920 
    921 	if ( wp_using_ext_object_cache() ) {
    922 		$result = wp_cache_set( $transient, $value, 'transient', $expiration );
    923 	} else {
    924 		$transient_timeout = '_transient_timeout_' . $transient;
    925 		$transient_option  = '_transient_' . $transient;
    926 
    927 		if ( false === get_option( $transient_option ) ) {
    928 			$autoload = 'yes';
    929 			if ( $expiration ) {
    930 				$autoload = 'no';
    931 				add_option( $transient_timeout, time() + $expiration, '', 'no' );
    932 			}
    933 			$result = add_option( $transient_option, $value, '', $autoload );
    934 		} else {
    935 			// If expiration is requested, but the transient has no timeout option,
    936 			// delete, then re-create transient rather than update.
    937 			$update = true;
    938 
    939 			if ( $expiration ) {
    940 				if ( false === get_option( $transient_timeout ) ) {
    941 					delete_option( $transient_option );
    942 					add_option( $transient_timeout, time() + $expiration, '', 'no' );
    943 					$result = add_option( $transient_option, $value, '', 'no' );
    944 					$update = false;
    945 				} else {
    946 					update_option( $transient_timeout, time() + $expiration );
    947 				}
    948 			}
    949 
    950 			if ( $update ) {
    951 				$result = update_option( $transient_option, $value );
    952 			}
    953 		}
    954 	}
    955 
    956 	if ( $result ) {
    957 
    958 		/**
    959 		 * Fires after the value for a specific transient has been set.
    960 		 *
    961 		 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
    962 		 *
    963 		 * @since 3.0.0
    964 		 * @since 3.6.0 The `$value` and `$expiration` parameters were added.
    965 		 * @since 4.4.0 The `$transient` parameter was added.
    966 		 *
    967 		 * @param mixed  $value      Transient value.
    968 		 * @param int    $expiration Time until expiration in seconds.
    969 		 * @param string $transient  The name of the transient.
    970 		 */
    971 		do_action( "set_transient_{$transient}", $value, $expiration, $transient );
    972 
    973 		/**
    974 		 * Fires after the value for a transient has been set.
    975 		 *
    976 		 * @since 3.0.0
    977 		 * @since 3.6.0 The `$value` and `$expiration` parameters were added.
    978 		 *
    979 		 * @param string $transient  The name of the transient.
    980 		 * @param mixed  $value      Transient value.
    981 		 * @param int    $expiration Time until expiration in seconds.
    982 		 */
    983 		do_action( 'setted_transient', $transient, $value, $expiration );
    984 	}
    985 
    986 	return $result;
    987 }
    988 
    989 /**
    990  * Deletes all expired transients.
    991  *
    992  * The multi-table delete syntax is used to delete the transient record
    993  * from table a, and the corresponding transient_timeout record from table b.
    994  *
    995  * @since 4.9.0
    996  *
    997  * @param bool $force_db Optional. Force cleanup to run against the database even when an external object cache is used.
    998  */
    999 function delete_expired_transients( $force_db = false ) {
   1000 	global $wpdb;
   1001 
   1002 	if ( ! $force_db && wp_using_ext_object_cache() ) {
   1003 		return;
   1004 	}
   1005 
   1006 	$wpdb->query(
   1007 		$wpdb->prepare(
   1008 			"DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b
   1009 			WHERE a.option_name LIKE %s
   1010 			AND a.option_name NOT LIKE %s
   1011 			AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) )
   1012 			AND b.option_value < %d",
   1013 			$wpdb->esc_like( '_transient_' ) . '%',
   1014 			$wpdb->esc_like( '_transient_timeout_' ) . '%',
   1015 			time()
   1016 		)
   1017 	);
   1018 
   1019 	if ( ! is_multisite() ) {
   1020 		// Single site stores site transients in the options table.
   1021 		$wpdb->query(
   1022 			$wpdb->prepare(
   1023 				"DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b
   1024 				WHERE a.option_name LIKE %s
   1025 				AND a.option_name NOT LIKE %s
   1026 				AND b.option_name = CONCAT( '_site_transient_timeout_', SUBSTRING( a.option_name, 17 ) )
   1027 				AND b.option_value < %d",
   1028 				$wpdb->esc_like( '_site_transient_' ) . '%',
   1029 				$wpdb->esc_like( '_site_transient_timeout_' ) . '%',
   1030 				time()
   1031 			)
   1032 		);
   1033 	} elseif ( is_multisite() && is_main_site() && is_main_network() ) {
   1034 		// Multisite stores site transients in the sitemeta table.
   1035 		$wpdb->query(
   1036 			$wpdb->prepare(
   1037 				"DELETE a, b FROM {$wpdb->sitemeta} a, {$wpdb->sitemeta} b
   1038 				WHERE a.meta_key LIKE %s
   1039 				AND a.meta_key NOT LIKE %s
   1040 				AND b.meta_key = CONCAT( '_site_transient_timeout_', SUBSTRING( a.meta_key, 17 ) )
   1041 				AND b.meta_value < %d",
   1042 				$wpdb->esc_like( '_site_transient_' ) . '%',
   1043 				$wpdb->esc_like( '_site_transient_timeout_' ) . '%',
   1044 				time()
   1045 			)
   1046 		);
   1047 	}
   1048 }
   1049 
   1050 /**
   1051  * Saves and restores user interface settings stored in a cookie.
   1052  *
   1053  * Checks if the current user-settings cookie is updated and stores it. When no
   1054  * cookie exists (different browser used), adds the last saved cookie restoring
   1055  * the settings.
   1056  *
   1057  * @since 2.7.0
   1058  */
   1059 function wp_user_settings() {
   1060 
   1061 	if ( ! is_admin() || wp_doing_ajax() ) {
   1062 		return;
   1063 	}
   1064 
   1065 	$user_id = get_current_user_id();
   1066 	if ( ! $user_id ) {
   1067 		return;
   1068 	}
   1069 
   1070 	if ( ! is_user_member_of_blog() ) {
   1071 		return;
   1072 	}
   1073 
   1074 	$settings = (string) get_user_option( 'user-settings', $user_id );
   1075 
   1076 	if ( isset( $_COOKIE[ 'wp-settings-' . $user_id ] ) ) {
   1077 		$cookie = preg_replace( '/[^A-Za-z0-9=&_]/', '', $_COOKIE[ 'wp-settings-' . $user_id ] );
   1078 
   1079 		// No change or both empty.
   1080 		if ( $cookie == $settings ) {
   1081 			return;
   1082 		}
   1083 
   1084 		$last_saved = (int) get_user_option( 'user-settings-time', $user_id );
   1085 		$current    = isset( $_COOKIE[ 'wp-settings-time-' . $user_id ] ) ? preg_replace( '/[^0-9]/', '', $_COOKIE[ 'wp-settings-time-' . $user_id ] ) : 0;
   1086 
   1087 		// The cookie is newer than the saved value. Update the user_option and leave the cookie as-is.
   1088 		if ( $current > $last_saved ) {
   1089 			update_user_option( $user_id, 'user-settings', $cookie, false );
   1090 			update_user_option( $user_id, 'user-settings-time', time() - 5, false );
   1091 			return;
   1092 		}
   1093 	}
   1094 
   1095 	// The cookie is not set in the current browser or the saved value is newer.
   1096 	$secure = ( 'https' === parse_url( admin_url(), PHP_URL_SCHEME ) );
   1097 	setcookie( 'wp-settings-' . $user_id, $settings, time() + YEAR_IN_SECONDS, SITECOOKIEPATH, null, $secure );
   1098 	setcookie( 'wp-settings-time-' . $user_id, time(), time() + YEAR_IN_SECONDS, SITECOOKIEPATH, null, $secure );
   1099 	$_COOKIE[ 'wp-settings-' . $user_id ] = $settings;
   1100 }
   1101 
   1102 /**
   1103  * Retrieves user interface setting value based on setting name.
   1104  *
   1105  * @since 2.7.0
   1106  *
   1107  * @param string       $name    The name of the setting.
   1108  * @param string|false $default Optional. Default value to return when $name is not set. Default false.
   1109  * @return mixed The last saved user setting or the default value/false if it doesn't exist.
   1110  */
   1111 function get_user_setting( $name, $default = false ) {
   1112 	$all_user_settings = get_all_user_settings();
   1113 
   1114 	return isset( $all_user_settings[ $name ] ) ? $all_user_settings[ $name ] : $default;
   1115 }
   1116 
   1117 /**
   1118  * Adds or updates user interface setting.
   1119  *
   1120  * Both $name and $value can contain only ASCII letters, numbers, hyphens, and underscores.
   1121  *
   1122  * This function has to be used before any output has started as it calls setcookie().
   1123  *
   1124  * @since 2.8.0
   1125  *
   1126  * @param string $name  The name of the setting.
   1127  * @param string $value The value for the setting.
   1128  * @return bool|null True if set successfully, false otherwise.
   1129  *                   Null if the current user is not a member of the site.
   1130  */
   1131 function set_user_setting( $name, $value ) {
   1132 	if ( headers_sent() ) {
   1133 		return false;
   1134 	}
   1135 
   1136 	$all_user_settings          = get_all_user_settings();
   1137 	$all_user_settings[ $name ] = $value;
   1138 
   1139 	return wp_set_all_user_settings( $all_user_settings );
   1140 }
   1141 
   1142 /**
   1143  * Deletes user interface settings.
   1144  *
   1145  * Deleting settings would reset them to the defaults.
   1146  *
   1147  * This function has to be used before any output has started as it calls setcookie().
   1148  *
   1149  * @since 2.7.0
   1150  *
   1151  * @param string $names The name or array of names of the setting to be deleted.
   1152  * @return bool|null True if deleted successfully, false otherwise.
   1153  *                   Null if the current user is not a member of the site.
   1154  */
   1155 function delete_user_setting( $names ) {
   1156 	if ( headers_sent() ) {
   1157 		return false;
   1158 	}
   1159 
   1160 	$all_user_settings = get_all_user_settings();
   1161 	$names             = (array) $names;
   1162 	$deleted           = false;
   1163 
   1164 	foreach ( $names as $name ) {
   1165 		if ( isset( $all_user_settings[ $name ] ) ) {
   1166 			unset( $all_user_settings[ $name ] );
   1167 			$deleted = true;
   1168 		}
   1169 	}
   1170 
   1171 	if ( $deleted ) {
   1172 		return wp_set_all_user_settings( $all_user_settings );
   1173 	}
   1174 
   1175 	return false;
   1176 }
   1177 
   1178 /**
   1179  * Retrieves all user interface settings.
   1180  *
   1181  * @since 2.7.0
   1182  *
   1183  * @global array $_updated_user_settings
   1184  *
   1185  * @return array The last saved user settings or empty array.
   1186  */
   1187 function get_all_user_settings() {
   1188 	global $_updated_user_settings;
   1189 
   1190 	$user_id = get_current_user_id();
   1191 	if ( ! $user_id ) {
   1192 		return array();
   1193 	}
   1194 
   1195 	if ( isset( $_updated_user_settings ) && is_array( $_updated_user_settings ) ) {
   1196 		return $_updated_user_settings;
   1197 	}
   1198 
   1199 	$user_settings = array();
   1200 
   1201 	if ( isset( $_COOKIE[ 'wp-settings-' . $user_id ] ) ) {
   1202 		$cookie = preg_replace( '/[^A-Za-z0-9=&_-]/', '', $_COOKIE[ 'wp-settings-' . $user_id ] );
   1203 
   1204 		if ( strpos( $cookie, '=' ) ) { // '=' cannot be 1st char.
   1205 			parse_str( $cookie, $user_settings );
   1206 		}
   1207 	} else {
   1208 		$option = get_user_option( 'user-settings', $user_id );
   1209 
   1210 		if ( $option && is_string( $option ) ) {
   1211 			parse_str( $option, $user_settings );
   1212 		}
   1213 	}
   1214 
   1215 	$_updated_user_settings = $user_settings;
   1216 	return $user_settings;
   1217 }
   1218 
   1219 /**
   1220  * Private. Sets all user interface settings.
   1221  *
   1222  * @since 2.8.0
   1223  * @access private
   1224  *
   1225  * @global array $_updated_user_settings
   1226  *
   1227  * @param array $user_settings User settings.
   1228  * @return bool|null True if set successfully, false if the current user could not be found.
   1229  *                   Null if the current user is not a member of the site.
   1230  */
   1231 function wp_set_all_user_settings( $user_settings ) {
   1232 	global $_updated_user_settings;
   1233 
   1234 	$user_id = get_current_user_id();
   1235 	if ( ! $user_id ) {
   1236 		return false;
   1237 	}
   1238 
   1239 	if ( ! is_user_member_of_blog() ) {
   1240 		return;
   1241 	}
   1242 
   1243 	$settings = '';
   1244 	foreach ( $user_settings as $name => $value ) {
   1245 		$_name  = preg_replace( '/[^A-Za-z0-9_-]+/', '', $name );
   1246 		$_value = preg_replace( '/[^A-Za-z0-9_-]+/', '', $value );
   1247 
   1248 		if ( ! empty( $_name ) ) {
   1249 			$settings .= $_name . '=' . $_value . '&';
   1250 		}
   1251 	}
   1252 
   1253 	$settings = rtrim( $settings, '&' );
   1254 	parse_str( $settings, $_updated_user_settings );
   1255 
   1256 	update_user_option( $user_id, 'user-settings', $settings, false );
   1257 	update_user_option( $user_id, 'user-settings-time', time(), false );
   1258 
   1259 	return true;
   1260 }
   1261 
   1262 /**
   1263  * Deletes the user settings of the current user.
   1264  *
   1265  * @since 2.7.0
   1266  */
   1267 function delete_all_user_settings() {
   1268 	$user_id = get_current_user_id();
   1269 	if ( ! $user_id ) {
   1270 		return;
   1271 	}
   1272 
   1273 	update_user_option( $user_id, 'user-settings', '', false );
   1274 	setcookie( 'wp-settings-' . $user_id, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH );
   1275 }
   1276 
   1277 /**
   1278  * Retrieve an option value for the current network based on name of option.
   1279  *
   1280  * @since 2.8.0
   1281  * @since 4.4.0 The `$use_cache` parameter was deprecated.
   1282  * @since 4.4.0 Modified into wrapper for get_network_option()
   1283  *
   1284  * @see get_network_option()
   1285  *
   1286  * @param string $option     Name of the option to retrieve. Expected to not be SQL-escaped.
   1287  * @param mixed  $default    Optional. Value to return if the option doesn't exist. Default false.
   1288  * @param bool   $deprecated Whether to use cache. Multisite only. Always set to true.
   1289  * @return mixed Value set for the option.
   1290  */
   1291 function get_site_option( $option, $default = false, $deprecated = true ) {
   1292 	return get_network_option( null, $option, $default );
   1293 }
   1294 
   1295 /**
   1296  * Adds a new option for the current network.
   1297  *
   1298  * Existing options will not be updated. Note that prior to 3.3 this wasn't the case.
   1299  *
   1300  * @since 2.8.0
   1301  * @since 4.4.0 Modified into wrapper for add_network_option()
   1302  *
   1303  * @see add_network_option()
   1304  *
   1305  * @param string $option Name of the option to add. Expected to not be SQL-escaped.
   1306  * @param mixed  $value  Option value, can be anything. Expected to not be SQL-escaped.
   1307  * @return bool True if the option was added, false otherwise.
   1308  */
   1309 function add_site_option( $option, $value ) {
   1310 	return add_network_option( null, $option, $value );
   1311 }
   1312 
   1313 /**
   1314  * Removes a option by name for the current network.
   1315  *
   1316  * @since 2.8.0
   1317  * @since 4.4.0 Modified into wrapper for delete_network_option()
   1318  *
   1319  * @see delete_network_option()
   1320  *
   1321  * @param string $option Name of the option to delete. Expected to not be SQL-escaped.
   1322  * @return bool True if the option was deleted, false otherwise.
   1323  */
   1324 function delete_site_option( $option ) {
   1325 	return delete_network_option( null, $option );
   1326 }
   1327 
   1328 /**
   1329  * Updates the value of an option that was already added for the current network.
   1330  *
   1331  * @since 2.8.0
   1332  * @since 4.4.0 Modified into wrapper for update_network_option()
   1333  *
   1334  * @see update_network_option()
   1335  *
   1336  * @param string $option Name of the option. Expected to not be SQL-escaped.
   1337  * @param mixed  $value  Option value. Expected to not be SQL-escaped.
   1338  * @return bool True if the value was updated, false otherwise.
   1339  */
   1340 function update_site_option( $option, $value ) {
   1341 	return update_network_option( null, $option, $value );
   1342 }
   1343 
   1344 /**
   1345  * Retrieves a network's option value based on the option name.
   1346  *
   1347  * @since 4.4.0
   1348  *
   1349  * @see get_option()
   1350  *
   1351  * @global wpdb $wpdb WordPress database abstraction object.
   1352  *
   1353  * @param int    $network_id ID of the network. Can be null to default to the current network ID.
   1354  * @param string $option     Name of the option to retrieve. Expected to not be SQL-escaped.
   1355  * @param mixed  $default    Optional. Value to return if the option doesn't exist. Default false.
   1356  * @return mixed Value set for the option.
   1357  */
   1358 function get_network_option( $network_id, $option, $default = false ) {
   1359 	global $wpdb;
   1360 
   1361 	if ( $network_id && ! is_numeric( $network_id ) ) {
   1362 		return false;
   1363 	}
   1364 
   1365 	$network_id = (int) $network_id;
   1366 
   1367 	// Fallback to the current network if a network ID is not specified.
   1368 	if ( ! $network_id ) {
   1369 		$network_id = get_current_network_id();
   1370 	}
   1371 
   1372 	/**
   1373 	 * Filters the value of an existing network option before it is retrieved.
   1374 	 *
   1375 	 * The dynamic portion of the hook name, `$option`, refers to the option name.
   1376 	 *
   1377 	 * Returning a truthy value from the filter will effectively short-circuit retrieval
   1378 	 * and return the passed value instead.
   1379 	 *
   1380 	 * @since 2.9.0 As 'pre_site_option_' . $key
   1381 	 * @since 3.0.0
   1382 	 * @since 4.4.0 The `$option` parameter was added.
   1383 	 * @since 4.7.0 The `$network_id` parameter was added.
   1384 	 * @since 4.9.0 The `$default` parameter was added.
   1385 	 *
   1386 	 * @param mixed  $pre_option The value to return instead of the option value. This differs
   1387 	 *                           from `$default`, which is used as the fallback value in the event
   1388 	 *                           the option doesn't exist elsewhere in get_network_option().
   1389 	 *                           Default false (to skip past the short-circuit).
   1390 	 * @param string $option     Option name.
   1391 	 * @param int    $network_id ID of the network.
   1392 	 * @param mixed  $default    The fallback value to return if the option does not exist.
   1393 	 *                           Default false.
   1394 	 */
   1395 	$pre = apply_filters( "pre_site_option_{$option}", false, $option, $network_id, $default );
   1396 
   1397 	if ( false !== $pre ) {
   1398 		return $pre;
   1399 	}
   1400 
   1401 	// Prevent non-existent options from triggering multiple queries.
   1402 	$notoptions_key = "$network_id:notoptions";
   1403 	$notoptions     = wp_cache_get( $notoptions_key, 'site-options' );
   1404 
   1405 	if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
   1406 
   1407 		/**
   1408 		 * Filters a specific default network option.
   1409 		 *
   1410 		 * The dynamic portion of the hook name, `$option`, refers to the option name.
   1411 		 *
   1412 		 * @since 3.4.0
   1413 		 * @since 4.4.0 The `$option` parameter was added.
   1414 		 * @since 4.7.0 The `$network_id` parameter was added.
   1415 		 *
   1416 		 * @param mixed  $default    The value to return if the site option does not exist
   1417 		 *                           in the database.
   1418 		 * @param string $option     Option name.
   1419 		 * @param int    $network_id ID of the network.
   1420 		 */
   1421 		return apply_filters( "default_site_option_{$option}", $default, $option, $network_id );
   1422 	}
   1423 
   1424 	if ( ! is_multisite() ) {
   1425 		/** This filter is documented in wp-includes/option.php */
   1426 		$default = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id );
   1427 		$value   = get_option( $option, $default );
   1428 	} else {
   1429 		$cache_key = "$network_id:$option";
   1430 		$value     = wp_cache_get( $cache_key, 'site-options' );
   1431 
   1432 		if ( ! isset( $value ) || false === $value ) {
   1433 			$row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
   1434 
   1435 			// Has to be get_row() instead of get_var() because of funkiness with 0, false, null values.
   1436 			if ( is_object( $row ) ) {
   1437 				$value = $row->meta_value;
   1438 				$value = maybe_unserialize( $value );
   1439 				wp_cache_set( $cache_key, $value, 'site-options' );
   1440 			} else {
   1441 				if ( ! is_array( $notoptions ) ) {
   1442 					$notoptions = array();
   1443 				}
   1444 
   1445 				$notoptions[ $option ] = true;
   1446 				wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
   1447 
   1448 				/** This filter is documented in wp-includes/option.php */
   1449 				$value = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id );
   1450 			}
   1451 		}
   1452 	}
   1453 
   1454 	if ( ! is_array( $notoptions ) ) {
   1455 		$notoptions = array();
   1456 		wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
   1457 	}
   1458 
   1459 	/**
   1460 	 * Filters the value of an existing network option.
   1461 	 *
   1462 	 * The dynamic portion of the hook name, `$option`, refers to the option name.
   1463 	 *
   1464 	 * @since 2.9.0 As 'site_option_' . $key
   1465 	 * @since 3.0.0
   1466 	 * @since 4.4.0 The `$option` parameter was added.
   1467 	 * @since 4.7.0 The `$network_id` parameter was added.
   1468 	 *
   1469 	 * @param mixed  $value      Value of network option.
   1470 	 * @param string $option     Option name.
   1471 	 * @param int    $network_id ID of the network.
   1472 	 */
   1473 	return apply_filters( "site_option_{$option}", $value, $option, $network_id );
   1474 }
   1475 
   1476 /**
   1477  * Adds a new network option.
   1478  *
   1479  * Existing options will not be updated.
   1480  *
   1481  * @since 4.4.0
   1482  *
   1483  * @see add_option()
   1484  *
   1485  * @global wpdb $wpdb WordPress database abstraction object.
   1486  *
   1487  * @param int    $network_id ID of the network. Can be null to default to the current network ID.
   1488  * @param string $option     Name of the option to add. Expected to not be SQL-escaped.
   1489  * @param mixed  $value      Option value, can be anything. Expected to not be SQL-escaped.
   1490  * @return bool True if the option was added, false otherwise.
   1491  */
   1492 function add_network_option( $network_id, $option, $value ) {
   1493 	global $wpdb;
   1494 
   1495 	if ( $network_id && ! is_numeric( $network_id ) ) {
   1496 		return false;
   1497 	}
   1498 
   1499 	$network_id = (int) $network_id;
   1500 
   1501 	// Fallback to the current network if a network ID is not specified.
   1502 	if ( ! $network_id ) {
   1503 		$network_id = get_current_network_id();
   1504 	}
   1505 
   1506 	wp_protect_special_option( $option );
   1507 
   1508 	/**
   1509 	 * Filters the value of a specific network option before it is added.
   1510 	 *
   1511 	 * The dynamic portion of the hook name, `$option`, refers to the option name.
   1512 	 *
   1513 	 * @since 2.9.0 As 'pre_add_site_option_' . $key
   1514 	 * @since 3.0.0
   1515 	 * @since 4.4.0 The `$option` parameter was added.
   1516 	 * @since 4.7.0 The `$network_id` parameter was added.
   1517 	 *
   1518 	 * @param mixed  $value      Value of network option.
   1519 	 * @param string $option     Option name.
   1520 	 * @param int    $network_id ID of the network.
   1521 	 */
   1522 	$value = apply_filters( "pre_add_site_option_{$option}", $value, $option, $network_id );
   1523 
   1524 	$notoptions_key = "$network_id:notoptions";
   1525 
   1526 	if ( ! is_multisite() ) {
   1527 		$result = add_option( $option, $value, '', 'no' );
   1528 	} else {
   1529 		$cache_key = "$network_id:$option";
   1530 
   1531 		// Make sure the option doesn't already exist.
   1532 		// We can check the 'notoptions' cache before we ask for a DB query.
   1533 		$notoptions = wp_cache_get( $notoptions_key, 'site-options' );
   1534 
   1535 		if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) {
   1536 			if ( false !== get_network_option( $network_id, $option, false ) ) {
   1537 				return false;
   1538 			}
   1539 		}
   1540 
   1541 		$value = sanitize_option( $option, $value );
   1542 
   1543 		$serialized_value = maybe_serialize( $value );
   1544 		$result           = $wpdb->insert(
   1545 			$wpdb->sitemeta,
   1546 			array(
   1547 				'site_id'    => $network_id,
   1548 				'meta_key'   => $option,
   1549 				'meta_value' => $serialized_value,
   1550 			)
   1551 		);
   1552 
   1553 		if ( ! $result ) {
   1554 			return false;
   1555 		}
   1556 
   1557 		wp_cache_set( $cache_key, $value, 'site-options' );
   1558 
   1559 		// This option exists now.
   1560 		$notoptions = wp_cache_get( $notoptions_key, 'site-options' ); // Yes, again... we need it to be fresh.
   1561 
   1562 		if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
   1563 			unset( $notoptions[ $option ] );
   1564 			wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
   1565 		}
   1566 	}
   1567 
   1568 	if ( $result ) {
   1569 
   1570 		/**
   1571 		 * Fires after a specific network option has been successfully added.
   1572 		 *
   1573 		 * The dynamic portion of the hook name, `$option`, refers to the option name.
   1574 		 *
   1575 		 * @since 2.9.0 As "add_site_option_{$key}"
   1576 		 * @since 3.0.0
   1577 		 * @since 4.7.0 The `$network_id` parameter was added.
   1578 		 *
   1579 		 * @param string $option     Name of the network option.
   1580 		 * @param mixed  $value      Value of the network option.
   1581 		 * @param int    $network_id ID of the network.
   1582 		 */
   1583 		do_action( "add_site_option_{$option}", $option, $value, $network_id );
   1584 
   1585 		/**
   1586 		 * Fires after a network option has been successfully added.
   1587 		 *
   1588 		 * @since 3.0.0
   1589 		 * @since 4.7.0 The `$network_id` parameter was added.
   1590 		 *
   1591 		 * @param string $option     Name of the network option.
   1592 		 * @param mixed  $value      Value of the network option.
   1593 		 * @param int    $network_id ID of the network.
   1594 		 */
   1595 		do_action( 'add_site_option', $option, $value, $network_id );
   1596 
   1597 		return true;
   1598 	}
   1599 
   1600 	return false;
   1601 }
   1602 
   1603 /**
   1604  * Removes a network option by name.
   1605  *
   1606  * @since 4.4.0
   1607  *
   1608  * @see delete_option()
   1609  *
   1610  * @global wpdb $wpdb WordPress database abstraction object.
   1611  *
   1612  * @param int    $network_id ID of the network. Can be null to default to the current network ID.
   1613  * @param string $option     Name of the option to delete. Expected to not be SQL-escaped.
   1614  * @return bool True if the option was deleted, false otherwise.
   1615  */
   1616 function delete_network_option( $network_id, $option ) {
   1617 	global $wpdb;
   1618 
   1619 	if ( $network_id && ! is_numeric( $network_id ) ) {
   1620 		return false;
   1621 	}
   1622 
   1623 	$network_id = (int) $network_id;
   1624 
   1625 	// Fallback to the current network if a network ID is not specified.
   1626 	if ( ! $network_id ) {
   1627 		$network_id = get_current_network_id();
   1628 	}
   1629 
   1630 	/**
   1631 	 * Fires immediately before a specific network option is deleted.
   1632 	 *
   1633 	 * The dynamic portion of the hook name, `$option`, refers to the option name.
   1634 	 *
   1635 	 * @since 3.0.0
   1636 	 * @since 4.4.0 The `$option` parameter was added.
   1637 	 * @since 4.7.0 The `$network_id` parameter was added.
   1638 	 *
   1639 	 * @param string $option     Option name.
   1640 	 * @param int    $network_id ID of the network.
   1641 	 */
   1642 	do_action( "pre_delete_site_option_{$option}", $option, $network_id );
   1643 
   1644 	if ( ! is_multisite() ) {
   1645 		$result = delete_option( $option );
   1646 	} else {
   1647 		$row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM {$wpdb->sitemeta} WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
   1648 		if ( is_null( $row ) || ! $row->meta_id ) {
   1649 			return false;
   1650 		}
   1651 		$cache_key = "$network_id:$option";
   1652 		wp_cache_delete( $cache_key, 'site-options' );
   1653 
   1654 		$result = $wpdb->delete(
   1655 			$wpdb->sitemeta,
   1656 			array(
   1657 				'meta_key' => $option,
   1658 				'site_id'  => $network_id,
   1659 			)
   1660 		);
   1661 	}
   1662 
   1663 	if ( $result ) {
   1664 
   1665 		/**
   1666 		 * Fires after a specific network option has been deleted.
   1667 		 *
   1668 		 * The dynamic portion of the hook name, `$option`, refers to the option name.
   1669 		 *
   1670 		 * @since 2.9.0 As "delete_site_option_{$key}"
   1671 		 * @since 3.0.0
   1672 		 * @since 4.7.0 The `$network_id` parameter was added.
   1673 		 *
   1674 		 * @param string $option     Name of the network option.
   1675 		 * @param int    $network_id ID of the network.
   1676 		 */
   1677 		do_action( "delete_site_option_{$option}", $option, $network_id );
   1678 
   1679 		/**
   1680 		 * Fires after a network option has been deleted.
   1681 		 *
   1682 		 * @since 3.0.0
   1683 		 * @since 4.7.0 The `$network_id` parameter was added.
   1684 		 *
   1685 		 * @param string $option     Name of the network option.
   1686 		 * @param int    $network_id ID of the network.
   1687 		 */
   1688 		do_action( 'delete_site_option', $option, $network_id );
   1689 
   1690 		return true;
   1691 	}
   1692 
   1693 	return false;
   1694 }
   1695 
   1696 /**
   1697  * Updates the value of a network option that was already added.
   1698  *
   1699  * @since 4.4.0
   1700  *
   1701  * @see update_option()
   1702  *
   1703  * @global wpdb $wpdb WordPress database abstraction object.
   1704  *
   1705  * @param int    $network_id ID of the network. Can be null to default to the current network ID.
   1706  * @param string $option     Name of the option. Expected to not be SQL-escaped.
   1707  * @param mixed  $value      Option value. Expected to not be SQL-escaped.
   1708  * @return bool True if the value was updated, false otherwise.
   1709  */
   1710 function update_network_option( $network_id, $option, $value ) {
   1711 	global $wpdb;
   1712 
   1713 	if ( $network_id && ! is_numeric( $network_id ) ) {
   1714 		return false;
   1715 	}
   1716 
   1717 	$network_id = (int) $network_id;
   1718 
   1719 	// Fallback to the current network if a network ID is not specified.
   1720 	if ( ! $network_id ) {
   1721 		$network_id = get_current_network_id();
   1722 	}
   1723 
   1724 	wp_protect_special_option( $option );
   1725 
   1726 	$old_value = get_network_option( $network_id, $option, false );
   1727 
   1728 	/**
   1729 	 * Filters a specific network option before its value is updated.
   1730 	 *
   1731 	 * The dynamic portion of the hook name, `$option`, refers to the option name.
   1732 	 *
   1733 	 * @since 2.9.0 As 'pre_update_site_option_' . $key
   1734 	 * @since 3.0.0
   1735 	 * @since 4.4.0 The `$option` parameter was added.
   1736 	 * @since 4.7.0 The `$network_id` parameter was added.
   1737 	 *
   1738 	 * @param mixed  $value      New value of the network option.
   1739 	 * @param mixed  $old_value  Old value of the network option.
   1740 	 * @param string $option     Option name.
   1741 	 * @param int    $network_id ID of the network.
   1742 	 */
   1743 	$value = apply_filters( "pre_update_site_option_{$option}", $value, $old_value, $option, $network_id );
   1744 
   1745 	/*
   1746 	 * If the new and old values are the same, no need to update.
   1747 	 *
   1748 	 * Unserialized values will be adequate in most cases. If the unserialized
   1749 	 * data differs, the (maybe) serialized data is checked to avoid
   1750 	 * unnecessary database calls for otherwise identical object instances.
   1751 	 *
   1752 	 * See https://core.trac.wordpress.org/ticket/44956
   1753 	 */
   1754 	if ( $value === $old_value || maybe_serialize( $value ) === maybe_serialize( $old_value ) ) {
   1755 		return false;
   1756 	}
   1757 
   1758 	if ( false === $old_value ) {
   1759 		return add_network_option( $network_id, $option, $value );
   1760 	}
   1761 
   1762 	$notoptions_key = "$network_id:notoptions";
   1763 	$notoptions     = wp_cache_get( $notoptions_key, 'site-options' );
   1764 
   1765 	if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
   1766 		unset( $notoptions[ $option ] );
   1767 		wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
   1768 	}
   1769 
   1770 	if ( ! is_multisite() ) {
   1771 		$result = update_option( $option, $value, 'no' );
   1772 	} else {
   1773 		$value = sanitize_option( $option, $value );
   1774 
   1775 		$serialized_value = maybe_serialize( $value );
   1776 		$result           = $wpdb->update(
   1777 			$wpdb->sitemeta,
   1778 			array( 'meta_value' => $serialized_value ),
   1779 			array(
   1780 				'site_id'  => $network_id,
   1781 				'meta_key' => $option,
   1782 			)
   1783 		);
   1784 
   1785 		if ( $result ) {
   1786 			$cache_key = "$network_id:$option";
   1787 			wp_cache_set( $cache_key, $value, 'site-options' );
   1788 		}
   1789 	}
   1790 
   1791 	if ( $result ) {
   1792 
   1793 		/**
   1794 		 * Fires after the value of a specific network option has been successfully updated.
   1795 		 *
   1796 		 * The dynamic portion of the hook name, `$option`, refers to the option name.
   1797 		 *
   1798 		 * @since 2.9.0 As "update_site_option_{$key}"
   1799 		 * @since 3.0.0
   1800 		 * @since 4.7.0 The `$network_id` parameter was added.
   1801 		 *
   1802 		 * @param string $option     Name of the network option.
   1803 		 * @param mixed  $value      Current value of the network option.
   1804 		 * @param mixed  $old_value  Old value of the network option.
   1805 		 * @param int    $network_id ID of the network.
   1806 		 */
   1807 		do_action( "update_site_option_{$option}", $option, $value, $old_value, $network_id );
   1808 
   1809 		/**
   1810 		 * Fires after the value of a network option has been successfully updated.
   1811 		 *
   1812 		 * @since 3.0.0
   1813 		 * @since 4.7.0 The `$network_id` parameter was added.
   1814 		 *
   1815 		 * @param string $option     Name of the network option.
   1816 		 * @param mixed  $value      Current value of the network option.
   1817 		 * @param mixed  $old_value  Old value of the network option.
   1818 		 * @param int    $network_id ID of the network.
   1819 		 */
   1820 		do_action( 'update_site_option', $option, $value, $old_value, $network_id );
   1821 
   1822 		return true;
   1823 	}
   1824 
   1825 	return false;
   1826 }
   1827 
   1828 /**
   1829  * Deletes a site transient.
   1830  *
   1831  * @since 2.9.0
   1832  *
   1833  * @param string $transient Transient name. Expected to not be SQL-escaped.
   1834  * @return bool True if the transient was deleted, false otherwise.
   1835  */
   1836 function delete_site_transient( $transient ) {
   1837 
   1838 	/**
   1839 	 * Fires immediately before a specific site transient is deleted.
   1840 	 *
   1841 	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
   1842 	 *
   1843 	 * @since 3.0.0
   1844 	 *
   1845 	 * @param string $transient Transient name.
   1846 	 */
   1847 	do_action( "delete_site_transient_{$transient}", $transient );
   1848 
   1849 	if ( wp_using_ext_object_cache() ) {
   1850 		$result = wp_cache_delete( $transient, 'site-transient' );
   1851 	} else {
   1852 		$option_timeout = '_site_transient_timeout_' . $transient;
   1853 		$option         = '_site_transient_' . $transient;
   1854 		$result         = delete_site_option( $option );
   1855 
   1856 		if ( $result ) {
   1857 			delete_site_option( $option_timeout );
   1858 		}
   1859 	}
   1860 
   1861 	if ( $result ) {
   1862 
   1863 		/**
   1864 		 * Fires after a transient is deleted.
   1865 		 *
   1866 		 * @since 3.0.0
   1867 		 *
   1868 		 * @param string $transient Deleted transient name.
   1869 		 */
   1870 		do_action( 'deleted_site_transient', $transient );
   1871 	}
   1872 
   1873 	return $result;
   1874 }
   1875 
   1876 /**
   1877  * Retrieves the value of a site transient.
   1878  *
   1879  * If the transient does not exist, does not have a value, or has expired,
   1880  * then the return value will be false.
   1881  *
   1882  * @since 2.9.0
   1883  *
   1884  * @see get_transient()
   1885  *
   1886  * @param string $transient Transient name. Expected to not be SQL-escaped.
   1887  * @return mixed Value of transient.
   1888  */
   1889 function get_site_transient( $transient ) {
   1890 
   1891 	/**
   1892 	 * Filters the value of an existing site transient before it is retrieved.
   1893 	 *
   1894 	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
   1895 	 *
   1896 	 * Returning a truthy value from the filter will effectively short-circuit retrieval
   1897 	 * and return the passed value instead.
   1898 	 *
   1899 	 * @since 2.9.0
   1900 	 * @since 4.4.0 The `$transient` parameter was added.
   1901 	 *
   1902 	 * @param mixed  $pre_site_transient The default value to return if the site transient does not exist.
   1903 	 *                                   Any value other than false will short-circuit the retrieval
   1904 	 *                                   of the transient, and return that value.
   1905 	 * @param string $transient          Transient name.
   1906 	 */
   1907 	$pre = apply_filters( "pre_site_transient_{$transient}", false, $transient );
   1908 
   1909 	if ( false !== $pre ) {
   1910 		return $pre;
   1911 	}
   1912 
   1913 	if ( wp_using_ext_object_cache() ) {
   1914 		$value = wp_cache_get( $transient, 'site-transient' );
   1915 	} else {
   1916 		// Core transients that do not have a timeout. Listed here so querying timeouts can be avoided.
   1917 		$no_timeout       = array( 'update_core', 'update_plugins', 'update_themes' );
   1918 		$transient_option = '_site_transient_' . $transient;
   1919 		if ( ! in_array( $transient, $no_timeout, true ) ) {
   1920 			$transient_timeout = '_site_transient_timeout_' . $transient;
   1921 			$timeout           = get_site_option( $transient_timeout );
   1922 			if ( false !== $timeout && $timeout < time() ) {
   1923 				delete_site_option( $transient_option );
   1924 				delete_site_option( $transient_timeout );
   1925 				$value = false;
   1926 			}
   1927 		}
   1928 
   1929 		if ( ! isset( $value ) ) {
   1930 			$value = get_site_option( $transient_option );
   1931 		}
   1932 	}
   1933 
   1934 	/**
   1935 	 * Filters the value of an existing site transient.
   1936 	 *
   1937 	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
   1938 	 *
   1939 	 * @since 2.9.0
   1940 	 * @since 4.4.0 The `$transient` parameter was added.
   1941 	 *
   1942 	 * @param mixed  $value     Value of site transient.
   1943 	 * @param string $transient Transient name.
   1944 	 */
   1945 	return apply_filters( "site_transient_{$transient}", $value, $transient );
   1946 }
   1947 
   1948 /**
   1949  * Sets/updates the value of a site transient.
   1950  *
   1951  * You do not need to serialize values. If the value needs to be serialized,
   1952  * then it will be serialized before it is set.
   1953  *
   1954  * @since 2.9.0
   1955  *
   1956  * @see set_transient()
   1957  *
   1958  * @param string $transient  Transient name. Expected to not be SQL-escaped. Must be
   1959  *                           167 characters or fewer in length.
   1960  * @param mixed  $value      Transient value. Expected to not be SQL-escaped.
   1961  * @param int    $expiration Optional. Time until expiration in seconds. Default 0 (no expiration).
   1962  * @return bool True if the value was set, false otherwise.
   1963  */
   1964 function set_site_transient( $transient, $value, $expiration = 0 ) {
   1965 
   1966 	/**
   1967 	 * Filters the value of a specific site transient before it is set.
   1968 	 *
   1969 	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
   1970 	 *
   1971 	 * @since 3.0.0
   1972 	 * @since 4.4.0 The `$transient` parameter was added.
   1973 	 *
   1974 	 * @param mixed  $value     New value of site transient.
   1975 	 * @param string $transient Transient name.
   1976 	 */
   1977 	$value = apply_filters( "pre_set_site_transient_{$transient}", $value, $transient );
   1978 
   1979 	$expiration = (int) $expiration;
   1980 
   1981 	/**
   1982 	 * Filters the expiration for a site transient before its value is set.
   1983 	 *
   1984 	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
   1985 	 *
   1986 	 * @since 4.4.0
   1987 	 *
   1988 	 * @param int    $expiration Time until expiration in seconds. Use 0 for no expiration.
   1989 	 * @param mixed  $value      New value of site transient.
   1990 	 * @param string $transient  Transient name.
   1991 	 */
   1992 	$expiration = apply_filters( "expiration_of_site_transient_{$transient}", $expiration, $value, $transient );
   1993 
   1994 	if ( wp_using_ext_object_cache() ) {
   1995 		$result = wp_cache_set( $transient, $value, 'site-transient', $expiration );
   1996 	} else {
   1997 		$transient_timeout = '_site_transient_timeout_' . $transient;
   1998 		$option            = '_site_transient_' . $transient;
   1999 
   2000 		if ( false === get_site_option( $option ) ) {
   2001 			if ( $expiration ) {
   2002 				add_site_option( $transient_timeout, time() + $expiration );
   2003 			}
   2004 			$result = add_site_option( $option, $value );
   2005 		} else {
   2006 			if ( $expiration ) {
   2007 				update_site_option( $transient_timeout, time() + $expiration );
   2008 			}
   2009 			$result = update_site_option( $option, $value );
   2010 		}
   2011 	}
   2012 
   2013 	if ( $result ) {
   2014 
   2015 		/**
   2016 		 * Fires after the value for a specific site transient has been set.
   2017 		 *
   2018 		 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
   2019 		 *
   2020 		 * @since 3.0.0
   2021 		 * @since 4.4.0 The `$transient` parameter was added
   2022 		 *
   2023 		 * @param mixed  $value      Site transient value.
   2024 		 * @param int    $expiration Time until expiration in seconds.
   2025 		 * @param string $transient  Transient name.
   2026 		 */
   2027 		do_action( "set_site_transient_{$transient}", $value, $expiration, $transient );
   2028 
   2029 		/**
   2030 		 * Fires after the value for a site transient has been set.
   2031 		 *
   2032 		 * @since 3.0.0
   2033 		 *
   2034 		 * @param string $transient  The name of the site transient.
   2035 		 * @param mixed  $value      Site transient value.
   2036 		 * @param int    $expiration Time until expiration in seconds.
   2037 		 */
   2038 		do_action( 'setted_site_transient', $transient, $value, $expiration );
   2039 	}
   2040 
   2041 	return $result;
   2042 }
   2043 
   2044 /**
   2045  * Registers default settings available in WordPress.
   2046  *
   2047  * The settings registered here are primarily useful for the REST API, so this
   2048  * does not encompass all settings available in WordPress.
   2049  *
   2050  * @since 4.7.0
   2051  */
   2052 function register_initial_settings() {
   2053 	register_setting(
   2054 		'general',
   2055 		'blogname',
   2056 		array(
   2057 			'show_in_rest' => array(
   2058 				'name' => 'title',
   2059 			),
   2060 			'type'         => 'string',
   2061 			'description'  => __( 'Site title.' ),
   2062 		)
   2063 	);
   2064 
   2065 	register_setting(
   2066 		'general',
   2067 		'blogdescription',
   2068 		array(
   2069 			'show_in_rest' => array(
   2070 				'name' => 'description',
   2071 			),
   2072 			'type'         => 'string',
   2073 			'description'  => __( 'Site tagline.' ),
   2074 		)
   2075 	);
   2076 
   2077 	if ( ! is_multisite() ) {
   2078 		register_setting(
   2079 			'general',
   2080 			'siteurl',
   2081 			array(
   2082 				'show_in_rest' => array(
   2083 					'name'   => 'url',
   2084 					'schema' => array(
   2085 						'format' => 'uri',
   2086 					),
   2087 				),
   2088 				'type'         => 'string',
   2089 				'description'  => __( 'Site URL.' ),
   2090 			)
   2091 		);
   2092 	}
   2093 
   2094 	if ( ! is_multisite() ) {
   2095 		register_setting(
   2096 			'general',
   2097 			'admin_email',
   2098 			array(
   2099 				'show_in_rest' => array(
   2100 					'name'   => 'email',
   2101 					'schema' => array(
   2102 						'format' => 'email',
   2103 					),
   2104 				),
   2105 				'type'         => 'string',
   2106 				'description'  => __( 'This address is used for admin purposes, like new user notification.' ),
   2107 			)
   2108 		);
   2109 	}
   2110 
   2111 	register_setting(
   2112 		'general',
   2113 		'timezone_string',
   2114 		array(
   2115 			'show_in_rest' => array(
   2116 				'name' => 'timezone',
   2117 			),
   2118 			'type'         => 'string',
   2119 			'description'  => __( 'A city in the same timezone as you.' ),
   2120 		)
   2121 	);
   2122 
   2123 	register_setting(
   2124 		'general',
   2125 		'date_format',
   2126 		array(
   2127 			'show_in_rest' => true,
   2128 			'type'         => 'string',
   2129 			'description'  => __( 'A date format for all date strings.' ),
   2130 		)
   2131 	);
   2132 
   2133 	register_setting(
   2134 		'general',
   2135 		'time_format',
   2136 		array(
   2137 			'show_in_rest' => true,
   2138 			'type'         => 'string',
   2139 			'description'  => __( 'A time format for all time strings.' ),
   2140 		)
   2141 	);
   2142 
   2143 	register_setting(
   2144 		'general',
   2145 		'start_of_week',
   2146 		array(
   2147 			'show_in_rest' => true,
   2148 			'type'         => 'integer',
   2149 			'description'  => __( 'A day number of the week that the week should start on.' ),
   2150 		)
   2151 	);
   2152 
   2153 	register_setting(
   2154 		'general',
   2155 		'WPLANG',
   2156 		array(
   2157 			'show_in_rest' => array(
   2158 				'name' => 'language',
   2159 			),
   2160 			'type'         => 'string',
   2161 			'description'  => __( 'WordPress locale code.' ),
   2162 			'default'      => 'en_US',
   2163 		)
   2164 	);
   2165 
   2166 	register_setting(
   2167 		'writing',
   2168 		'use_smilies',
   2169 		array(
   2170 			'show_in_rest' => true,
   2171 			'type'         => 'boolean',
   2172 			'description'  => __( 'Convert emoticons like :-) and :-P to graphics on display.' ),
   2173 			'default'      => true,
   2174 		)
   2175 	);
   2176 
   2177 	register_setting(
   2178 		'writing',
   2179 		'default_category',
   2180 		array(
   2181 			'show_in_rest' => true,
   2182 			'type'         => 'integer',
   2183 			'description'  => __( 'Default post category.' ),
   2184 		)
   2185 	);
   2186 
   2187 	register_setting(
   2188 		'writing',
   2189 		'default_post_format',
   2190 		array(
   2191 			'show_in_rest' => true,
   2192 			'type'         => 'string',
   2193 			'description'  => __( 'Default post format.' ),
   2194 		)
   2195 	);
   2196 
   2197 	register_setting(
   2198 		'reading',
   2199 		'posts_per_page',
   2200 		array(
   2201 			'show_in_rest' => true,
   2202 			'type'         => 'integer',
   2203 			'description'  => __( 'Blog pages show at most.' ),
   2204 			'default'      => 10,
   2205 		)
   2206 	);
   2207 
   2208 	register_setting(
   2209 		'discussion',
   2210 		'default_ping_status',
   2211 		array(
   2212 			'show_in_rest' => array(
   2213 				'schema' => array(
   2214 					'enum' => array( 'open', 'closed' ),
   2215 				),
   2216 			),
   2217 			'type'         => 'string',
   2218 			'description'  => __( 'Allow link notifications from other blogs (pingbacks and trackbacks) on new articles.' ),
   2219 		)
   2220 	);
   2221 
   2222 	register_setting(
   2223 		'discussion',
   2224 		'default_comment_status',
   2225 		array(
   2226 			'show_in_rest' => array(
   2227 				'schema' => array(
   2228 					'enum' => array( 'open', 'closed' ),
   2229 				),
   2230 			),
   2231 			'type'         => 'string',
   2232 			'description'  => __( 'Allow people to submit comments on new posts.' ),
   2233 		)
   2234 	);
   2235 }
   2236 
   2237 /**
   2238  * Registers a setting and its data.
   2239  *
   2240  * @since 2.7.0
   2241  * @since 4.7.0 `$args` can be passed to set flags on the setting, similar to `register_meta()`.
   2242  * @since 5.5.0 `$new_whitelist_options` was renamed to `$new_allowed_options`.
   2243  *              Please consider writing more inclusive code.
   2244  *
   2245  * @global array $new_allowed_options
   2246  * @global array $wp_registered_settings
   2247  *
   2248  * @param string $option_group A settings group name. Should correspond to an allowed option key name.
   2249  *                             Default allowed option key names include 'general', 'discussion', 'media',
   2250  *                             'reading', 'writing', 'misc', 'options', and 'privacy'.
   2251  * @param string $option_name The name of an option to sanitize and save.
   2252  * @param array  $args {
   2253  *     Data used to describe the setting when registered.
   2254  *
   2255  *     @type string     $type              The type of data associated with this setting.
   2256  *                                         Valid values are 'string', 'boolean', 'integer', 'number', 'array', and 'object'.
   2257  *     @type string     $description       A description of the data attached to this setting.
   2258  *     @type callable   $sanitize_callback A callback function that sanitizes the option's value.
   2259  *     @type bool|array $show_in_rest      Whether data associated with this setting should be included in the REST API.
   2260  *                                         When registering complex settings, this argument may optionally be an
   2261  *                                         array with a 'schema' key.
   2262  *     @type mixed      $default           Default value when calling `get_option()`.
   2263  * }
   2264  */
   2265 function register_setting( $option_group, $option_name, $args = array() ) {
   2266 	global $new_allowed_options, $wp_registered_settings;
   2267 
   2268 	/*
   2269 	 * In 5.5.0, the `$new_whitelist_options` global variable was renamed to `$new_allowed_options`.
   2270 	 * Please consider writing more inclusive code.
   2271 	 */
   2272 	$GLOBALS['new_whitelist_options'] = &$new_allowed_options;
   2273 
   2274 	$defaults = array(
   2275 		'type'              => 'string',
   2276 		'group'             => $option_group,
   2277 		'description'       => '',
   2278 		'sanitize_callback' => null,
   2279 		'show_in_rest'      => false,
   2280 	);
   2281 
   2282 	// Back-compat: old sanitize callback is added.
   2283 	if ( is_callable( $args ) ) {
   2284 		$args = array(
   2285 			'sanitize_callback' => $args,
   2286 		);
   2287 	}
   2288 
   2289 	/**
   2290 	 * Filters the registration arguments when registering a setting.
   2291 	 *
   2292 	 * @since 4.7.0
   2293 	 *
   2294 	 * @param array  $args         Array of setting registration arguments.
   2295 	 * @param array  $defaults     Array of default arguments.
   2296 	 * @param string $option_group Setting group.
   2297 	 * @param string $option_name  Setting name.
   2298 	 */
   2299 	$args = apply_filters( 'register_setting_args', $args, $defaults, $option_group, $option_name );
   2300 
   2301 	$args = wp_parse_args( $args, $defaults );
   2302 
   2303 	// Require an item schema when registering settings with an array type.
   2304 	if ( false !== $args['show_in_rest'] && 'array' === $args['type'] && ( ! is_array( $args['show_in_rest'] ) || ! isset( $args['show_in_rest']['schema']['items'] ) ) ) {
   2305 		_doing_it_wrong( __FUNCTION__, __( 'When registering an "array" setting to show in the REST API, you must specify the schema for each array item in "show_in_rest.schema.items".' ), '5.4.0' );
   2306 	}
   2307 
   2308 	if ( ! is_array( $wp_registered_settings ) ) {
   2309 		$wp_registered_settings = array();
   2310 	}
   2311 
   2312 	if ( 'misc' === $option_group ) {
   2313 		_deprecated_argument(
   2314 			__FUNCTION__,
   2315 			'3.0.0',
   2316 			sprintf(
   2317 				/* translators: %s: misc */
   2318 				__( 'The "%s" options group has been removed. Use another settings group.' ),
   2319 				'misc'
   2320 			)
   2321 		);
   2322 		$option_group = 'general';
   2323 	}
   2324 
   2325 	if ( 'privacy' === $option_group ) {
   2326 		_deprecated_argument(
   2327 			__FUNCTION__,
   2328 			'3.5.0',
   2329 			sprintf(
   2330 				/* translators: %s: privacy */
   2331 				__( 'The "%s" options group has been removed. Use another settings group.' ),
   2332 				'privacy'
   2333 			)
   2334 		);
   2335 		$option_group = 'reading';
   2336 	}
   2337 
   2338 	$new_allowed_options[ $option_group ][] = $option_name;
   2339 
   2340 	if ( ! empty( $args['sanitize_callback'] ) ) {
   2341 		add_filter( "sanitize_option_{$option_name}", $args['sanitize_callback'] );
   2342 	}
   2343 	if ( array_key_exists( 'default', $args ) ) {
   2344 		add_filter( "default_option_{$option_name}", 'filter_default_option', 10, 3 );
   2345 	}
   2346 
   2347 	/**
   2348 	 * Fires immediately before the setting is registered but after its filters are in place.
   2349 	 *
   2350 	 * @since 5.5.0
   2351 	 *
   2352 	 * @param string $option_group Setting group.
   2353 	 * @param string $option_name  Setting name.
   2354 	 * @param array  $args         Array of setting registration arguments.
   2355 	 */
   2356 	do_action( 'register_setting', $option_group, $option_name, $args );
   2357 
   2358 	$wp_registered_settings[ $option_name ] = $args;
   2359 }
   2360 
   2361 /**
   2362  * Unregisters a setting.
   2363  *
   2364  * @since 2.7.0
   2365  * @since 4.7.0 `$sanitize_callback` was deprecated. The callback from `register_setting()` is now used instead.
   2366  * @since 5.5.0 `$new_whitelist_options` was renamed to `$new_allowed_options`.
   2367  *              Please consider writing more inclusive code.
   2368  *
   2369  * @global array $new_allowed_options
   2370  * @global array $wp_registered_settings
   2371  *
   2372  * @param string          $option_group The settings group name used during registration.
   2373  * @param string          $option_name  The name of the option to unregister.
   2374  * @param callable|string $deprecated   Deprecated.
   2375  */
   2376 function unregister_setting( $option_group, $option_name, $deprecated = '' ) {
   2377 	global $new_allowed_options, $wp_registered_settings;
   2378 
   2379 	/*
   2380 	 * In 5.5.0, the `$new_whitelist_options` global variable was renamed to `$new_allowed_options`.
   2381 	 * Please consider writing more inclusive code.
   2382 	 */
   2383 	$GLOBALS['new_whitelist_options'] = &$new_allowed_options;
   2384 
   2385 	if ( 'misc' === $option_group ) {
   2386 		_deprecated_argument(
   2387 			__FUNCTION__,
   2388 			'3.0.0',
   2389 			sprintf(
   2390 				/* translators: %s: misc */
   2391 				__( 'The "%s" options group has been removed. Use another settings group.' ),
   2392 				'misc'
   2393 			)
   2394 		);
   2395 		$option_group = 'general';
   2396 	}
   2397 
   2398 	if ( 'privacy' === $option_group ) {
   2399 		_deprecated_argument(
   2400 			__FUNCTION__,
   2401 			'3.5.0',
   2402 			sprintf(
   2403 				/* translators: %s: privacy */
   2404 				__( 'The "%s" options group has been removed. Use another settings group.' ),
   2405 				'privacy'
   2406 			)
   2407 		);
   2408 		$option_group = 'reading';
   2409 	}
   2410 
   2411 	$pos = array_search( $option_name, (array) $new_allowed_options[ $option_group ], true );
   2412 
   2413 	if ( false !== $pos ) {
   2414 		unset( $new_allowed_options[ $option_group ][ $pos ] );
   2415 	}
   2416 
   2417 	if ( '' !== $deprecated ) {
   2418 		_deprecated_argument(
   2419 			__FUNCTION__,
   2420 			'4.7.0',
   2421 			sprintf(
   2422 				/* translators: 1: $sanitize_callback, 2: register_setting() */
   2423 				__( '%1$s is deprecated. The callback from %2$s is used instead.' ),
   2424 				'<code>$sanitize_callback</code>',
   2425 				'<code>register_setting()</code>'
   2426 			)
   2427 		);
   2428 		remove_filter( "sanitize_option_{$option_name}", $deprecated );
   2429 	}
   2430 
   2431 	if ( isset( $wp_registered_settings[ $option_name ] ) ) {
   2432 		// Remove the sanitize callback if one was set during registration.
   2433 		if ( ! empty( $wp_registered_settings[ $option_name ]['sanitize_callback'] ) ) {
   2434 			remove_filter( "sanitize_option_{$option_name}", $wp_registered_settings[ $option_name ]['sanitize_callback'] );
   2435 		}
   2436 
   2437 		// Remove the default filter if a default was provided during registration.
   2438 		if ( array_key_exists( 'default', $wp_registered_settings[ $option_name ] ) ) {
   2439 			remove_filter( "default_option_{$option_name}", 'filter_default_option', 10 );
   2440 		}
   2441 
   2442 		/**
   2443 		 * Fires immediately before the setting is unregistered and after its filters have been removed.
   2444 		 *
   2445 		 * @since 5.5.0
   2446 		 *
   2447 		 * @param string $option_group Setting group.
   2448 		 * @param string $option_name  Setting name.
   2449 		 */
   2450 		do_action( 'unregister_setting', $option_group, $option_name );
   2451 
   2452 		unset( $wp_registered_settings[ $option_name ] );
   2453 	}
   2454 }
   2455 
   2456 /**
   2457  * Retrieves an array of registered settings.
   2458  *
   2459  * @since 4.7.0
   2460  *
   2461  * @global array $wp_registered_settings
   2462  *
   2463  * @return array List of registered settings, keyed by option name.
   2464  */
   2465 function get_registered_settings() {
   2466 	global $wp_registered_settings;
   2467 
   2468 	if ( ! is_array( $wp_registered_settings ) ) {
   2469 		return array();
   2470 	}
   2471 
   2472 	return $wp_registered_settings;
   2473 }
   2474 
   2475 /**
   2476  * Filters the default value for the option.
   2477  *
   2478  * For settings which register a default setting in `register_setting()`, this
   2479  * function is added as a filter to `default_option_{$option}`.
   2480  *
   2481  * @since 4.7.0
   2482  *
   2483  * @param mixed  $default        Existing default value to return.
   2484  * @param string $option         Option name.
   2485  * @param bool   $passed_default Was `get_option()` passed a default value?
   2486  * @return mixed Filtered default value.
   2487  */
   2488 function filter_default_option( $default, $option, $passed_default ) {
   2489 	if ( $passed_default ) {
   2490 		return $default;
   2491 	}
   2492 
   2493 	$registered = get_registered_settings();
   2494 	if ( empty( $registered[ $option ] ) ) {
   2495 		return $default;
   2496 	}
   2497 
   2498 	return $registered[ $option ]['default'];
   2499 }