[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

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

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


Generated : Wed Apr 24 08:20:01 2024 Cross-referenced by PHPXref