[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> option.php (source)

   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   *
  32   * 1. When the option has not been saved in the database, the `$default_value` value
  33   *    is returned if provided. If not, boolean `false` is returned.
  34   * 2. When one of the Options API filters is used: {@see 'pre_option_$option'},
  35   *    {@see 'default_option_$option'}, or {@see 'option_$option'}, the returned
  36   *    value may not match the expected type.
  37   * 3. When the option has just been saved in the database, and get_option()
  38   *    is used right after, non-string scalar and null values are not converted to
  39   *    string equivalents and the original type is returned.
  40   *
  41   * Examples:
  42   *
  43   * When adding options like this: `add_option( 'my_option_name', 'value' )`
  44   * and then retrieving them with `get_option( 'my_option_name' )`, the returned
  45   * values will be:
  46   *
  47   *   - `false` returns `string(0) ""`
  48   *   - `true`  returns `string(1) "1"`
  49   *   - `0`     returns `string(1) "0"`
  50   *   - `1`     returns `string(1) "1"`
  51   *   - `'0'`   returns `string(1) "0"`
  52   *   - `'1'`   returns `string(1) "1"`
  53   *   - `null`  returns `string(0) ""`
  54   *
  55   * When adding options with non-scalar values like
  56   * `add_option( 'my_array', array( false, 'str', null ) )`, the returned value
  57   * will be identical to the original as it is serialized before saving
  58   * it in the database:
  59   *
  60   *     array(3) {
  61   *         [0] => bool(false)
  62   *         [1] => string(3) "str"
  63   *         [2] => NULL
  64   *     }
  65   *
  66   * @since 1.5.0
  67   *
  68   * @global wpdb $wpdb WordPress database abstraction object.
  69   *
  70   * @param string $option        Name of the option to retrieve. Expected to not be SQL-escaped.
  71   * @param mixed  $default_value Optional. Default value to return if the option does not exist.
  72   * @return mixed Value of the option. A value of any type may be returned, including
  73   *               scalar (string, boolean, float, integer), null, array, object.
  74   *               Scalar and null values will be returned as strings as long as they originate
  75   *               from a database stored option value. If there is no option in the database,
  76   *               boolean `false` is returned.
  77   */
  78  function get_option( $option, $default_value = false ) {
  79      global $wpdb;
  80  
  81      if ( is_scalar( $option ) ) {
  82          $option = trim( $option );
  83      }
  84  
  85      if ( empty( $option ) ) {
  86          return false;
  87      }
  88  
  89      /*
  90       * Until a proper _deprecated_option() function can be introduced,
  91       * redirect requests to deprecated keys to the new, correct ones.
  92       */
  93      $deprecated_keys = array(
  94          'blacklist_keys'    => 'disallowed_keys',
  95          'comment_whitelist' => 'comment_previously_approved',
  96      );
  97  
  98      if ( isset( $deprecated_keys[ $option ] ) && ! wp_installing() ) {
  99          _deprecated_argument(
 100              __FUNCTION__,
 101              '5.5.0',
 102              sprintf(
 103                  /* translators: 1: Deprecated option key, 2: New option key. */
 104                  __( 'The "%1$s" option key has been renamed to "%2$s".' ),
 105                  $option,
 106                  $deprecated_keys[ $option ]
 107              )
 108          );
 109          return get_option( $deprecated_keys[ $option ], $default_value );
 110      }
 111  
 112      /**
 113       * Filters the value of an existing option before it is retrieved.
 114       *
 115       * The dynamic portion of the hook name, `$option`, refers to the option name.
 116       *
 117       * Returning a value other than false from the filter will short-circuit retrieval
 118       * and return that value instead.
 119       *
 120       * @since 1.5.0
 121       * @since 4.4.0 The `$option` parameter was added.
 122       * @since 4.9.0 The `$default_value` parameter was added.
 123       *
 124       * @param mixed  $pre_option    The value to return instead of the option value. This differs from
 125       *                              `$default_value`, which is used as the fallback value in the event
 126       *                              the option doesn't exist elsewhere in get_option().
 127       *                              Default false (to skip past the short-circuit).
 128       * @param string $option        Option name.
 129       * @param mixed  $default_value The fallback value to return if the option does not exist.
 130       *                              Default false.
 131       */
 132      $pre = apply_filters( "pre_option_{$option}", false, $option, $default_value );
 133  
 134      /**
 135       * Filters the value of any existing option before it is retrieved.
 136       *
 137       * Returning a value other than false from the filter will short-circuit retrieval
 138       * and return that value instead.
 139       *
 140       * @since 6.1.0
 141       *
 142       * @param mixed  $pre_option    The value to return instead of the option value. This differs from
 143       *                              `$default_value`, which is used as the fallback value in the event
 144       *                              the option doesn't exist elsewhere in get_option().
 145       *                              Default false (to skip past the short-circuit).
 146       * @param string $option        Name of the option.
 147       * @param mixed  $default_value The fallback value to return if the option does not exist.
 148       *                              Default false.
 149       */
 150      $pre = apply_filters( 'pre_option', $pre, $option, $default_value );
 151  
 152      if ( false !== $pre ) {
 153          return $pre;
 154      }
 155  
 156      if ( defined( 'WP_SETUP_CONFIG' ) ) {
 157          return false;
 158      }
 159  
 160      // Distinguish between `false` as a default, and not passing one.
 161      $passed_default = func_num_args() > 1;
 162  
 163      if ( ! wp_installing() ) {
 164          $alloptions = wp_load_alloptions();
 165          /*
 166           * When getting an option value, we check in the following order for performance:
 167           *
 168           * 1. Check the 'alloptions' cache first to prioritize existing loaded options.
 169           * 2. Check the 'notoptions' cache before a cache lookup or DB hit.
 170           * 3. Check the 'options' cache prior to a DB hit.
 171           * 4. Check the DB for the option and cache it in either the 'options' or 'notoptions' cache.
 172           */
 173          if ( isset( $alloptions[ $option ] ) ) {
 174              $value = $alloptions[ $option ];
 175          } else {
 176              // Check for non-existent options first to avoid unnecessary object cache lookups and DB hits.
 177              $notoptions = wp_cache_get( 'notoptions', 'options' );
 178  
 179              if ( ! is_array( $notoptions ) ) {
 180                  $notoptions = array();
 181                  wp_cache_set( 'notoptions', $notoptions, 'options' );
 182              }
 183  
 184              if ( isset( $notoptions[ $option ] ) ) {
 185                  /**
 186                   * Filters the default value for an option.
 187                   *
 188                   * The dynamic portion of the hook name, `$option`, refers to the option name.
 189                   *
 190                   * @since 3.4.0
 191                   * @since 4.4.0 The `$option` parameter was added.
 192                   * @since 4.7.0 The `$passed_default` parameter was added to distinguish between a `false` value and the default parameter value.
 193                   *
 194                   * @param mixed  $default_value  The default value to return if the option does not exist
 195                   *                               in the database.
 196                   * @param string $option         Option name.
 197                   * @param bool   $passed_default Was `get_option()` passed a default value?
 198                   */
 199                  return apply_filters( "default_option_{$option}", $default_value, $option, $passed_default );
 200              }
 201  
 202              $value = wp_cache_get( $option, 'options' );
 203  
 204              if ( false === $value ) {
 205  
 206                  $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
 207  
 208                  // Has to be get_row() instead of get_var() because of funkiness with 0, false, null values.
 209                  if ( is_object( $row ) ) {
 210                      $value = $row->option_value;
 211                      wp_cache_add( $option, $value, 'options' );
 212                  } else { // Option does not exist, so we must cache its non-existence.
 213                      $notoptions[ $option ] = true;
 214                      wp_cache_set( 'notoptions', $notoptions, 'options' );
 215  
 216                      /** This filter is documented in wp-includes/option.php */
 217                      return apply_filters( "default_option_{$option}", $default_value, $option, $passed_default );
 218                  }
 219              }
 220          }
 221      } else {
 222          $suppress = $wpdb->suppress_errors();
 223          $row      = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
 224          $wpdb->suppress_errors( $suppress );
 225  
 226          if ( is_object( $row ) ) {
 227              $value = $row->option_value;
 228          } else {
 229              /** This filter is documented in wp-includes/option.php */
 230              return apply_filters( "default_option_{$option}", $default_value, $option, $passed_default );
 231          }
 232      }
 233  
 234      // If home is not set, use siteurl.
 235      if ( 'home' === $option && '' === $value ) {
 236          return get_option( 'siteurl' );
 237      }
 238  
 239      if ( in_array( $option, array( 'siteurl', 'home', 'category_base', 'tag_base' ), true ) ) {
 240          $value = untrailingslashit( $value );
 241      }
 242  
 243      /**
 244       * Filters the value of an existing option.
 245       *
 246       * The dynamic portion of the hook name, `$option`, refers to the option name.
 247       *
 248       * @since 1.5.0 As `option_{$setting}`.
 249       * @since 3.0.0
 250       * @since 4.4.0 The `$option` parameter was added.
 251       *
 252       * @param mixed  $value  Value of the option. If stored serialized, it will be
 253       *                       unserialized prior to being returned.
 254       * @param string $option Option name.
 255       */
 256      return apply_filters( "option_{$option}", maybe_unserialize( $value ), $option );
 257  }
 258  
 259  /**
 260   * Primes specific options into the cache with a single database query.
 261   *
 262   * Only options that do not already exist in cache will be loaded.
 263   *
 264   * @since 6.4.0
 265   *
 266   * @global wpdb $wpdb WordPress database abstraction object.
 267   *
 268   * @param string[] $options An array of option names to be loaded.
 269   */
 270  function wp_prime_option_caches( $options ) {
 271      global $wpdb;
 272  
 273      $alloptions     = wp_load_alloptions();
 274      $cached_options = wp_cache_get_multiple( $options, 'options' );
 275      $notoptions     = wp_cache_get( 'notoptions', 'options' );
 276      if ( ! is_array( $notoptions ) ) {
 277          $notoptions = array();
 278      }
 279  
 280      // Filter options that are not in the cache.
 281      $options_to_prime = array();
 282      foreach ( $options as $option ) {
 283          if (
 284              ( ! isset( $cached_options[ $option ] ) || false === $cached_options[ $option ] )
 285              && ! isset( $alloptions[ $option ] )
 286              && ! isset( $notoptions[ $option ] )
 287          ) {
 288              $options_to_prime[] = $option;
 289          }
 290      }
 291  
 292      // Bail early if there are no options to be loaded.
 293      if ( empty( $options_to_prime ) ) {
 294          return;
 295      }
 296  
 297      $results = $wpdb->get_results(
 298          $wpdb->prepare(
 299              sprintf(
 300                  "SELECT option_name, option_value FROM $wpdb->options WHERE option_name IN (%s)",
 301                  implode( ',', array_fill( 0, count( $options_to_prime ), '%s' ) )
 302              ),
 303              $options_to_prime
 304          )
 305      );
 306  
 307      $options_found = array();
 308      foreach ( $results as $result ) {
 309          /*
 310           * The cache is primed with the raw value (i.e. not maybe_unserialized).
 311           *
 312           * `get_option()` will handle unserializing the value as needed.
 313           */
 314          $options_found[ $result->option_name ] = $result->option_value;
 315      }
 316      wp_cache_set_multiple( $options_found, 'options' );
 317  
 318      // If all options were found, no need to update `notoptions` cache.
 319      if ( count( $options_found ) === count( $options_to_prime ) ) {
 320          return;
 321      }
 322  
 323      $options_not_found = array_diff( $options_to_prime, array_keys( $options_found ) );
 324  
 325      // Add the options that were not found to the cache.
 326      $update_notoptions = false;
 327      foreach ( $options_not_found as $option_name ) {
 328          if ( ! isset( $notoptions[ $option_name ] ) ) {
 329              $notoptions[ $option_name ] = true;
 330              $update_notoptions          = true;
 331          }
 332      }
 333  
 334      // Only update the cache if it was modified.
 335      if ( $update_notoptions ) {
 336          wp_cache_set( 'notoptions', $notoptions, 'options' );
 337      }
 338  }
 339  
 340  /**
 341   * Primes the cache of all options registered with a specific option group.
 342   *
 343   * @since 6.4.0
 344   *
 345   * @global array $new_allowed_options
 346   *
 347   * @param string $option_group The option group to load options for.
 348   */
 349  function wp_prime_option_caches_by_group( $option_group ) {
 350      global $new_allowed_options;
 351  
 352      if ( isset( $new_allowed_options[ $option_group ] ) ) {
 353          wp_prime_option_caches( $new_allowed_options[ $option_group ] );
 354      }
 355  }
 356  
 357  /**
 358   * Retrieves multiple options.
 359   *
 360   * Options are loaded as necessary first in order to use a single database query at most.
 361   *
 362   * @since 6.4.0
 363   *
 364   * @param string[] $options An array of option names to retrieve.
 365   * @return array An array of key-value pairs for the requested options.
 366   */
 367  function get_options( $options ) {
 368      wp_prime_option_caches( $options );
 369  
 370      $result = array();
 371      foreach ( $options as $option ) {
 372          $result[ $option ] = get_option( $option );
 373      }
 374  
 375      return $result;
 376  }
 377  
 378  /**
 379   * Sets the autoload values for multiple options in the database.
 380   *
 381   * Autoloading too many options can lead to performance problems, especially if the options are not frequently used.
 382   * This function allows modifying the autoload value for multiple options without changing the actual option value.
 383   * This is for example recommended for plugin activation and deactivation hooks, to ensure any options exclusively used
 384   * by the plugin which are generally autoloaded can be set to not autoload when the plugin is inactive.
 385   *
 386   * @since 6.4.0
 387   * @since 6.7.0 The autoload values 'yes' and 'no' are deprecated.
 388   *
 389   * @global wpdb $wpdb WordPress database abstraction object.
 390   *
 391   * @param array $options Associative array of option names and their autoload values to set. The option names are
 392   *                       expected to not be SQL-escaped. The autoload values should be boolean values. For backward
 393   *                       compatibility 'yes' and 'no' are also accepted, though using these values is deprecated.
 394   * @return array Associative array of all provided $options as keys and boolean values for whether their autoload value
 395   *               was updated.
 396   */
 397  function wp_set_option_autoload_values( array $options ) {
 398      global $wpdb;
 399  
 400      if ( ! $options ) {
 401          return array();
 402      }
 403  
 404      $grouped_options = array(
 405          'on'  => array(),
 406          'off' => array(),
 407      );
 408      $results         = array();
 409      foreach ( $options as $option => $autoload ) {
 410          wp_protect_special_option( $option ); // Ensure only valid options can be passed.
 411  
 412          /*
 413           * Sanitize autoload value and categorize accordingly.
 414           * The values 'yes', 'no', 'on', and 'off' are supported for backward compatibility.
 415           */
 416          if ( 'off' === $autoload || 'no' === $autoload || false === $autoload ) {
 417              $grouped_options['off'][] = $option;
 418          } else {
 419              $grouped_options['on'][] = $option;
 420          }
 421          $results[ $option ] = false; // Initialize result value.
 422      }
 423  
 424      $where      = array();
 425      $where_args = array();
 426      foreach ( $grouped_options as $autoload => $options ) {
 427          if ( ! $options ) {
 428              continue;
 429          }
 430          $placeholders = implode( ',', array_fill( 0, count( $options ), '%s' ) );
 431          $where[]      = "autoload != '%s' AND option_name IN ($placeholders)";
 432          $where_args[] = $autoload;
 433          foreach ( $options as $option ) {
 434              $where_args[] = $option;
 435          }
 436      }
 437      $where = 'WHERE ' . implode( ' OR ', $where );
 438  
 439      /*
 440       * Determine the relevant options that do not already use the given autoload value.
 441       * If no options are returned, no need to update.
 442       */
 443      // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
 444      $options_to_update = $wpdb->get_col( $wpdb->prepare( "SELECT option_name FROM $wpdb->options $where", $where_args ) );
 445      if ( ! $options_to_update ) {
 446          return $results;
 447      }
 448  
 449      // Run UPDATE queries as needed (maximum 2) to update the relevant options' autoload values to 'yes' or 'no'.
 450      foreach ( $grouped_options as $autoload => $options ) {
 451          if ( ! $options ) {
 452              continue;
 453          }
 454          $options                      = array_intersect( $options, $options_to_update );
 455          $grouped_options[ $autoload ] = $options;
 456          if ( ! $grouped_options[ $autoload ] ) {
 457              continue;
 458          }
 459  
 460          // Run query to update autoload value for all the options where it is needed.
 461          $success = $wpdb->query(
 462              $wpdb->prepare(
 463                  "UPDATE $wpdb->options SET autoload = %s WHERE option_name IN (" . implode( ',', array_fill( 0, count( $grouped_options[ $autoload ] ), '%s' ) ) . ')',
 464                  array_merge(
 465                      array( $autoload ),
 466                      $grouped_options[ $autoload ]
 467                  )
 468              )
 469          );
 470          if ( ! $success ) {
 471              // Set option list to an empty array to indicate no options were updated.
 472              $grouped_options[ $autoload ] = array();
 473              continue;
 474          }
 475  
 476          // Assume that on success all options were updated, which should be the case given only new values are sent.
 477          foreach ( $grouped_options[ $autoload ] as $option ) {
 478              $results[ $option ] = true;
 479          }
 480      }
 481  
 482      /*
 483       * If any options were changed to 'on', delete their individual caches, and delete 'alloptions' cache so that it
 484       * is refreshed as needed.
 485       * If no options were changed to 'on' but any options were changed to 'no', delete them from the 'alloptions'
 486       * cache. This is not necessary when options were changed to 'on', since in that situation the entire cache is
 487       * deleted anyway.
 488       */
 489      if ( $grouped_options['on'] ) {
 490          wp_cache_delete_multiple( $grouped_options['on'], 'options' );
 491          wp_cache_delete( 'alloptions', 'options' );
 492      } elseif ( $grouped_options['off'] ) {
 493          $alloptions = wp_load_alloptions( true );
 494  
 495          foreach ( $grouped_options['off'] as $option ) {
 496              if ( isset( $alloptions[ $option ] ) ) {
 497                  unset( $alloptions[ $option ] );
 498              }
 499          }
 500  
 501          wp_cache_set( 'alloptions', $alloptions, 'options' );
 502      }
 503  
 504      return $results;
 505  }
 506  
 507  /**
 508   * Sets the autoload value for multiple options in the database.
 509   *
 510   * This is a wrapper for {@see wp_set_option_autoload_values()}, which can be used to set different autoload values for
 511   * each option at once.
 512   *
 513   * @since 6.4.0
 514   * @since 6.7.0 The autoload values 'yes' and 'no' are deprecated.
 515   *
 516   * @see wp_set_option_autoload_values()
 517   *
 518   * @param string[] $options  List of option names. Expected to not be SQL-escaped.
 519   * @param bool     $autoload Autoload value to control whether to load the options when WordPress starts up.
 520   *                           For backward compatibility 'yes' and 'no' are also accepted, though using these values is
 521   *                           deprecated.
 522   * @return array Associative array of all provided $options as keys and boolean values for whether their autoload value
 523   *               was updated.
 524   */
 525  function wp_set_options_autoload( array $options, $autoload ) {
 526      return wp_set_option_autoload_values(
 527          array_fill_keys( $options, $autoload )
 528      );
 529  }
 530  
 531  /**
 532   * Sets the autoload value for an option in the database.
 533   *
 534   * This is a wrapper for {@see wp_set_option_autoload_values()}, which can be used to set the autoload value for
 535   * multiple options at once.
 536   *
 537   * @since 6.4.0
 538   * @since 6.7.0 The autoload values 'yes' and 'no' are deprecated.
 539   *
 540   * @see wp_set_option_autoload_values()
 541   *
 542   * @param string $option   Name of the option. Expected to not be SQL-escaped.
 543   * @param bool   $autoload Autoload value to control whether to load the option when WordPress starts up.
 544   *                         For backward compatibility 'yes' and 'no' are also accepted, though using these values is
 545   *                         deprecated.
 546   * @return bool True if the autoload value was modified, false otherwise.
 547   */
 548  function wp_set_option_autoload( $option, $autoload ) {
 549      $result = wp_set_option_autoload_values( array( $option => $autoload ) );
 550      return $result[ $option ] ?? false;
 551  }
 552  
 553  /**
 554   * Protects WordPress special option from being modified.
 555   *
 556   * Will die if $option is in protected list. Protected options are 'alloptions'
 557   * and 'notoptions' options.
 558   *
 559   * @since 2.2.0
 560   *
 561   * @param string $option Option name.
 562   */
 563  function wp_protect_special_option( $option ) {
 564      if ( 'alloptions' === $option || 'notoptions' === $option ) {
 565          wp_die(
 566              sprintf(
 567                  /* translators: %s: Option name. */
 568                  __( '%s is a protected WP option and may not be modified' ),
 569                  esc_html( $option )
 570              )
 571          );
 572      }
 573  }
 574  
 575  /**
 576   * Prints option value after sanitizing for forms.
 577   *
 578   * @since 1.5.0
 579   *
 580   * @param string $option Option name.
 581   */
 582  function form_option( $option ) {
 583      echo esc_attr( get_option( $option ) );
 584  }
 585  
 586  /**
 587   * Loads and caches all autoloaded options, if available or all options.
 588   *
 589   * @since 2.2.0
 590   * @since 5.3.1 The `$force_cache` parameter was added.
 591   *
 592   * @global wpdb $wpdb WordPress database abstraction object.
 593   *
 594   * @param bool $force_cache Optional. Whether to force an update of the local cache
 595   *                          from the persistent cache. Default false.
 596   * @return array List of all options.
 597   */
 598  function wp_load_alloptions( $force_cache = false ) {
 599      global $wpdb;
 600  
 601      /**
 602       * Filters the array of alloptions before it is populated.
 603       *
 604       * Returning an array from the filter will effectively short circuit
 605       * wp_load_alloptions(), returning that value instead.
 606       *
 607       * @since 6.2.0
 608       *
 609       * @param array|null $alloptions  An array of alloptions. Default null.
 610       * @param bool       $force_cache Whether to force an update of the local cache from the persistent cache. Default false.
 611       */
 612      $alloptions = apply_filters( 'pre_wp_load_alloptions', null, $force_cache );
 613      if ( is_array( $alloptions ) ) {
 614          return $alloptions;
 615      }
 616  
 617      if ( ! wp_installing() || ! is_multisite() ) {
 618          $alloptions = wp_cache_get( 'alloptions', 'options', $force_cache );
 619      } else {
 620          $alloptions = false;
 621      }
 622  
 623      if ( ! $alloptions ) {
 624          $suppress      = $wpdb->suppress_errors();
 625          $alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE autoload IN ( '" . implode( "', '", esc_sql( wp_autoload_values_to_autoload() ) ) . "' )" );
 626  
 627          if ( ! $alloptions_db ) {
 628              $alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" );
 629          }
 630          $wpdb->suppress_errors( $suppress );
 631  
 632          $alloptions = array();
 633          foreach ( (array) $alloptions_db as $o ) {
 634              $alloptions[ $o->option_name ] = $o->option_value;
 635          }
 636  
 637          if ( ! wp_installing() || ! is_multisite() ) {
 638              /**
 639               * Filters all options before caching them.
 640               *
 641               * @since 4.9.0
 642               *
 643               * @param array $alloptions Array with all options.
 644               */
 645              $alloptions = apply_filters( 'pre_cache_alloptions', $alloptions );
 646  
 647              wp_cache_add( 'alloptions', $alloptions, 'options' );
 648          }
 649      }
 650  
 651      /**
 652       * Filters all options after retrieving them.
 653       *
 654       * @since 4.9.0
 655       *
 656       * @param array $alloptions Array with all options.
 657       */
 658      return apply_filters( 'alloptions', $alloptions );
 659  }
 660  
 661  /**
 662   * Primes specific network options for the current network into the cache with a single database query.
 663   *
 664   * Only network options that do not already exist in cache will be loaded.
 665   *
 666   * If site is not multisite, then call wp_prime_option_caches().
 667   *
 668   * @since 6.6.0
 669   *
 670   * @see wp_prime_network_option_caches()
 671   *
 672   * @param string[] $options An array of option names to be loaded.
 673   */
 674  function wp_prime_site_option_caches( array $options ) {
 675      wp_prime_network_option_caches( null, $options );
 676  }
 677  
 678  /**
 679   * Primes specific network options into the cache with a single database query.
 680   *
 681   * Only network options that do not already exist in cache will be loaded.
 682   *
 683   * If site is not multisite, then call wp_prime_option_caches().
 684   *
 685   * @since 6.6.0
 686   *
 687   * @global wpdb $wpdb WordPress database abstraction object.
 688   *
 689   * @param int|null $network_id ID of the network. Can be null to default to the current network ID.
 690   * @param string[] $options    An array of option names to be loaded.
 691   */
 692  function wp_prime_network_option_caches( $network_id, array $options ) {
 693      global $wpdb;
 694  
 695      if ( wp_installing() ) {
 696          return;
 697      }
 698  
 699      if ( ! is_multisite() ) {
 700          wp_prime_option_caches( $options );
 701          return;
 702      }
 703  
 704      if ( $network_id && ! is_numeric( $network_id ) ) {
 705          return;
 706      }
 707  
 708      $network_id = (int) $network_id;
 709  
 710      // Fallback to the current network if a network ID is not specified.
 711      if ( ! $network_id ) {
 712          $network_id = get_current_network_id();
 713      }
 714  
 715      $cache_keys = array();
 716      foreach ( $options as $option ) {
 717          $cache_keys[ $option ] = "{$network_id}:{$option}";
 718      }
 719  
 720      $cache_group    = 'site-options';
 721      $cached_options = wp_cache_get_multiple( array_values( $cache_keys ), $cache_group );
 722  
 723      $notoptions_key = "$network_id:notoptions";
 724      $notoptions     = wp_cache_get( $notoptions_key, $cache_group );
 725  
 726      if ( ! is_array( $notoptions ) ) {
 727          $notoptions = array();
 728      }
 729  
 730      // Filter options that are not in the cache.
 731      $options_to_prime = array();
 732      foreach ( $cache_keys as $option => $cache_key ) {
 733          if (
 734              ( ! isset( $cached_options[ $cache_key ] ) || false === $cached_options[ $cache_key ] )
 735              && ! isset( $notoptions[ $option ] )
 736          ) {
 737              $options_to_prime[] = $option;
 738          }
 739      }
 740  
 741      // Bail early if there are no options to be loaded.
 742      if ( empty( $options_to_prime ) ) {
 743          return;
 744      }
 745  
 746      $query_args   = $options_to_prime;
 747      $query_args[] = $network_id;
 748      $results      = $wpdb->get_results(
 749          $wpdb->prepare(
 750              sprintf(
 751                  "SELECT meta_key, meta_value FROM $wpdb->sitemeta WHERE meta_key IN (%s) AND site_id = %s",
 752                  implode( ',', array_fill( 0, count( $options_to_prime ), '%s' ) ),
 753                  '%d'
 754              ),
 755              $query_args
 756          )
 757      );
 758  
 759      $data          = array();
 760      $options_found = array();
 761      foreach ( $results as $result ) {
 762          $key                = $result->meta_key;
 763          $cache_key          = $cache_keys[ $key ];
 764          $data[ $cache_key ] = maybe_unserialize( $result->meta_value );
 765          $options_found[]    = $key;
 766      }
 767      wp_cache_set_multiple( $data, $cache_group );
 768      // If all options were found, no need to update `notoptions` cache.
 769      if ( count( $options_found ) === count( $options_to_prime ) ) {
 770          return;
 771      }
 772  
 773      $options_not_found = array_diff( $options_to_prime, $options_found );
 774  
 775      // Add the options that were not found to the cache.
 776      $update_notoptions = false;
 777      foreach ( $options_not_found as $option_name ) {
 778          if ( ! isset( $notoptions[ $option_name ] ) ) {
 779              $notoptions[ $option_name ] = true;
 780              $update_notoptions          = true;
 781          }
 782      }
 783  
 784      // Only update the cache if it was modified.
 785      if ( $update_notoptions ) {
 786          wp_cache_set( $notoptions_key, $notoptions, $cache_group );
 787      }
 788  }
 789  
 790  /**
 791   * Loads and primes caches of certain often requested network options if is_multisite().
 792   *
 793   * @since 3.0.0
 794   * @since 6.3.0 Also prime caches for network options when persistent object cache is enabled.
 795   * @since 6.6.0 Uses wp_prime_network_option_caches().
 796   *
 797   * @param int $network_id Optional. Network ID of network for which to prime network options cache. Defaults to current network.
 798   */
 799  function wp_load_core_site_options( $network_id = null ) {
 800      if ( ! is_multisite() || wp_installing() ) {
 801          return;
 802      }
 803      $core_options = array( 'site_name', 'siteurl', 'active_sitewide_plugins', '_site_transient_timeout_theme_roots', '_site_transient_theme_roots', 'site_admins', 'can_compress_scripts', 'global_terms_enabled', 'ms_files_rewriting', 'WPLANG' );
 804  
 805      wp_prime_network_option_caches( $network_id, $core_options );
 806  }
 807  
 808  /**
 809   * Updates the value of an option that was already added.
 810   *
 811   * You do not need to serialize values. If the value needs to be serialized,
 812   * then it will be serialized before it is inserted into the database.
 813   * Remember, resources cannot be serialized or added as an option.
 814   *
 815   * If the option does not exist, it will be created.
 816  
 817   * This function is designed to work with or without a logged-in user. In terms of security,
 818   * plugin developers should check the current user's capabilities before updating any options.
 819   *
 820   * @since 1.0.0
 821   * @since 4.2.0 The `$autoload` parameter was added.
 822   * @since 6.7.0 The autoload values 'yes' and 'no' are deprecated.
 823   *
 824   * @global wpdb $wpdb WordPress database abstraction object.
 825   *
 826   * @param string    $option   Name of the option to update. Expected to not be SQL-escaped.
 827   * @param mixed     $value    Option value. Must be serializable if non-scalar. Expected to not be SQL-escaped.
 828   * @param bool|null $autoload Optional. Whether to load the option when WordPress starts up.
 829   *                            Accepts a boolean, or `null` to stick with the initial value or, if no initial value is
 830   *                            set, to leave the decision up to default heuristics in WordPress.
 831   *                            For existing options, `$autoload` can only be updated using `update_option()` if `$value`
 832   *                            is also changed.
 833   *                            For backward compatibility 'yes' and 'no' are also accepted, though using these values is
 834   *                            deprecated.
 835   *                            Autoloading too many options can lead to performance problems, especially if the
 836   *                            options are not frequently used. For options which are accessed across several places
 837   *                            in the frontend, it is recommended to autoload them, by using true.
 838   *                            For options which are accessed only on few specific URLs, it is recommended
 839   *                            to not autoload them, by using false.
 840   *                            For non-existent options, the default is null, which means WordPress will determine
 841   *                            the autoload value.
 842   * @return bool True if the value was updated, false otherwise.
 843   */
 844  function update_option( $option, $value, $autoload = null ) {
 845      global $wpdb;
 846  
 847      if ( is_scalar( $option ) ) {
 848          $option = trim( $option );
 849      }
 850  
 851      if ( empty( $option ) ) {
 852          return false;
 853      }
 854  
 855      /*
 856       * Until a proper _deprecated_option() function can be introduced,
 857       * redirect requests to deprecated keys to the new, correct ones.
 858       */
 859      $deprecated_keys = array(
 860          'blacklist_keys'    => 'disallowed_keys',
 861          'comment_whitelist' => 'comment_previously_approved',
 862      );
 863  
 864      if ( isset( $deprecated_keys[ $option ] ) && ! wp_installing() ) {
 865          _deprecated_argument(
 866              __FUNCTION__,
 867              '5.5.0',
 868              sprintf(
 869                  /* translators: 1: Deprecated option key, 2: New option key. */
 870                  __( 'The "%1$s" option key has been renamed to "%2$s".' ),
 871                  $option,
 872                  $deprecated_keys[ $option ]
 873              )
 874          );
 875          return update_option( $deprecated_keys[ $option ], $value, $autoload );
 876      }
 877  
 878      wp_protect_special_option( $option );
 879  
 880      if ( is_object( $value ) ) {
 881          $value = clone $value;
 882      }
 883  
 884      $value     = sanitize_option( $option, $value );
 885      $old_value = get_option( $option );
 886  
 887      /**
 888       * Filters a specific option before its value is (maybe) serialized and updated.
 889       *
 890       * The dynamic portion of the hook name, `$option`, refers to the option name.
 891       *
 892       * @since 2.6.0
 893       * @since 4.4.0 The `$option` parameter was added.
 894       *
 895       * @param mixed  $value     The new, unserialized option value.
 896       * @param mixed  $old_value The old option value.
 897       * @param string $option    Option name.
 898       */
 899      $value = apply_filters( "pre_update_option_{$option}", $value, $old_value, $option );
 900  
 901      /**
 902       * Filters an option before its value is (maybe) serialized and updated.
 903       *
 904       * @since 3.9.0
 905       *
 906       * @param mixed  $value     The new, unserialized option value.
 907       * @param string $option    Name of the option.
 908       * @param mixed  $old_value The old option value.
 909       */
 910      $value = apply_filters( 'pre_update_option', $value, $option, $old_value );
 911  
 912      /*
 913       * If the new and old values are the same, no need to update.
 914       *
 915       * Unserialized values will be adequate in most cases. If the unserialized
 916       * data differs, the (maybe) serialized data is checked to avoid
 917       * unnecessary database calls for otherwise identical object instances.
 918       *
 919       * See https://core.trac.wordpress.org/ticket/38903
 920       */
 921      if ( $value === $old_value || maybe_serialize( $value ) === maybe_serialize( $old_value ) ) {
 922          return false;
 923      }
 924  
 925      /** This filter is documented in wp-includes/option.php */
 926      if ( apply_filters( "default_option_{$option}", false, $option, false ) === $old_value ) {
 927          return add_option( $option, $value, '', $autoload );
 928      }
 929  
 930      $serialized_value = maybe_serialize( $value );
 931  
 932      /**
 933       * Fires immediately before an option value is updated.
 934       *
 935       * @since 2.9.0
 936       *
 937       * @param string $option    Name of the option to update.
 938       * @param mixed  $old_value The old option value.
 939       * @param mixed  $value     The new option value.
 940       */
 941      do_action( 'update_option', $option, $old_value, $value );
 942  
 943      $update_args = array(
 944          'option_value' => $serialized_value,
 945      );
 946  
 947      if ( null !== $autoload ) {
 948          $update_args['autoload'] = wp_determine_option_autoload_value( $option, $value, $serialized_value, $autoload );
 949      } else {
 950          // Retrieve the current autoload value to reevaluate it in case it was set automatically.
 951          $raw_autoload = $wpdb->get_var( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
 952          $allow_values = array( 'auto-on', 'auto-off', 'auto' );
 953          if ( in_array( $raw_autoload, $allow_values, true ) ) {
 954              $autoload = wp_determine_option_autoload_value( $option, $value, $serialized_value, $autoload );
 955              if ( $autoload !== $raw_autoload ) {
 956                  $update_args['autoload'] = $autoload;
 957              }
 958          }
 959      }
 960  
 961      $result = $wpdb->update( $wpdb->options, $update_args, array( 'option_name' => $option ) );
 962      if ( ! $result ) {
 963          return false;
 964      }
 965  
 966      $notoptions = wp_cache_get( 'notoptions', 'options' );
 967  
 968      if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
 969          unset( $notoptions[ $option ] );
 970          wp_cache_set( 'notoptions', $notoptions, 'options' );
 971      }
 972  
 973      if ( ! wp_installing() ) {
 974          if ( ! isset( $update_args['autoload'] ) ) {
 975              // Update the cached value based on where it is currently cached.
 976              $alloptions = wp_load_alloptions( true );
 977  
 978              if ( isset( $alloptions[ $option ] ) ) {
 979                  $alloptions[ $option ] = $serialized_value;
 980                  wp_cache_set( 'alloptions', $alloptions, 'options' );
 981              } else {
 982                  wp_cache_set( $option, $serialized_value, 'options' );
 983              }
 984          } elseif ( in_array( $update_args['autoload'], wp_autoload_values_to_autoload(), true ) ) {
 985              // Delete the individual cache, then set in alloptions cache.
 986              wp_cache_delete( $option, 'options' );
 987  
 988              $alloptions = wp_load_alloptions( true );
 989  
 990              $alloptions[ $option ] = $serialized_value;
 991              wp_cache_set( 'alloptions', $alloptions, 'options' );
 992          } else {
 993              // Delete the alloptions cache, then set the individual cache.
 994              $alloptions = wp_load_alloptions( true );
 995  
 996              if ( isset( $alloptions[ $option ] ) ) {
 997                  unset( $alloptions[ $option ] );
 998                  wp_cache_set( 'alloptions', $alloptions, 'options' );
 999              }
1000  
1001              wp_cache_set( $option, $serialized_value, 'options' );
1002          }
1003      }
1004  
1005      /**
1006       * Fires after the value of a specific option has been successfully updated.
1007       *
1008       * The dynamic portion of the hook name, `$option`, refers to the option name.
1009       *
1010       * @since 2.0.1
1011       * @since 4.4.0 The `$option` parameter was added.
1012       *
1013       * @param mixed  $old_value The old option value.
1014       * @param mixed  $value     The new option value.
1015       * @param string $option    Option name.
1016       */
1017      do_action( "update_option_{$option}", $old_value, $value, $option );
1018  
1019      /**
1020       * Fires after the value of an option has been successfully updated.
1021       *
1022       * @since 2.9.0
1023       *
1024       * @param string $option    Name of the updated option.
1025       * @param mixed  $old_value The old option value.
1026       * @param mixed  $value     The new option value.
1027       */
1028      do_action( 'updated_option', $option, $old_value, $value );
1029  
1030      return true;
1031  }
1032  
1033  /**
1034   * Adds a new option.
1035   *
1036   * You do not need to serialize values. If the value needs to be serialized,
1037   * then it will be serialized before it is inserted into the database.
1038   * Remember, resources cannot be serialized or added as an option.
1039   *
1040   * You can create options without values and then update the values later.
1041   * Existing options will not be updated and checks are performed to ensure that you
1042   * aren't adding a protected WordPress option. Care should be taken to not name
1043   * options the same as the ones which are protected.
1044   *
1045   * @since 1.0.0
1046   * @since 6.6.0 The $autoload parameter's default value was changed to null.
1047   * @since 6.7.0 The autoload values 'yes' and 'no' are deprecated.
1048   *
1049   * @global wpdb $wpdb WordPress database abstraction object.
1050   *
1051   * @param string    $option     Name of the option to add. Expected to not be SQL-escaped.
1052   * @param mixed     $value      Optional. Option value. Must be serializable if non-scalar.
1053   *                              Expected to not be SQL-escaped.
1054   * @param string    $deprecated Optional. Description. Not used anymore.
1055   * @param bool|null $autoload   Optional. Whether to load the option when WordPress starts up.
1056   *                              Accepts a boolean, or `null` to leave the decision up to default heuristics in
1057   *                              WordPress. For backward compatibility 'yes' and 'no' are also accepted, though using
1058   *                              these values is deprecated.
1059   *                              Autoloading too many options can lead to performance problems, especially if the
1060   *                              options are not frequently used. For options which are accessed across several places
1061   *                              in the frontend, it is recommended to autoload them, by using true.
1062   *                              For options which are accessed only on few specific URLs, it is recommended
1063   *                              to not autoload them, by using false.
1064   *                              Default is null, which means WordPress will determine the autoload value.
1065   * @return bool True if the option was added, false otherwise.
1066   */
1067  function add_option( $option, $value = '', $deprecated = '', $autoload = null ) {
1068      global $wpdb;
1069  
1070      if ( ! empty( $deprecated ) ) {
1071          _deprecated_argument( __FUNCTION__, '2.3.0' );
1072      }
1073  
1074      if ( is_scalar( $option ) ) {
1075          $option = trim( $option );
1076      }
1077  
1078      if ( empty( $option ) ) {
1079          return false;
1080      }
1081  
1082      /*
1083       * Until a proper _deprecated_option() function can be introduced,
1084       * redirect requests to deprecated keys to the new, correct ones.
1085       */
1086      $deprecated_keys = array(
1087          'blacklist_keys'    => 'disallowed_keys',
1088          'comment_whitelist' => 'comment_previously_approved',
1089      );
1090  
1091      if ( isset( $deprecated_keys[ $option ] ) && ! wp_installing() ) {
1092          _deprecated_argument(
1093              __FUNCTION__,
1094              '5.5.0',
1095              sprintf(
1096                  /* translators: 1: Deprecated option key, 2: New option key. */
1097                  __( 'The "%1$s" option key has been renamed to "%2$s".' ),
1098                  $option,
1099                  $deprecated_keys[ $option ]
1100              )
1101          );
1102          return add_option( $deprecated_keys[ $option ], $value, $deprecated, $autoload );
1103      }
1104  
1105      wp_protect_special_option( $option );
1106  
1107      if ( is_object( $value ) ) {
1108          $value = clone $value;
1109      }
1110  
1111      $value = sanitize_option( $option, $value );
1112  
1113      /*
1114       * Make sure the option doesn't already exist.
1115       * We can check the 'notoptions' cache before we ask for a DB query.
1116       */
1117      $notoptions = wp_cache_get( 'notoptions', 'options' );
1118  
1119      if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) {
1120          /** This filter is documented in wp-includes/option.php */
1121          if ( apply_filters( "default_option_{$option}", false, $option, false ) !== get_option( $option ) ) {
1122              return false;
1123          }
1124      }
1125  
1126      $serialized_value = maybe_serialize( $value );
1127  
1128      $autoload = wp_determine_option_autoload_value( $option, $value, $serialized_value, $autoload );
1129  
1130      /**
1131       * Fires before an option is added.
1132       *
1133       * @since 2.9.0
1134       *
1135       * @param string $option Name of the option to add.
1136       * @param mixed  $value  Value of the option.
1137       */
1138      do_action( 'add_option', $option, $value );
1139  
1140      $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 ) );
1141      if ( ! $result ) {
1142          return false;
1143      }
1144  
1145      if ( ! wp_installing() ) {
1146          if ( in_array( $autoload, wp_autoload_values_to_autoload(), true ) ) {
1147              $alloptions            = wp_load_alloptions( true );
1148              $alloptions[ $option ] = $serialized_value;
1149              wp_cache_set( 'alloptions', $alloptions, 'options' );
1150          } else {
1151              wp_cache_set( $option, $serialized_value, 'options' );
1152          }
1153      }
1154  
1155      // This option exists now.
1156      $notoptions = wp_cache_get( 'notoptions', 'options' ); // Yes, again... we need it to be fresh.
1157  
1158      if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
1159          unset( $notoptions[ $option ] );
1160          wp_cache_set( 'notoptions', $notoptions, 'options' );
1161      }
1162  
1163      /**
1164       * Fires after a specific option has been added.
1165       *
1166       * The dynamic portion of the hook name, `$option`, refers to the option name.
1167       *
1168       * @since 2.5.0 As `add_option_{$name}`
1169       * @since 3.0.0
1170       *
1171       * @param string $option Name of the option to add.
1172       * @param mixed  $value  Value of the option.
1173       */
1174      do_action( "add_option_{$option}", $option, $value );
1175  
1176      /**
1177       * Fires after an option has been added.
1178       *
1179       * @since 2.9.0
1180       *
1181       * @param string $option Name of the added option.
1182       * @param mixed  $value  Value of the option.
1183       */
1184      do_action( 'added_option', $option, $value );
1185  
1186      return true;
1187  }
1188  
1189  /**
1190   * Removes an option by name. Prevents removal of protected WordPress options.
1191   *
1192   * @since 1.2.0
1193   *
1194   * @global wpdb $wpdb WordPress database abstraction object.
1195   *
1196   * @param string $option Name of the option to delete. Expected to not be SQL-escaped.
1197   * @return bool True if the option was deleted, false otherwise.
1198   */
1199  function delete_option( $option ) {
1200      global $wpdb;
1201  
1202      if ( is_scalar( $option ) ) {
1203          $option = trim( $option );
1204      }
1205  
1206      if ( empty( $option ) ) {
1207          return false;
1208      }
1209  
1210      wp_protect_special_option( $option );
1211  
1212      // Get the ID, if no ID then return.
1213      $row = $wpdb->get_row( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s", $option ) );
1214      if ( is_null( $row ) ) {
1215          return false;
1216      }
1217  
1218      /**
1219       * Fires immediately before an option is deleted.
1220       *
1221       * @since 2.9.0
1222       *
1223       * @param string $option Name of the option to delete.
1224       */
1225      do_action( 'delete_option', $option );
1226  
1227      $result = $wpdb->delete( $wpdb->options, array( 'option_name' => $option ) );
1228  
1229      if ( ! wp_installing() ) {
1230          if ( in_array( $row->autoload, wp_autoload_values_to_autoload(), true ) ) {
1231              $alloptions = wp_load_alloptions( true );
1232  
1233              if ( is_array( $alloptions ) && isset( $alloptions[ $option ] ) ) {
1234                  unset( $alloptions[ $option ] );
1235                  wp_cache_set( 'alloptions', $alloptions, 'options' );
1236              }
1237          } else {
1238              wp_cache_delete( $option, 'options' );
1239          }
1240  
1241          $notoptions = wp_cache_get( 'notoptions', 'options' );
1242  
1243          if ( ! is_array( $notoptions ) ) {
1244              $notoptions = array();
1245          }
1246          $notoptions[ $option ] = true;
1247  
1248          wp_cache_set( 'notoptions', $notoptions, 'options' );
1249      }
1250  
1251      if ( $result ) {
1252  
1253          /**
1254           * Fires after a specific option has been deleted.
1255           *
1256           * The dynamic portion of the hook name, `$option`, refers to the option name.
1257           *
1258           * @since 3.0.0
1259           *
1260           * @param string $option Name of the deleted option.
1261           */
1262          do_action( "delete_option_{$option}", $option );
1263  
1264          /**
1265           * Fires after an option has been deleted.
1266           *
1267           * @since 2.9.0
1268           *
1269           * @param string $option Name of the deleted option.
1270           */
1271          do_action( 'deleted_option', $option );
1272  
1273          return true;
1274      }
1275  
1276      return false;
1277  }
1278  
1279  /**
1280   *  Determines the appropriate autoload value for an option based on input.
1281   *
1282   *  This function checks the provided autoload value and returns a standardized value
1283   *  ('on', 'off', 'auto-on', 'auto-off', or 'auto') based on specific conditions.
1284   *
1285   * If no explicit autoload value is provided, the function will check for certain heuristics around the given option.
1286   * It will return `auto-on` to indicate autoloading, `auto-off` to indicate not autoloading, or `auto` if no clear
1287   * decision could be made.
1288   *
1289   * @since 6.6.0
1290   * @access private
1291   *
1292   * @param string    $option           The name of the option.
1293   * @param mixed     $value            The value of the option to check its autoload value.
1294   * @param mixed     $serialized_value The serialized value of the option to check its autoload value.
1295   * @param bool|null $autoload         The autoload value to check.
1296   *                                    Accepts 'on'|true to enable or 'off'|false to disable, or
1297   *                                    'auto-on', 'auto-off', or 'auto' for internal purposes.
1298   *                                    Any other autoload value will be forced to either 'auto-on',
1299   *                                    'auto-off', or 'auto'.
1300   *                                    'yes' and 'no' are supported for backward compatibility.
1301   * @return string Returns the original $autoload value if explicit, or 'auto-on', 'auto-off',
1302   *                or 'auto' depending on default heuristics.
1303   */
1304  function wp_determine_option_autoload_value( $option, $value, $serialized_value, $autoload ) {
1305  
1306      // Check if autoload is a boolean.
1307      if ( is_bool( $autoload ) ) {
1308          return $autoload ? 'on' : 'off';
1309      }
1310  
1311      switch ( $autoload ) {
1312          case 'on':
1313          case 'yes':
1314              return 'on';
1315          case 'off':
1316          case 'no':
1317              return 'off';
1318      }
1319  
1320      /**
1321       * Allows to determine the default autoload value for an option where no explicit value is passed.
1322       *
1323       * @since 6.6.0
1324       *
1325       * @param bool|null $autoload         The default autoload value to set. Returning true will be set as 'auto-on' in the
1326       *                                    database, false will be set as 'auto-off', and null will be set as 'auto'.
1327       * @param string    $option           The passed option name.
1328       * @param mixed     $value            The passed option value to be saved.
1329       * @param mixed     $serialized_value The passed option value to be saved, in serialized form.
1330       */
1331      $autoload = apply_filters( 'wp_default_autoload_value', null, $option, $value, $serialized_value );
1332      if ( is_bool( $autoload ) ) {
1333          return $autoload ? 'auto-on' : 'auto-off';
1334      }
1335  
1336      return 'auto';
1337  }
1338  
1339  /**
1340   * Filters the default autoload value to disable autoloading if the option value is too large.
1341   *
1342   * @since 6.6.0
1343   * @access private
1344   *
1345   * @param bool|null $autoload         The default autoload value to set.
1346   * @param string    $option           The passed option name.
1347   * @param mixed     $value            The passed option value to be saved.
1348   * @param mixed     $serialized_value The passed option value to be saved, in serialized form.
1349   * @return bool|null Potentially modified $default.
1350   */
1351  function wp_filter_default_autoload_value_via_option_size( $autoload, $option, $value, $serialized_value ) {
1352      /**
1353       * Filters the maximum size of option value in bytes.
1354       *
1355       * @since 6.6.0
1356       *
1357       * @param int    $max_option_size The option-size threshold, in bytes. Default 150000.
1358       * @param string $option          The name of the option.
1359       */
1360      $max_option_size = (int) apply_filters( 'wp_max_autoloaded_option_size', 150000, $option );
1361      $size            = ! empty( $serialized_value ) ? strlen( $serialized_value ) : 0;
1362  
1363      if ( $size > $max_option_size ) {
1364          return false;
1365      }
1366  
1367      return $autoload;
1368  }
1369  
1370  /**
1371   * Deletes a transient.
1372   *
1373   * @since 2.8.0
1374   *
1375   * @param string $transient Transient name. Expected to not be SQL-escaped.
1376   * @return bool True if the transient was deleted, false otherwise.
1377   */
1378  function delete_transient( $transient ) {
1379  
1380      /**
1381       * Fires immediately before a specific transient is deleted.
1382       *
1383       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1384       *
1385       * @since 3.0.0
1386       *
1387       * @param string $transient Transient name.
1388       */
1389      do_action( "delete_transient_{$transient}", $transient );
1390  
1391      if ( wp_using_ext_object_cache() || wp_installing() ) {
1392          $result = wp_cache_delete( $transient, 'transient' );
1393      } else {
1394          $option_timeout = '_transient_timeout_' . $transient;
1395          $option         = '_transient_' . $transient;
1396          $result         = delete_option( $option );
1397  
1398          if ( $result ) {
1399              delete_option( $option_timeout );
1400          }
1401      }
1402  
1403      if ( $result ) {
1404  
1405          /**
1406           * Fires after a transient is deleted.
1407           *
1408           * @since 3.0.0
1409           *
1410           * @param string $transient Deleted transient name.
1411           */
1412          do_action( 'deleted_transient', $transient );
1413      }
1414  
1415      return $result;
1416  }
1417  
1418  /**
1419   * Retrieves the value of a transient.
1420   *
1421   * If the transient does not exist, does not have a value, or has expired,
1422   * then the return value will be false.
1423   *
1424   * @since 2.8.0
1425   *
1426   * @param string $transient Transient name. Expected to not be SQL-escaped.
1427   * @return mixed Value of transient.
1428   */
1429  function get_transient( $transient ) {
1430  
1431      /**
1432       * Filters the value of an existing transient before it is retrieved.
1433       *
1434       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1435       *
1436       * Returning a value other than false from the filter will short-circuit retrieval
1437       * and return that value instead.
1438       *
1439       * @since 2.8.0
1440       * @since 4.4.0 The `$transient` parameter was added
1441       *
1442       * @param mixed  $pre_transient The default value to return if the transient does not exist.
1443       *                              Any value other than false will short-circuit the retrieval
1444       *                              of the transient, and return that value.
1445       * @param string $transient     Transient name.
1446       */
1447      $pre = apply_filters( "pre_transient_{$transient}", false, $transient );
1448  
1449      if ( false !== $pre ) {
1450          return $pre;
1451      }
1452  
1453      if ( wp_using_ext_object_cache() || wp_installing() ) {
1454          $value = wp_cache_get( $transient, 'transient' );
1455      } else {
1456          $transient_option = '_transient_' . $transient;
1457          if ( ! wp_installing() ) {
1458              // If option is not in alloptions, it is not autoloaded and thus has a timeout.
1459              $alloptions = wp_load_alloptions();
1460  
1461              if ( ! isset( $alloptions[ $transient_option ] ) ) {
1462                  $transient_timeout = '_transient_timeout_' . $transient;
1463                  wp_prime_option_caches( array( $transient_option, $transient_timeout ) );
1464                  $timeout = get_option( $transient_timeout );
1465                  if ( false !== $timeout && $timeout < time() ) {
1466                      delete_option( $transient_option );
1467                      delete_option( $transient_timeout );
1468                      $value = false;
1469                  }
1470              }
1471          }
1472  
1473          if ( ! isset( $value ) ) {
1474              $value = get_option( $transient_option );
1475          }
1476      }
1477  
1478      /**
1479       * Filters an existing transient's value.
1480       *
1481       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1482       *
1483       * @since 2.8.0
1484       * @since 4.4.0 The `$transient` parameter was added
1485       *
1486       * @param mixed  $value     Value of transient.
1487       * @param string $transient Transient name.
1488       */
1489      return apply_filters( "transient_{$transient}", $value, $transient );
1490  }
1491  
1492  /**
1493   * Sets/updates the value of a transient.
1494   *
1495   * You do not need to serialize values. If the value needs to be serialized,
1496   * then it will be serialized before it is set.
1497   *
1498   * @since 2.8.0
1499   *
1500   * @param string $transient  Transient name. Expected to not be SQL-escaped.
1501   *                           Must be 172 characters or fewer in length.
1502   * @param mixed  $value      Transient value. Must be serializable if non-scalar.
1503   *                           Expected to not be SQL-escaped.
1504   * @param int    $expiration Optional. Time until expiration in seconds. Default 0 (no expiration).
1505   * @return bool True if the value was set, false otherwise.
1506   */
1507  function set_transient( $transient, $value, $expiration = 0 ) {
1508  
1509      $expiration = (int) $expiration;
1510  
1511      /**
1512       * Filters a specific transient before its value is set.
1513       *
1514       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1515       *
1516       * @since 3.0.0
1517       * @since 4.2.0 The `$expiration` parameter was added.
1518       * @since 4.4.0 The `$transient` parameter was added.
1519       *
1520       * @param mixed  $value      New value of transient.
1521       * @param int    $expiration Time until expiration in seconds.
1522       * @param string $transient  Transient name.
1523       */
1524      $value = apply_filters( "pre_set_transient_{$transient}", $value, $expiration, $transient );
1525  
1526      /**
1527       * Filters the expiration for a transient before its value is set.
1528       *
1529       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1530       *
1531       * @since 4.4.0
1532       *
1533       * @param int    $expiration Time until expiration in seconds. Use 0 for no expiration.
1534       * @param mixed  $value      New value of transient.
1535       * @param string $transient  Transient name.
1536       */
1537      $expiration = apply_filters( "expiration_of_transient_{$transient}", $expiration, $value, $transient );
1538  
1539      if ( wp_using_ext_object_cache() || wp_installing() ) {
1540          $result = wp_cache_set( $transient, $value, 'transient', $expiration );
1541      } else {
1542          $transient_timeout = '_transient_timeout_' . $transient;
1543          $transient_option  = '_transient_' . $transient;
1544          wp_prime_option_caches( array( $transient_option, $transient_timeout ) );
1545  
1546          if ( false === get_option( $transient_option ) ) {
1547              $autoload = true;
1548              if ( $expiration ) {
1549                  $autoload = false;
1550                  add_option( $transient_timeout, time() + $expiration, '', false );
1551              }
1552              $result = add_option( $transient_option, $value, '', $autoload );
1553          } else {
1554              /*
1555               * If expiration is requested, but the transient has no timeout option,
1556               * delete, then re-create transient rather than update.
1557               */
1558              $update = true;
1559  
1560              if ( $expiration ) {
1561                  if ( false === get_option( $transient_timeout ) ) {
1562                      delete_option( $transient_option );
1563                      add_option( $transient_timeout, time() + $expiration, '', false );
1564                      $result = add_option( $transient_option, $value, '', false );
1565                      $update = false;
1566                  } else {
1567                      update_option( $transient_timeout, time() + $expiration );
1568                  }
1569              }
1570  
1571              if ( $update ) {
1572                  $result = update_option( $transient_option, $value );
1573              }
1574          }
1575      }
1576  
1577      if ( $result ) {
1578  
1579          /**
1580           * Fires after the value for a specific transient has been set.
1581           *
1582           * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1583           *
1584           * @since 3.0.0
1585           * @since 3.6.0 The `$value` and `$expiration` parameters were added.
1586           * @since 4.4.0 The `$transient` parameter was added.
1587           *
1588           * @param mixed  $value      Transient value.
1589           * @param int    $expiration Time until expiration in seconds.
1590           * @param string $transient  The name of the transient.
1591           */
1592          do_action( "set_transient_{$transient}", $value, $expiration, $transient );
1593  
1594          /**
1595           * Fires after the value for a transient has been set.
1596           *
1597           * @since 6.8.0
1598           *
1599           * @param string $transient  The name of the transient.
1600           * @param mixed  $value      Transient value.
1601           * @param int    $expiration Time until expiration in seconds.
1602           */
1603          do_action( 'set_transient', $transient, $value, $expiration );
1604  
1605          /**
1606           * Fires after the transient is set.
1607           *
1608           * @since 3.0.0
1609           * @since 3.6.0 The `$value` and `$expiration` parameters were added.
1610           * @deprecated 6.8.0 Use {@see 'set_transient'} instead.
1611           *
1612           * @param string $transient  The name of the transient.
1613           * @param mixed  $value      Transient value.
1614           * @param int    $expiration Time until expiration in seconds.
1615           */
1616          do_action_deprecated( 'setted_transient', array( $transient, $value, $expiration ), '6.8.0', 'set_transient' );
1617      }
1618  
1619      return $result;
1620  }
1621  
1622  /**
1623   * Deletes all expired transients.
1624   *
1625   * Note that this function won't do anything if an external object cache is in use.
1626   *
1627   * The multi-table delete syntax is used to delete the transient record
1628   * from table a, and the corresponding transient_timeout record from table b.
1629   *
1630   * @since 4.9.0
1631   *
1632   * @global wpdb $wpdb WordPress database abstraction object.
1633   *
1634   * @param bool $force_db Optional. Force cleanup to run against the database even when an external object cache is used.
1635   */
1636  function delete_expired_transients( $force_db = false ) {
1637      global $wpdb;
1638  
1639      if ( ! $force_db && wp_using_ext_object_cache() ) {
1640          return;
1641      }
1642  
1643      $wpdb->query(
1644          $wpdb->prepare(
1645              "DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b
1646              WHERE a.option_name LIKE %s
1647              AND a.option_name NOT LIKE %s
1648              AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) )
1649              AND b.option_value < %d",
1650              $wpdb->esc_like( '_transient_' ) . '%',
1651              $wpdb->esc_like( '_transient_timeout_' ) . '%',
1652              time()
1653          )
1654      );
1655  
1656      if ( ! is_multisite() ) {
1657          // Single site stores site transients in the options table.
1658          $wpdb->query(
1659              $wpdb->prepare(
1660                  "DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b
1661                  WHERE a.option_name LIKE %s
1662                  AND a.option_name NOT LIKE %s
1663                  AND b.option_name = CONCAT( '_site_transient_timeout_', SUBSTRING( a.option_name, 17 ) )
1664                  AND b.option_value < %d",
1665                  $wpdb->esc_like( '_site_transient_' ) . '%',
1666                  $wpdb->esc_like( '_site_transient_timeout_' ) . '%',
1667                  time()
1668              )
1669          );
1670      } elseif ( is_main_site() && is_main_network() ) {
1671          // Multisite stores site transients in the sitemeta table.
1672          $wpdb->query(
1673              $wpdb->prepare(
1674                  "DELETE a, b FROM {$wpdb->sitemeta} a, {$wpdb->sitemeta} b
1675                  WHERE a.meta_key LIKE %s
1676                  AND a.meta_key NOT LIKE %s
1677                  AND b.meta_key = CONCAT( '_site_transient_timeout_', SUBSTRING( a.meta_key, 17 ) )
1678                  AND b.meta_value < %d",
1679                  $wpdb->esc_like( '_site_transient_' ) . '%',
1680                  $wpdb->esc_like( '_site_transient_timeout_' ) . '%',
1681                  time()
1682              )
1683          );
1684      }
1685  }
1686  
1687  /**
1688   * Saves and restores user interface settings stored in a cookie.
1689   *
1690   * Checks if the current user-settings cookie is updated and stores it. When no
1691   * cookie exists (different browser used), adds the last saved cookie restoring
1692   * the settings.
1693   *
1694   * @since 2.7.0
1695   */
1696  function wp_user_settings() {
1697  
1698      if ( ! is_admin() || wp_doing_ajax() ) {
1699          return;
1700      }
1701  
1702      $user_id = get_current_user_id();
1703      if ( ! $user_id ) {
1704          return;
1705      }
1706  
1707      if ( ! is_user_member_of_blog() ) {
1708          return;
1709      }
1710  
1711      $settings = (string) get_user_option( 'user-settings', $user_id );
1712  
1713      if ( isset( $_COOKIE[ 'wp-settings-' . $user_id ] ) ) {
1714          $cookie = preg_replace( '/[^A-Za-z0-9=&_]/', '', $_COOKIE[ 'wp-settings-' . $user_id ] );
1715  
1716          // No change or both empty.
1717          if ( $cookie === $settings ) {
1718              return;
1719          }
1720  
1721          $last_saved = (int) get_user_option( 'user-settings-time', $user_id );
1722          $current    = 0;
1723  
1724          if ( isset( $_COOKIE[ 'wp-settings-time-' . $user_id ] ) ) {
1725              $current = (int) preg_replace( '/[^0-9]/', '', $_COOKIE[ 'wp-settings-time-' . $user_id ] );
1726          }
1727  
1728          // The cookie is newer than the saved value. Update the user_option and leave the cookie as-is.
1729          if ( $current > $last_saved ) {
1730              update_user_option( $user_id, 'user-settings', $cookie, false );
1731              update_user_option( $user_id, 'user-settings-time', time() - 5, false );
1732              return;
1733          }
1734      }
1735  
1736      // The cookie is not set in the current browser or the saved value is newer.
1737      $secure = ( 'https' === parse_url( admin_url(), PHP_URL_SCHEME ) );
1738      setcookie( 'wp-settings-' . $user_id, $settings, time() + YEAR_IN_SECONDS, SITECOOKIEPATH, '', $secure );
1739      setcookie( 'wp-settings-time-' . $user_id, time(), time() + YEAR_IN_SECONDS, SITECOOKIEPATH, '', $secure );
1740      $_COOKIE[ 'wp-settings-' . $user_id ] = $settings;
1741  }
1742  
1743  /**
1744   * Retrieves user interface setting value based on setting name.
1745   *
1746   * @since 2.7.0
1747   *
1748   * @param string       $name          The name of the setting.
1749   * @param string|false $default_value Optional. Default value to return when $name is not set. Default false.
1750   * @return mixed The last saved user setting or the default value/false if it doesn't exist.
1751   */
1752  function get_user_setting( $name, $default_value = false ) {
1753      $all_user_settings = get_all_user_settings();
1754  
1755      return $all_user_settings[ $name ] ?? $default_value;
1756  }
1757  
1758  /**
1759   * Adds or updates user interface setting.
1760   *
1761   * Both `$name` and `$value` can contain only ASCII letters, numbers, hyphens, and underscores.
1762   *
1763   * This function has to be used before any output has started as it calls `setcookie()`.
1764   *
1765   * @since 2.8.0
1766   *
1767   * @param string $name  The name of the setting.
1768   * @param string $value The value for the setting.
1769   * @return bool|null True if set successfully, false otherwise.
1770   *                   Null if the current user is not a member of the site.
1771   */
1772  function set_user_setting( $name, $value ) {
1773      if ( headers_sent() ) {
1774          return false;
1775      }
1776  
1777      $all_user_settings          = get_all_user_settings();
1778      $all_user_settings[ $name ] = $value;
1779  
1780      return wp_set_all_user_settings( $all_user_settings );
1781  }
1782  
1783  /**
1784   * Deletes user interface settings.
1785   *
1786   * Deleting settings would reset them to the defaults.
1787   *
1788   * This function has to be used before any output has started as it calls `setcookie()`.
1789   *
1790   * @since 2.7.0
1791   *
1792   * @param string $names The name or array of names of the setting to be deleted.
1793   * @return bool|null True if deleted successfully, false otherwise.
1794   *                   Null if the current user is not a member of the site.
1795   */
1796  function delete_user_setting( $names ) {
1797      if ( headers_sent() ) {
1798          return false;
1799      }
1800  
1801      $all_user_settings = get_all_user_settings();
1802      $names             = (array) $names;
1803      $deleted           = false;
1804  
1805      foreach ( $names as $name ) {
1806          if ( isset( $all_user_settings[ $name ] ) ) {
1807              unset( $all_user_settings[ $name ] );
1808              $deleted = true;
1809          }
1810      }
1811  
1812      if ( $deleted ) {
1813          return wp_set_all_user_settings( $all_user_settings );
1814      }
1815  
1816      return false;
1817  }
1818  
1819  /**
1820   * Retrieves all user interface settings.
1821   *
1822   * @since 2.7.0
1823   *
1824   * @global array $_updated_user_settings
1825   *
1826   * @return array The last saved user settings or empty array.
1827   */
1828  function get_all_user_settings() {
1829      global $_updated_user_settings;
1830  
1831      $user_id = get_current_user_id();
1832      if ( ! $user_id ) {
1833          return array();
1834      }
1835  
1836      if ( isset( $_updated_user_settings ) && is_array( $_updated_user_settings ) ) {
1837          return $_updated_user_settings;
1838      }
1839  
1840      $user_settings = array();
1841  
1842      if ( isset( $_COOKIE[ 'wp-settings-' . $user_id ] ) ) {
1843          $cookie = preg_replace( '/[^A-Za-z0-9=&_-]/', '', $_COOKIE[ 'wp-settings-' . $user_id ] );
1844  
1845          if ( strpos( $cookie, '=' ) ) { // '=' cannot be 1st char.
1846              parse_str( $cookie, $user_settings );
1847          }
1848      } else {
1849          $option = get_user_option( 'user-settings', $user_id );
1850  
1851          if ( $option && is_string( $option ) ) {
1852              parse_str( $option, $user_settings );
1853          }
1854      }
1855  
1856      $_updated_user_settings = $user_settings;
1857      return $user_settings;
1858  }
1859  
1860  /**
1861   * Private. Sets all user interface settings.
1862   *
1863   * @since 2.8.0
1864   * @access private
1865   *
1866   * @global array $_updated_user_settings
1867   *
1868   * @param array $user_settings User settings.
1869   * @return bool|null True if set successfully, false if the current user could not be found.
1870   *                   Null if the current user is not a member of the site.
1871   */
1872  function wp_set_all_user_settings( $user_settings ) {
1873      global $_updated_user_settings;
1874  
1875      $user_id = get_current_user_id();
1876      if ( ! $user_id ) {
1877          return false;
1878      }
1879  
1880      if ( ! is_user_member_of_blog() ) {
1881          return null;
1882      }
1883  
1884      $settings = '';
1885      foreach ( $user_settings as $name => $value ) {
1886          $_name  = preg_replace( '/[^A-Za-z0-9_-]+/', '', $name );
1887          $_value = preg_replace( '/[^A-Za-z0-9_-]+/', '', $value );
1888  
1889          if ( ! empty( $_name ) ) {
1890              $settings .= $_name . '=' . $_value . '&';
1891          }
1892      }
1893  
1894      $settings = rtrim( $settings, '&' );
1895      parse_str( $settings, $_updated_user_settings );
1896  
1897      update_user_option( $user_id, 'user-settings', $settings, false );
1898      update_user_option( $user_id, 'user-settings-time', time(), false );
1899  
1900      return true;
1901  }
1902  
1903  /**
1904   * Deletes the user settings of the current user.
1905   *
1906   * @since 2.7.0
1907   */
1908  function delete_all_user_settings() {
1909      $user_id = get_current_user_id();
1910      if ( ! $user_id ) {
1911          return;
1912      }
1913  
1914      update_user_option( $user_id, 'user-settings', '', false );
1915      setcookie( 'wp-settings-' . $user_id, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH );
1916  }
1917  
1918  /**
1919   * Retrieve an option value for the current network based on name of option.
1920   *
1921   * @since 2.8.0
1922   * @since 4.4.0 The `$use_cache` parameter was deprecated.
1923   * @since 4.4.0 Modified into wrapper for get_network_option()
1924   *
1925   * @see get_network_option()
1926   *
1927   * @param string $option        Name of the option to retrieve. Expected to not be SQL-escaped.
1928   * @param mixed  $default_value Optional. Value to return if the option doesn't exist. Default false.
1929   * @param bool   $deprecated    Whether to use cache. Multisite only. Always set to true.
1930   * @return mixed Value set for the option.
1931   */
1932  function get_site_option( $option, $default_value = false, $deprecated = true ) {
1933      return get_network_option( null, $option, $default_value );
1934  }
1935  
1936  /**
1937   * Adds a new option for the current network.
1938   *
1939   * Existing options will not be updated. Note that prior to 3.3 this wasn't the case.
1940   *
1941   * @since 2.8.0
1942   * @since 4.4.0 Modified into wrapper for add_network_option()
1943   *
1944   * @see add_network_option()
1945   *
1946   * @param string $option Name of the option to add. Expected to not be SQL-escaped.
1947   * @param mixed  $value  Option value, can be anything. Expected to not be SQL-escaped.
1948   * @return bool True if the option was added, false otherwise.
1949   */
1950  function add_site_option( $option, $value ) {
1951      return add_network_option( null, $option, $value );
1952  }
1953  
1954  /**
1955   * Removes an option by name for the current network.
1956   *
1957   * @since 2.8.0
1958   * @since 4.4.0 Modified into wrapper for delete_network_option()
1959   *
1960   * @see delete_network_option()
1961   *
1962   * @param string $option Name of the option to delete. Expected to not be SQL-escaped.
1963   * @return bool True if the option was deleted, false otherwise.
1964   */
1965  function delete_site_option( $option ) {
1966      return delete_network_option( null, $option );
1967  }
1968  
1969  /**
1970   * Updates the value of an option that was already added for the current network.
1971   *
1972   * @since 2.8.0
1973   * @since 4.4.0 Modified into wrapper for update_network_option()
1974   *
1975   * @see update_network_option()
1976   *
1977   * @param string $option Name of the option. Expected to not be SQL-escaped.
1978   * @param mixed  $value  Option value. Expected to not be SQL-escaped.
1979   * @return bool True if the value was updated, false otherwise.
1980   */
1981  function update_site_option( $option, $value ) {
1982      return update_network_option( null, $option, $value );
1983  }
1984  
1985  /**
1986   * Retrieves a network's option value based on the option name.
1987   *
1988   * @since 4.4.0
1989   *
1990   * @see get_option()
1991   *
1992   * @global wpdb $wpdb WordPress database abstraction object.
1993   *
1994   * @param int|null $network_id    ID of the network. Can be null to default to the current network ID.
1995   * @param string   $option        Name of the option to retrieve. Expected to not be SQL-escaped.
1996   * @param mixed    $default_value Optional. Value to return if the option doesn't exist. Default false.
1997   * @return mixed Value set for the option.
1998   */
1999  function get_network_option( $network_id, $option, $default_value = false ) {
2000      global $wpdb;
2001  
2002      if ( $network_id && ! is_numeric( $network_id ) ) {
2003          return false;
2004      }
2005  
2006      $network_id = (int) $network_id;
2007  
2008      // Fallback to the current network if a network ID is not specified.
2009      if ( ! $network_id ) {
2010          $network_id = get_current_network_id();
2011      }
2012  
2013      /**
2014       * Filters the value of an existing network option before it is retrieved.
2015       *
2016       * The dynamic portion of the hook name, `$option`, refers to the option name.
2017       *
2018       * Returning a value other than false from the filter will short-circuit retrieval
2019       * and return that value instead.
2020       *
2021       * @since 2.9.0 As `pre_site_option_{$key}`.
2022       * @since 3.0.0
2023       * @since 4.4.0 The `$option` parameter was added.
2024       * @since 4.7.0 The `$network_id` parameter was added.
2025       * @since 4.9.0 The `$default_value` parameter was added.
2026       *
2027       * @param mixed  $pre_site_option The value to return instead of the option value. This differs from
2028       *                                `$default_value`, which is used as the fallback value in the event
2029       *                                the option doesn't exist elsewhere in get_network_option().
2030       *                                Default false (to skip past the short-circuit).
2031       * @param string $option          Option name.
2032       * @param int    $network_id      ID of the network.
2033       * @param mixed  $default_value   The fallback value to return if the option does not exist.
2034       *                                Default false.
2035       */
2036      $pre = apply_filters( "pre_site_option_{$option}", false, $option, $network_id, $default_value );
2037  
2038      /**
2039       * Filters the value of any existing network option before it is retrieved.
2040       *
2041       * Returning a value other than false from the filter will short-circuit retrieval
2042       * and return that value instead.
2043       *
2044       * @since 6.9.0
2045       *
2046       * @param mixed  $pre_option    The value to return instead of the network option value. This differs
2047       *                              from `$default_value`, which is used as the fallback value in the event
2048       *                              the option doesn't exist elsewhere in get_network_option().
2049       *                              Default false (to skip past the short-circuit).
2050       * @param string $option        Name of the option.
2051       * @param int    $network_id    ID of the network.
2052       * @param mixed  $default_value The fallback value to return if the option does not exist.
2053       *                              Default false.
2054       */
2055      $pre = apply_filters( 'pre_site_option', $pre, $option, $network_id, $default_value );
2056  
2057      if ( false !== $pre ) {
2058          return $pre;
2059      }
2060  
2061      // Prevent non-existent options from triggering multiple queries.
2062      $notoptions_key = "$network_id:notoptions";
2063      $notoptions     = wp_cache_get( $notoptions_key, 'site-options' );
2064  
2065      if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
2066  
2067          /**
2068           * Filters the value of a specific default network option.
2069           *
2070           * The dynamic portion of the hook name, `$option`, refers to the option name.
2071           *
2072           * @since 3.4.0
2073           * @since 4.4.0 The `$option` parameter was added.
2074           * @since 4.7.0 The `$network_id` parameter was added.
2075           *
2076           * @param mixed  $default_value The value to return if the site option does not exist
2077           *                              in the database.
2078           * @param string $option        Option name.
2079           * @param int    $network_id    ID of the network.
2080           */
2081          return apply_filters( "default_site_option_{$option}", $default_value, $option, $network_id );
2082      }
2083  
2084      if ( ! is_multisite() ) {
2085          /** This filter is documented in wp-includes/option.php */
2086          $default_value = apply_filters( 'default_site_option_' . $option, $default_value, $option, $network_id );
2087          $value         = get_option( $option, $default_value );
2088      } else {
2089          $cache_key = "$network_id:$option";
2090          $value     = wp_cache_get( $cache_key, 'site-options' );
2091  
2092          if ( ! isset( $value ) || false === $value ) {
2093              $row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
2094  
2095              // Has to be get_row() instead of get_var() because of funkiness with 0, false, null values.
2096              if ( is_object( $row ) ) {
2097                  $value = $row->meta_value;
2098                  $value = maybe_unserialize( $value );
2099                  wp_cache_set( $cache_key, $value, 'site-options' );
2100              } else {
2101                  if ( ! is_array( $notoptions ) ) {
2102                      $notoptions = array();
2103                  }
2104  
2105                  $notoptions[ $option ] = true;
2106                  wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
2107  
2108                  /** This filter is documented in wp-includes/option.php */
2109                  $value = apply_filters( 'default_site_option_' . $option, $default_value, $option, $network_id );
2110              }
2111          }
2112      }
2113  
2114      if ( ! is_array( $notoptions ) ) {
2115          $notoptions = array();
2116          wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
2117      }
2118  
2119      /**
2120       * Filters the value of an existing network option.
2121       *
2122       * The dynamic portion of the hook name, `$option`, refers to the option name.
2123       *
2124       * @since 2.9.0 As `site_option_{$key}`.
2125       * @since 3.0.0
2126       * @since 4.4.0 The `$option` parameter was added.
2127       * @since 4.7.0 The `$network_id` parameter was added.
2128       *
2129       * @param mixed  $value      Value of network option.
2130       * @param string $option     Option name.
2131       * @param int    $network_id ID of the network.
2132       */
2133      return apply_filters( "site_option_{$option}", $value, $option, $network_id );
2134  }
2135  
2136  /**
2137   * Adds a new network option.
2138   *
2139   * Existing options will not be updated.
2140   *
2141   * @since 4.4.0
2142   *
2143   * @see add_option()
2144   *
2145   * @global wpdb $wpdb WordPress database abstraction object.
2146   *
2147   * @param int|null $network_id ID of the network. Can be null to default to the current network ID.
2148   * @param string   $option     Name of the option to add. Expected to not be SQL-escaped.
2149   * @param mixed    $value      Option value, can be anything. Expected to not be SQL-escaped.
2150   * @return bool True if the option was added, false otherwise.
2151   */
2152  function add_network_option( $network_id, $option, $value ) {
2153      global $wpdb;
2154  
2155      if ( $network_id && ! is_numeric( $network_id ) ) {
2156          return false;
2157      }
2158  
2159      $network_id = (int) $network_id;
2160  
2161      // Fallback to the current network if a network ID is not specified.
2162      if ( ! $network_id ) {
2163          $network_id = get_current_network_id();
2164      }
2165  
2166      wp_protect_special_option( $option );
2167  
2168      /**
2169       * Filters the value of a specific network option before it is added.
2170       *
2171       * The dynamic portion of the hook name, `$option`, refers to the option name.
2172       *
2173       * @since 2.9.0 As `pre_add_site_option_{$key}`.
2174       * @since 3.0.0
2175       * @since 4.4.0 The `$option` parameter was added.
2176       * @since 4.7.0 The `$network_id` parameter was added.
2177       *
2178       * @param mixed  $value      Value of network option.
2179       * @param string $option     Option name.
2180       * @param int    $network_id ID of the network.
2181       */
2182      $value = apply_filters( "pre_add_site_option_{$option}", $value, $option, $network_id );
2183  
2184      $notoptions_key = "$network_id:notoptions";
2185  
2186      if ( ! is_multisite() ) {
2187          $result = add_option( $option, $value, '', false );
2188      } else {
2189          $cache_key = "$network_id:$option";
2190  
2191          /*
2192           * Make sure the option doesn't already exist.
2193           * We can check the 'notoptions' cache before we ask for a DB query.
2194           */
2195          $notoptions = wp_cache_get( $notoptions_key, 'site-options' );
2196  
2197          if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) {
2198              if ( false !== get_network_option( $network_id, $option, false ) ) {
2199                  return false;
2200              }
2201          }
2202  
2203          $value = sanitize_option( $option, $value );
2204  
2205          $serialized_value = maybe_serialize( $value );
2206          $result           = $wpdb->insert(
2207              $wpdb->sitemeta,
2208              array(
2209                  'site_id'    => $network_id,
2210                  'meta_key'   => $option,
2211                  'meta_value' => $serialized_value,
2212              )
2213          );
2214  
2215          if ( ! $result ) {
2216              return false;
2217          }
2218  
2219          wp_cache_set( $cache_key, $value, 'site-options' );
2220  
2221          // This option exists now.
2222          $notoptions = wp_cache_get( $notoptions_key, 'site-options' ); // Yes, again... we need it to be fresh.
2223  
2224          if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
2225              unset( $notoptions[ $option ] );
2226              wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
2227          }
2228      }
2229  
2230      if ( $result ) {
2231  
2232          /**
2233           * Fires after a specific network option has been successfully added.
2234           *
2235           * The dynamic portion of the hook name, `$option`, refers to the option name.
2236           *
2237           * @since 2.9.0 As `add_site_option_{$key}`.
2238           * @since 3.0.0
2239           * @since 4.7.0 The `$network_id` parameter was added.
2240           *
2241           * @param string $option     Name of the network option.
2242           * @param mixed  $value      Value of the network option.
2243           * @param int    $network_id ID of the network.
2244           */
2245          do_action( "add_site_option_{$option}", $option, $value, $network_id );
2246  
2247          /**
2248           * Fires after a network option has been successfully added.
2249           *
2250           * @since 3.0.0
2251           * @since 4.7.0 The `$network_id` parameter was added.
2252           *
2253           * @param string $option     Name of the network option.
2254           * @param mixed  $value      Value of the network option.
2255           * @param int    $network_id ID of the network.
2256           */
2257          do_action( 'add_site_option', $option, $value, $network_id );
2258  
2259          return true;
2260      }
2261  
2262      return false;
2263  }
2264  
2265  /**
2266   * Removes a network option by name.
2267   *
2268   * @since 4.4.0
2269   *
2270   * @see delete_option()
2271   *
2272   * @global wpdb $wpdb WordPress database abstraction object.
2273   *
2274   * @param int|null $network_id ID of the network. Can be null to default to the current network ID.
2275   * @param string   $option     Name of the option to delete. Expected to not be SQL-escaped.
2276   * @return bool True if the option was deleted, false otherwise.
2277   */
2278  function delete_network_option( $network_id, $option ) {
2279      global $wpdb;
2280  
2281      if ( $network_id && ! is_numeric( $network_id ) ) {
2282          return false;
2283      }
2284  
2285      $network_id = (int) $network_id;
2286  
2287      // Fallback to the current network if a network ID is not specified.
2288      if ( ! $network_id ) {
2289          $network_id = get_current_network_id();
2290      }
2291  
2292      /**
2293       * Fires immediately before a specific network option is deleted.
2294       *
2295       * The dynamic portion of the hook name, `$option`, refers to the option name.
2296       *
2297       * @since 3.0.0
2298       * @since 4.4.0 The `$option` parameter was added.
2299       * @since 4.7.0 The `$network_id` parameter was added.
2300       *
2301       * @param string $option     Option name.
2302       * @param int    $network_id ID of the network.
2303       */
2304      do_action( "pre_delete_site_option_{$option}", $option, $network_id );
2305  
2306      if ( ! is_multisite() ) {
2307          $result = delete_option( $option );
2308      } else {
2309          $row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM {$wpdb->sitemeta} WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
2310          if ( is_null( $row ) || ! $row->meta_id ) {
2311              return false;
2312          }
2313          $cache_key = "$network_id:$option";
2314          wp_cache_delete( $cache_key, 'site-options' );
2315  
2316          $result = $wpdb->delete(
2317              $wpdb->sitemeta,
2318              array(
2319                  'meta_key' => $option,
2320                  'site_id'  => $network_id,
2321              )
2322          );
2323  
2324          if ( $result ) {
2325              $notoptions_key = "$network_id:notoptions";
2326              $notoptions     = wp_cache_get( $notoptions_key, 'site-options' );
2327  
2328              if ( ! is_array( $notoptions ) ) {
2329                  $notoptions = array();
2330              }
2331              $notoptions[ $option ] = true;
2332              wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
2333          }
2334      }
2335  
2336      if ( $result ) {
2337  
2338          /**
2339           * Fires after a specific network option has been deleted.
2340           *
2341           * The dynamic portion of the hook name, `$option`, refers to the option name.
2342           *
2343           * @since 2.9.0 As `delete_site_option_{$key}`.
2344           * @since 3.0.0
2345           * @since 4.7.0 The `$network_id` parameter was added.
2346           *
2347           * @param string $option     Name of the network option.
2348           * @param int    $network_id ID of the network.
2349           */
2350          do_action( "delete_site_option_{$option}", $option, $network_id );
2351  
2352          /**
2353           * Fires after a network option has been deleted.
2354           *
2355           * @since 3.0.0
2356           * @since 4.7.0 The `$network_id` parameter was added.
2357           *
2358           * @param string $option     Name of the network option.
2359           * @param int    $network_id ID of the network.
2360           */
2361          do_action( 'delete_site_option', $option, $network_id );
2362  
2363          return true;
2364      }
2365  
2366      return false;
2367  }
2368  
2369  /**
2370   * Updates the value of a network option that was already added.
2371   *
2372   * @since 4.4.0
2373   *
2374   * @see update_option()
2375   *
2376   * @global wpdb $wpdb WordPress database abstraction object.
2377   *
2378   * @param int|null $network_id ID of the network. Can be null to default to the current network ID.
2379   * @param string   $option     Name of the option. Expected to not be SQL-escaped.
2380   * @param mixed    $value      Option value. Expected to not be SQL-escaped.
2381   * @return bool True if the value was updated, false otherwise.
2382   */
2383  function update_network_option( $network_id, $option, $value ) {
2384      global $wpdb;
2385  
2386      if ( $network_id && ! is_numeric( $network_id ) ) {
2387          return false;
2388      }
2389  
2390      $network_id = (int) $network_id;
2391  
2392      // Fallback to the current network if a network ID is not specified.
2393      if ( ! $network_id ) {
2394          $network_id = get_current_network_id();
2395      }
2396  
2397      wp_protect_special_option( $option );
2398  
2399      $old_value = get_network_option( $network_id, $option );
2400  
2401      /**
2402       * Filters a specific network option before its value is updated.
2403       *
2404       * The dynamic portion of the hook name, `$option`, refers to the option name.
2405       *
2406       * @since 2.9.0 As 'pre_update_site_option_' . $key
2407       * @since 3.0.0
2408       * @since 4.4.0 The `$option` parameter was added.
2409       * @since 4.7.0 The `$network_id` parameter was added.
2410       *
2411       * @param mixed  $value      New value of the network option.
2412       * @param mixed  $old_value  Old value of the network option.
2413       * @param string $option     Option name.
2414       * @param int    $network_id ID of the network.
2415       */
2416      $value = apply_filters( "pre_update_site_option_{$option}", $value, $old_value, $option, $network_id );
2417  
2418      /*
2419       * If the new and old values are the same, no need to update.
2420       *
2421       * Unserialized values will be adequate in most cases. If the unserialized
2422       * data differs, the (maybe) serialized data is checked to avoid
2423       * unnecessary database calls for otherwise identical object instances.
2424       *
2425       * See https://core.trac.wordpress.org/ticket/44956
2426       */
2427      if ( $value === $old_value || maybe_serialize( $value ) === maybe_serialize( $old_value ) ) {
2428          return false;
2429      }
2430  
2431      if ( false === $old_value ) {
2432          return add_network_option( $network_id, $option, $value );
2433      }
2434  
2435      $notoptions_key = "$network_id:notoptions";
2436      $notoptions     = wp_cache_get( $notoptions_key, 'site-options' );
2437  
2438      if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
2439          unset( $notoptions[ $option ] );
2440          wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
2441      }
2442  
2443      if ( ! is_multisite() ) {
2444          $result = update_option( $option, $value, false );
2445      } else {
2446          $value = sanitize_option( $option, $value );
2447  
2448          $serialized_value = maybe_serialize( $value );
2449          $result           = $wpdb->update(
2450              $wpdb->sitemeta,
2451              array( 'meta_value' => $serialized_value ),
2452              array(
2453                  'site_id'  => $network_id,
2454                  'meta_key' => $option,
2455              )
2456          );
2457  
2458          if ( $result ) {
2459              $cache_key = "$network_id:$option";
2460              wp_cache_set( $cache_key, $value, 'site-options' );
2461          }
2462      }
2463  
2464      if ( $result ) {
2465  
2466          /**
2467           * Fires after the value of a specific network option has been successfully updated.
2468           *
2469           * The dynamic portion of the hook name, `$option`, refers to the option name.
2470           *
2471           * @since 2.9.0 As "update_site_option_{$key}"
2472           * @since 3.0.0
2473           * @since 4.7.0 The `$network_id` parameter was added.
2474           *
2475           * @param string $option     Name of the network option.
2476           * @param mixed  $value      Current value of the network option.
2477           * @param mixed  $old_value  Old value of the network option.
2478           * @param int    $network_id ID of the network.
2479           */
2480          do_action( "update_site_option_{$option}", $option, $value, $old_value, $network_id );
2481  
2482          /**
2483           * Fires after the value of a network option has been successfully updated.
2484           *
2485           * @since 3.0.0
2486           * @since 4.7.0 The `$network_id` parameter was added.
2487           *
2488           * @param string $option     Name of the network option.
2489           * @param mixed  $value      Current value of the network option.
2490           * @param mixed  $old_value  Old value of the network option.
2491           * @param int    $network_id ID of the network.
2492           */
2493          do_action( 'update_site_option', $option, $value, $old_value, $network_id );
2494  
2495          return true;
2496      }
2497  
2498      return false;
2499  }
2500  
2501  /**
2502   * Deletes a site transient.
2503   *
2504   * @since 2.9.0
2505   *
2506   * @param string $transient Transient name. Expected to not be SQL-escaped.
2507   * @return bool True if the transient was deleted, false otherwise.
2508   */
2509  function delete_site_transient( $transient ) {
2510  
2511      /**
2512       * Fires immediately before a specific site transient is deleted.
2513       *
2514       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
2515       *
2516       * @since 3.0.0
2517       *
2518       * @param string $transient Transient name.
2519       */
2520      do_action( "delete_site_transient_{$transient}", $transient );
2521  
2522      if ( wp_using_ext_object_cache() || wp_installing() ) {
2523          $result = wp_cache_delete( $transient, 'site-transient' );
2524      } else {
2525          $option_timeout = '_site_transient_timeout_' . $transient;
2526          $option         = '_site_transient_' . $transient;
2527          $result         = delete_site_option( $option );
2528  
2529          if ( $result ) {
2530              delete_site_option( $option_timeout );
2531          }
2532      }
2533  
2534      if ( $result ) {
2535  
2536          /**
2537           * Fires after a transient is deleted.
2538           *
2539           * @since 3.0.0
2540           *
2541           * @param string $transient Deleted transient name.
2542           */
2543          do_action( 'deleted_site_transient', $transient );
2544      }
2545  
2546      return $result;
2547  }
2548  
2549  /**
2550   * Retrieves the value of a site transient.
2551   *
2552   * If the transient does not exist, does not have a value, or has expired,
2553   * then the return value will be false.
2554   *
2555   * @since 2.9.0
2556   *
2557   * @see get_transient()
2558   *
2559   * @param string $transient Transient name. Expected to not be SQL-escaped.
2560   * @return mixed Value of transient.
2561   */
2562  function get_site_transient( $transient ) {
2563  
2564      /**
2565       * Filters the value of an existing site transient before it is retrieved.
2566       *
2567       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
2568       *
2569       * Returning a value other than boolean false will short-circuit retrieval and
2570       * return that value instead.
2571       *
2572       * @since 2.9.0
2573       * @since 4.4.0 The `$transient` parameter was added.
2574       *
2575       * @param mixed  $pre_site_transient The default value to return if the site transient does not exist.
2576       *                                   Any value other than false will short-circuit the retrieval
2577       *                                   of the transient, and return that value.
2578       * @param string $transient          Transient name.
2579       */
2580      $pre = apply_filters( "pre_site_transient_{$transient}", false, $transient );
2581  
2582      if ( false !== $pre ) {
2583          return $pre;
2584      }
2585  
2586      if ( wp_using_ext_object_cache() || wp_installing() ) {
2587          $value = wp_cache_get( $transient, 'site-transient' );
2588      } else {
2589          // Core transients that do not have a timeout. Listed here so querying timeouts can be avoided.
2590          $no_timeout       = array( 'update_core', 'update_plugins', 'update_themes' );
2591          $transient_option = '_site_transient_' . $transient;
2592          if ( ! in_array( $transient, $no_timeout, true ) ) {
2593              $transient_timeout = '_site_transient_timeout_' . $transient;
2594              wp_prime_site_option_caches( array( $transient_option, $transient_timeout ) );
2595  
2596              $timeout = get_site_option( $transient_timeout );
2597              if ( false !== $timeout && $timeout < time() ) {
2598                  delete_site_option( $transient_option );
2599                  delete_site_option( $transient_timeout );
2600                  $value = false;
2601              }
2602          }
2603  
2604          if ( ! isset( $value ) ) {
2605              $value = get_site_option( $transient_option );
2606          }
2607      }
2608  
2609      /**
2610       * Filters the value of an existing site transient.
2611       *
2612       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
2613       *
2614       * @since 2.9.0
2615       * @since 4.4.0 The `$transient` parameter was added.
2616       *
2617       * @param mixed  $value     Value of site transient.
2618       * @param string $transient Transient name.
2619       */
2620      return apply_filters( "site_transient_{$transient}", $value, $transient );
2621  }
2622  
2623  /**
2624   * Sets/updates the value of a site transient.
2625   *
2626   * You do not need to serialize values. If the value needs to be serialized,
2627   * then it will be serialized before it is set.
2628   *
2629   * @since 2.9.0
2630   *
2631   * @see set_transient()
2632   *
2633   * @param string $transient  Transient name. Expected to not be SQL-escaped. Must be
2634   *                           167 characters or fewer in length.
2635   * @param mixed  $value      Transient value. Expected to not be SQL-escaped.
2636   * @param int    $expiration Optional. Time until expiration in seconds. Default 0 (no expiration).
2637   * @return bool True if the value was set, false otherwise.
2638   */
2639  function set_site_transient( $transient, $value, $expiration = 0 ) {
2640  
2641      /**
2642       * Filters the value of a specific site transient before it is set.
2643       *
2644       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
2645       *
2646       * @since 3.0.0
2647       * @since 4.4.0 The `$transient` parameter was added.
2648       *
2649       * @param mixed  $value     New value of site transient.
2650       * @param string $transient Transient name.
2651       */
2652      $value = apply_filters( "pre_set_site_transient_{$transient}", $value, $transient );
2653  
2654      $expiration = (int) $expiration;
2655  
2656      /**
2657       * Filters the expiration for a site transient before its value is set.
2658       *
2659       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
2660       *
2661       * @since 4.4.0
2662       *
2663       * @param int    $expiration Time until expiration in seconds. Use 0 for no expiration.
2664       * @param mixed  $value      New value of site transient.
2665       * @param string $transient  Transient name.
2666       */
2667      $expiration = apply_filters( "expiration_of_site_transient_{$transient}", $expiration, $value, $transient );
2668  
2669      if ( wp_using_ext_object_cache() || wp_installing() ) {
2670          $result = wp_cache_set( $transient, $value, 'site-transient', $expiration );
2671      } else {
2672          $transient_timeout = '_site_transient_timeout_' . $transient;
2673          $option            = '_site_transient_' . $transient;
2674          wp_prime_site_option_caches( array( $option, $transient_timeout ) );
2675  
2676          if ( false === get_site_option( $option ) ) {
2677              if ( $expiration ) {
2678                  add_site_option( $transient_timeout, time() + $expiration );
2679              }
2680              $result = add_site_option( $option, $value );
2681          } else {
2682              if ( $expiration ) {
2683                  update_site_option( $transient_timeout, time() + $expiration );
2684              }
2685              $result = update_site_option( $option, $value );
2686          }
2687      }
2688  
2689      if ( $result ) {
2690  
2691          /**
2692           * Fires after the value for a specific site transient has been set.
2693           *
2694           * The dynamic portion of the hook name, `$transient`, refers to the transient name.
2695           *
2696           * @since 3.0.0
2697           * @since 4.4.0 The `$transient` parameter was added
2698           *
2699           * @param mixed  $value      Site transient value.
2700           * @param int    $expiration Time until expiration in seconds.
2701           * @param string $transient  Transient name.
2702           */
2703          do_action( "set_site_transient_{$transient}", $value, $expiration, $transient );
2704  
2705          /**
2706           * Fires after the value for a site transient has been set.
2707           *
2708           * @since 6.8.0
2709           *
2710           * @param string $transient  The name of the site transient.
2711           * @param mixed  $value      Site transient value.
2712           * @param int    $expiration Time until expiration in seconds.
2713           */
2714          do_action( 'set_site_transient', $transient, $value, $expiration );
2715  
2716          /**
2717           * Fires after the value for a site transient has been set.
2718           *
2719           * @since 3.0.0
2720           * @deprecated 6.8.0 Use {@see 'set_site_transient'} instead.
2721           *
2722           * @param string $transient  The name of the site transient.
2723           * @param mixed  $value      Site transient value.
2724           * @param int    $expiration Time until expiration in seconds.
2725           */
2726          do_action_deprecated( 'setted_site_transient', array( $transient, $value, $expiration ), '6.8.0', 'set_site_transient' );
2727      }
2728  
2729      return $result;
2730  }
2731  
2732  /**
2733   * Registers default settings available in WordPress.
2734   *
2735   * The settings registered here are primarily useful for the REST API, so this
2736   * does not encompass all settings available in WordPress.
2737   *
2738   * @since 4.7.0
2739   * @since 6.0.1 The `show_on_front`, `page_on_front`, and `page_for_posts` options were added.
2740   */
2741  function register_initial_settings() {
2742      register_setting(
2743          'general',
2744          'blogname',
2745          array(
2746              'show_in_rest' => array(
2747                  'name' => 'title',
2748              ),
2749              'type'         => 'string',
2750              'label'        => __( 'Title' ),
2751              'description'  => __( 'Site title.' ),
2752          )
2753      );
2754  
2755      register_setting(
2756          'general',
2757          'blogdescription',
2758          array(
2759              'show_in_rest' => array(
2760                  'name' => 'description',
2761              ),
2762              'type'         => 'string',
2763              'label'        => __( 'Tagline' ),
2764              'description'  => __( 'Site tagline.' ),
2765          )
2766      );
2767  
2768      if ( ! is_multisite() ) {
2769          register_setting(
2770              'general',
2771              'siteurl',
2772              array(
2773                  'show_in_rest' => array(
2774                      'name'   => 'url',
2775                      'schema' => array(
2776                          'format' => 'uri',
2777                      ),
2778                  ),
2779                  'type'         => 'string',
2780                  'description'  => __( 'Site URL.' ),
2781              )
2782          );
2783      }
2784  
2785      if ( ! is_multisite() ) {
2786          register_setting(
2787              'general',
2788              'admin_email',
2789              array(
2790                  'show_in_rest' => array(
2791                      'name'   => 'email',
2792                      'schema' => array(
2793                          'format' => 'email',
2794                      ),
2795                  ),
2796                  'type'         => 'string',
2797                  'description'  => __( 'This address is used for admin purposes, like new user notification.' ),
2798              )
2799          );
2800      }
2801  
2802      register_setting(
2803          'general',
2804          'timezone_string',
2805          array(
2806              'show_in_rest' => array(
2807                  'name' => 'timezone',
2808              ),
2809              'type'         => 'string',
2810              'description'  => __( 'A city in the same timezone as you.' ),
2811          )
2812      );
2813  
2814      register_setting(
2815          'general',
2816          'date_format',
2817          array(
2818              'show_in_rest' => true,
2819              'type'         => 'string',
2820              'description'  => __( 'A date format for all date strings.' ),
2821          )
2822      );
2823  
2824      register_setting(
2825          'general',
2826          'time_format',
2827          array(
2828              'show_in_rest' => true,
2829              'type'         => 'string',
2830              'description'  => __( 'A time format for all time strings.' ),
2831          )
2832      );
2833  
2834      register_setting(
2835          'general',
2836          'start_of_week',
2837          array(
2838              'show_in_rest' => true,
2839              'type'         => 'integer',
2840              'description'  => __( 'A day number of the week that the week should start on.' ),
2841          )
2842      );
2843  
2844      register_setting(
2845          'general',
2846          'WPLANG',
2847          array(
2848              'show_in_rest' => array(
2849                  'name' => 'language',
2850              ),
2851              'type'         => 'string',
2852              'description'  => __( 'WordPress locale code.' ),
2853              'default'      => 'en_US',
2854          )
2855      );
2856  
2857      register_setting(
2858          'writing',
2859          'use_smilies',
2860          array(
2861              'show_in_rest' => true,
2862              'type'         => 'boolean',
2863              'description'  => __( 'Convert emoticons like :-) and :-P to graphics on display.' ),
2864              'default'      => true,
2865          )
2866      );
2867  
2868      register_setting(
2869          'writing',
2870          'default_category',
2871          array(
2872              'show_in_rest' => true,
2873              'type'         => 'integer',
2874              'description'  => __( 'Default post category.' ),
2875          )
2876      );
2877  
2878      register_setting(
2879          'writing',
2880          'default_post_format',
2881          array(
2882              'show_in_rest' => true,
2883              'type'         => 'string',
2884              'description'  => __( 'Default post format.' ),
2885          )
2886      );
2887  
2888      register_setting(
2889          'reading',
2890          'posts_per_page',
2891          array(
2892              'show_in_rest' => true,
2893              'type'         => 'integer',
2894              'label'        => __( 'Maximum posts per page' ),
2895              'description'  => __( 'Blog pages show at most.' ),
2896              'default'      => 10,
2897          )
2898      );
2899  
2900      register_setting(
2901          'reading',
2902          'show_on_front',
2903          array(
2904              'show_in_rest' => true,
2905              'type'         => 'string',
2906              'label'        => __( 'Show on front' ),
2907              'description'  => __( 'What to show on the front page' ),
2908          )
2909      );
2910  
2911      register_setting(
2912          'reading',
2913          'page_on_front',
2914          array(
2915              'show_in_rest' => true,
2916              'type'         => 'integer',
2917              'label'        => __( 'Page on front' ),
2918              'description'  => __( 'The ID of the page that should be displayed on the front page' ),
2919          )
2920      );
2921  
2922      register_setting(
2923          'reading',
2924          'page_for_posts',
2925          array(
2926              'show_in_rest' => true,
2927              'type'         => 'integer',
2928              'description'  => __( 'The ID of the page that should display the latest posts' ),
2929          )
2930      );
2931  
2932      register_setting(
2933          'discussion',
2934          'default_ping_status',
2935          array(
2936              'show_in_rest' => array(
2937                  'schema' => array(
2938                      'enum' => array( 'open', 'closed' ),
2939                  ),
2940              ),
2941              'type'         => 'string',
2942              'description'  => __( 'Allow link notifications from other blogs (pingbacks and trackbacks) on new articles.' ),
2943          )
2944      );
2945  
2946      register_setting(
2947          'discussion',
2948          'default_comment_status',
2949          array(
2950              'show_in_rest' => array(
2951                  'schema' => array(
2952                      'enum' => array( 'open', 'closed' ),
2953                  ),
2954              ),
2955              'type'         => 'string',
2956              'label'        => __( 'Allow comments on new posts' ),
2957              'description'  => __( 'Allow people to submit comments on new posts.' ),
2958          )
2959      );
2960  }
2961  
2962  /**
2963   * Registers a setting and its data.
2964   *
2965   * @since 2.7.0
2966   * @since 3.0.0 The `misc` option group was deprecated.
2967   * @since 3.5.0 The `privacy` option group was deprecated.
2968   * @since 4.7.0 `$args` can be passed to set flags on the setting, similar to `register_meta()`.
2969   * @since 5.5.0 `$new_whitelist_options` was renamed to `$new_allowed_options`.
2970   *              Please consider writing more inclusive code.
2971   * @since 6.6.0 Added the `label` argument.
2972   *
2973   * @global array $new_allowed_options
2974   * @global array $wp_registered_settings
2975   *
2976   * @param string $option_group A settings group name. Should correspond to an allowed option key name.
2977   *                             Default allowed option key names include 'general', 'discussion', 'media',
2978   *                             'reading', 'writing', and 'options'.
2979   * @param string $option_name The name of an option to sanitize and save.
2980   * @param array  $args {
2981   *     Data used to describe the setting when registered.
2982   *
2983   *     @type string     $type              The type of data associated with this setting.
2984   *                                         Valid values are 'string', 'boolean', 'integer', 'number', 'array', and 'object'.
2985   *     @type string     $label             A label of the data attached to this setting.
2986   *     @type string     $description       A description of the data attached to this setting.
2987   *     @type callable   $sanitize_callback A callback function that sanitizes the option's value.
2988   *     @type bool|array $show_in_rest      Whether data associated with this setting should be included in the REST API.
2989   *                                         When registering complex settings, this argument may optionally be an
2990   *                                         array with a 'schema' key.
2991   *     @type mixed      $default           Default value when calling `get_option()`.
2992   * }
2993   */
2994  function register_setting( $option_group, $option_name, $args = array() ) {
2995      global $new_allowed_options, $wp_registered_settings;
2996  
2997      /*
2998       * In 5.5.0, the `$new_whitelist_options` global variable was renamed to `$new_allowed_options`.
2999       * Please consider writing more inclusive code.
3000       */
3001      $GLOBALS['new_whitelist_options'] = &$new_allowed_options;
3002  
3003      $defaults = array(
3004          'type'              => 'string',
3005          'group'             => $option_group,
3006          'label'             => '',
3007          'description'       => '',
3008          'sanitize_callback' => null,
3009          'show_in_rest'      => false,
3010      );
3011  
3012      // Back-compat: old sanitize callback is added.
3013      if ( is_callable( $args ) ) {
3014          $args = array(
3015              'sanitize_callback' => $args,
3016          );
3017      }
3018  
3019      /**
3020       * Filters the registration arguments when registering a setting.
3021       *
3022       * @since 4.7.0
3023       *
3024       * @param array  $args         Array of setting registration arguments.
3025       * @param array  $defaults     Array of default arguments.
3026       * @param string $option_group Setting group.
3027       * @param string $option_name  Setting name.
3028       */
3029      $args = apply_filters( 'register_setting_args', $args, $defaults, $option_group, $option_name );
3030  
3031      $args = wp_parse_args( $args, $defaults );
3032  
3033      // Require an item schema when registering settings with an array type.
3034      if ( false !== $args['show_in_rest'] && 'array' === $args['type'] && ( ! is_array( $args['show_in_rest'] ) || ! isset( $args['show_in_rest']['schema']['items'] ) ) ) {
3035          _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' );
3036      }
3037  
3038      if ( ! is_array( $wp_registered_settings ) ) {
3039          $wp_registered_settings = array();
3040      }
3041  
3042      if ( 'misc' === $option_group ) {
3043          _deprecated_argument(
3044              __FUNCTION__,
3045              '3.0.0',
3046              sprintf(
3047                  /* translators: %s: misc */
3048                  __( 'The "%s" options group has been removed. Use another settings group.' ),
3049                  'misc'
3050              )
3051          );
3052          $option_group = 'general';
3053      }
3054  
3055      if ( 'privacy' === $option_group ) {
3056          _deprecated_argument(
3057              __FUNCTION__,
3058              '3.5.0',
3059              sprintf(
3060                  /* translators: %s: privacy */
3061                  __( 'The "%s" options group has been removed. Use another settings group.' ),
3062                  'privacy'
3063              )
3064          );
3065          $option_group = 'reading';
3066      }
3067  
3068      $new_allowed_options[ $option_group ][] = $option_name;
3069  
3070      if ( ! empty( $args['sanitize_callback'] ) ) {
3071          add_filter( "sanitize_option_{$option_name}", $args['sanitize_callback'] );
3072      }
3073      if ( array_key_exists( 'default', $args ) ) {
3074          add_filter( "default_option_{$option_name}", 'filter_default_option', 10, 3 );
3075      }
3076  
3077      /**
3078       * Fires immediately before the setting is registered but after its filters are in place.
3079       *
3080       * @since 5.5.0
3081       *
3082       * @param string $option_group Setting group.
3083       * @param string $option_name  Setting name.
3084       * @param array  $args         Array of setting registration arguments.
3085       */
3086      do_action( 'register_setting', $option_group, $option_name, $args );
3087  
3088      $wp_registered_settings[ $option_name ] = $args;
3089  }
3090  
3091  /**
3092   * Unregisters a setting.
3093   *
3094   * @since 2.7.0
3095   * @since 4.7.0 `$sanitize_callback` was deprecated. The callback from `register_setting()` is now used instead.
3096   * @since 5.5.0 `$new_whitelist_options` was renamed to `$new_allowed_options`.
3097   *              Please consider writing more inclusive code.
3098   *
3099   * @global array $new_allowed_options
3100   * @global array $wp_registered_settings
3101   *
3102   * @param string   $option_group The settings group name used during registration.
3103   * @param string   $option_name  The name of the option to unregister.
3104   * @param callable $deprecated   Optional. Deprecated.
3105   */
3106  function unregister_setting( $option_group, $option_name, $deprecated = '' ) {
3107      global $new_allowed_options, $wp_registered_settings;
3108  
3109      /*
3110       * In 5.5.0, the `$new_whitelist_options` global variable was renamed to `$new_allowed_options`.
3111       * Please consider writing more inclusive code.
3112       */
3113      $GLOBALS['new_whitelist_options'] = &$new_allowed_options;
3114  
3115      if ( 'misc' === $option_group ) {
3116          _deprecated_argument(
3117              __FUNCTION__,
3118              '3.0.0',
3119              sprintf(
3120                  /* translators: %s: misc */
3121                  __( 'The "%s" options group has been removed. Use another settings group.' ),
3122                  'misc'
3123              )
3124          );
3125          $option_group = 'general';
3126      }
3127  
3128      if ( 'privacy' === $option_group ) {
3129          _deprecated_argument(
3130              __FUNCTION__,
3131              '3.5.0',
3132              sprintf(
3133                  /* translators: %s: privacy */
3134                  __( 'The "%s" options group has been removed. Use another settings group.' ),
3135                  'privacy'
3136              )
3137          );
3138          $option_group = 'reading';
3139      }
3140  
3141      $pos = false;
3142      if ( isset( $new_allowed_options[ $option_group ] ) ) {
3143          $pos = array_search( $option_name, (array) $new_allowed_options[ $option_group ], true );
3144      }
3145  
3146      if ( false !== $pos ) {
3147          unset( $new_allowed_options[ $option_group ][ $pos ] );
3148      }
3149  
3150      if ( '' !== $deprecated ) {
3151          _deprecated_argument(
3152              __FUNCTION__,
3153              '4.7.0',
3154              sprintf(
3155                  /* translators: 1: $sanitize_callback, 2: register_setting() */
3156                  __( '%1$s is deprecated. The callback from %2$s is used instead.' ),
3157                  '<code>$sanitize_callback</code>',
3158                  '<code>register_setting()</code>'
3159              )
3160          );
3161          remove_filter( "sanitize_option_{$option_name}", $deprecated );
3162      }
3163  
3164      if ( isset( $wp_registered_settings[ $option_name ] ) ) {
3165          // Remove the sanitize callback if one was set during registration.
3166          if ( ! empty( $wp_registered_settings[ $option_name ]['sanitize_callback'] ) ) {
3167              remove_filter( "sanitize_option_{$option_name}", $wp_registered_settings[ $option_name ]['sanitize_callback'] );
3168          }
3169  
3170          // Remove the default filter if a default was provided during registration.
3171          if ( array_key_exists( 'default', $wp_registered_settings[ $option_name ] ) ) {
3172              remove_filter( "default_option_{$option_name}", 'filter_default_option', 10 );
3173          }
3174  
3175          /**
3176           * Fires immediately before the setting is unregistered and after its filters have been removed.
3177           *
3178           * @since 5.5.0
3179           *
3180           * @param string $option_group Setting group.
3181           * @param string $option_name  Setting name.
3182           */
3183          do_action( 'unregister_setting', $option_group, $option_name );
3184  
3185          unset( $wp_registered_settings[ $option_name ] );
3186      }
3187  }
3188  
3189  /**
3190   * Retrieves an array of registered settings.
3191   *
3192   * @since 4.7.0
3193   *
3194   * @global array $wp_registered_settings
3195   *
3196   * @return array {
3197   *     List of registered settings, keyed by option name.
3198   *
3199   *     @type array ...$0 {
3200   *         Data used to describe the setting when registered.
3201   *
3202   *         @type string     $type              The type of data associated with this setting.
3203   *                                             Valid values are 'string', 'boolean', 'integer', 'number', 'array', and 'object'.
3204   *         @type string     $label             A label of the data attached to this setting.
3205   *         @type string     $description       A description of the data attached to this setting.
3206   *         @type callable   $sanitize_callback A callback function that sanitizes the option's value.
3207   *         @type bool|array $show_in_rest      Whether data associated with this setting should be included in the REST API.
3208   *                                             When registering complex settings, this argument may optionally be an
3209   *                                             array with a 'schema' key.
3210   *         @type mixed      $default           Default value when calling `get_option()`.
3211   *     }
3212   * }
3213   */
3214  function get_registered_settings() {
3215      global $wp_registered_settings;
3216  
3217      if ( ! is_array( $wp_registered_settings ) ) {
3218          return array();
3219      }
3220  
3221      return $wp_registered_settings;
3222  }
3223  
3224  /**
3225   * Filters the default value for the option.
3226   *
3227   * For settings which register a default setting in `register_setting()`, this
3228   * function is added as a filter to `default_option_{$option}`.
3229   *
3230   * @since 4.7.0
3231   *
3232   * @param mixed  $default_value  Existing default value to return.
3233   * @param string $option         Option name.
3234   * @param bool   $passed_default Was `get_option()` passed a default value?
3235   * @return mixed Filtered default value.
3236   */
3237  function filter_default_option( $default_value, $option, $passed_default ) {
3238      if ( $passed_default ) {
3239          return $default_value;
3240      }
3241  
3242      $registered = get_registered_settings();
3243      if ( empty( $registered[ $option ] ) ) {
3244          return $default_value;
3245      }
3246  
3247      return $registered[ $option ]['default'];
3248  }
3249  
3250  /**
3251   * Returns the values that trigger autoloading from the options table.
3252   *
3253   * @since 6.6.0
3254   *
3255   * @return string[] The values that trigger autoloading.
3256   */
3257  function wp_autoload_values_to_autoload() {
3258      $autoload_values = array( 'yes', 'on', 'auto-on', 'auto' );
3259  
3260      /**
3261       * Filters the autoload values that should be considered for autoloading from the options table.
3262       *
3263       * The filter can only be used to remove autoload values from the default list.
3264       *
3265       * @since 6.6.0
3266       *
3267       * @param string[] $autoload_values Autoload values used to autoload option.
3268       *                               Default list contains 'yes', 'on', 'auto-on', and 'auto'.
3269       */
3270      $filtered_values = apply_filters( 'wp_autoload_values_to_autoload', $autoload_values );
3271  
3272      return array_intersect( $filtered_values, $autoload_values );
3273  }


Generated : Wed Feb 11 08:20:09 2026 Cross-referenced by PHPXref