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


Generated : Thu Jan 30 08:20:01 2025 Cross-referenced by PHPXref