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


Generated : Mon Jul 15 08:20:02 2024 Cross-referenced by PHPXref