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


Generated : Tue Jul 14 08:20:16 2026 Cross-referenced by PHPXref