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


Generated : Thu Oct 24 08:20:01 2024 Cross-referenced by PHPXref