[ Index ]

PHP Cross Reference of WordPress

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 or does not have a value, then the return value
  13   * will be false. This is useful to check whether you need to install an option
  14   * and is commonly used during installation of plugin options and to test
  15   * whether upgrading is required.
  16   *
  17   * If the option was serialized then it will be unserialized when it is returned.
  18   *
  19   * Any scalar values will be returned as strings. You may coerce the return type of
  20   * a given option by registering an {@see 'option_$option'} filter callback.
  21   *
  22   * @since 1.5.0
  23   *
  24   * @global wpdb $wpdb WordPress database abstraction object.
  25   *
  26   * @param string $option  Name of the option to retrieve. Expected to not be SQL-escaped.
  27   * @param mixed  $default Optional. Default value to return if the option does not exist.
  28   * @return mixed Value set for the option.
  29   */
  30  function get_option( $option, $default = false ) {
  31      global $wpdb;
  32  
  33      $option = trim( $option );
  34      if ( empty( $option ) ) {
  35          return false;
  36      }
  37  
  38      /*
  39       * Until a proper _deprecated_option() function can be introduced,
  40       * redirect requests to deprecated keys to the new, correct ones.
  41       */
  42      $deprecated_keys = array(
  43          'blacklist_keys'    => 'disallowed_keys',
  44          'comment_whitelist' => 'comment_previously_approved',
  45      );
  46  
  47      if ( ! wp_installing() && isset( $deprecated_keys[ $option ] ) ) {
  48          _deprecated_argument(
  49              __FUNCTION__,
  50              '5.5.0',
  51              sprintf(
  52                  /* translators: 1: Deprecated option key, 2: New option key. */
  53                  __( 'The "%1$s" option key has been renamed to "%2$s".' ),
  54                  $option,
  55                  $deprecated_keys[ $option ]
  56              )
  57          );
  58          return get_option( $deprecated_keys[ $option ], $default );
  59      }
  60  
  61      /**
  62       * Filters the value of an existing option before it is retrieved.
  63       *
  64       * The dynamic portion of the hook name, `$option`, refers to the option name.
  65       *
  66       * Returning a truthy value from the filter will effectively short-circuit retrieval
  67       * and return the passed value instead.
  68       *
  69       * @since 1.5.0
  70       * @since 4.4.0 The `$option` parameter was added.
  71       * @since 4.9.0 The `$default` parameter was added.
  72       *
  73       * @param mixed  $pre_option The value to return instead of the option value. This differs
  74       *                           from `$default`, which is used as the fallback value in the event
  75       *                           the option doesn't exist elsewhere in get_option().
  76       *                           Default false (to skip past the short-circuit).
  77       * @param string $option     Option name.
  78       * @param mixed  $default    The fallback value to return if the option does not exist.
  79       *                           Default false.
  80       */
  81      $pre = apply_filters( "pre_option_{$option}", false, $option, $default );
  82  
  83      if ( false !== $pre ) {
  84          return $pre;
  85      }
  86  
  87      if ( defined( 'WP_SETUP_CONFIG' ) ) {
  88          return false;
  89      }
  90  
  91      // Distinguish between `false` as a default, and not passing one.
  92      $passed_default = func_num_args() > 1;
  93  
  94      if ( ! wp_installing() ) {
  95          // Prevent non-existent options from triggering multiple queries.
  96          $notoptions = wp_cache_get( 'notoptions', 'options' );
  97  
  98          if ( isset( $notoptions[ $option ] ) ) {
  99              /**
 100               * Filters the default value for an option.
 101               *
 102               * The dynamic portion of the hook name, `$option`, refers to the option name.
 103               *
 104               * @since 3.4.0
 105               * @since 4.4.0 The `$option` parameter was added.
 106               * @since 4.7.0 The `$passed_default` parameter was added to distinguish between a `false` value and the default parameter value.
 107               *
 108               * @param mixed  $default The default value to return if the option does not exist
 109               *                        in the database.
 110               * @param string $option  Option name.
 111               * @param bool   $passed_default Was `get_option()` passed a default value?
 112               */
 113              return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
 114          }
 115  
 116          $alloptions = wp_load_alloptions();
 117  
 118          if ( isset( $alloptions[ $option ] ) ) {
 119              $value = $alloptions[ $option ];
 120          } else {
 121              $value = wp_cache_get( $option, 'options' );
 122  
 123              if ( false === $value ) {
 124                  $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
 125  
 126                  // Has to be get_row() instead of get_var() because of funkiness with 0, false, null values.
 127                  if ( is_object( $row ) ) {
 128                      $value = $row->option_value;
 129                      wp_cache_add( $option, $value, 'options' );
 130                  } else { // Option does not exist, so we must cache its non-existence.
 131                      if ( ! is_array( $notoptions ) ) {
 132                          $notoptions = array();
 133                      }
 134  
 135                      $notoptions[ $option ] = true;
 136                      wp_cache_set( 'notoptions', $notoptions, 'options' );
 137  
 138                      /** This filter is documented in wp-includes/option.php */
 139                      return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
 140                  }
 141              }
 142          }
 143      } else {
 144          $suppress = $wpdb->suppress_errors();
 145          $row      = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
 146          $wpdb->suppress_errors( $suppress );
 147  
 148          if ( is_object( $row ) ) {
 149              $value = $row->option_value;
 150          } else {
 151              /** This filter is documented in wp-includes/option.php */
 152              return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
 153          }
 154      }
 155  
 156      // If home is not set, use siteurl.
 157      if ( 'home' === $option && '' === $value ) {
 158          return get_option( 'siteurl' );
 159      }
 160  
 161      if ( in_array( $option, array( 'siteurl', 'home', 'category_base', 'tag_base' ), true ) ) {
 162          $value = untrailingslashit( $value );
 163      }
 164  
 165      /**
 166       * Filters the value of an existing option.
 167       *
 168       * The dynamic portion of the hook name, `$option`, refers to the option name.
 169       *
 170       * @since 1.5.0 As 'option_' . $setting
 171       * @since 3.0.0
 172       * @since 4.4.0 The `$option` parameter was added.
 173       *
 174       * @param mixed  $value  Value of the option. If stored serialized, it will be
 175       *                       unserialized prior to being returned.
 176       * @param string $option Option name.
 177       */
 178      return apply_filters( "option_{$option}", maybe_unserialize( $value ), $option );
 179  }
 180  
 181  /**
 182   * Protects WordPress special option from being modified.
 183   *
 184   * Will die if $option is in protected list. Protected options are 'alloptions'
 185   * and 'notoptions' options.
 186   *
 187   * @since 2.2.0
 188   *
 189   * @param string $option Option name.
 190   */
 191  function wp_protect_special_option( $option ) {
 192      if ( 'alloptions' === $option || 'notoptions' === $option ) {
 193          wp_die(
 194              sprintf(
 195                  /* translators: %s: Option name. */
 196                  __( '%s is a protected WP option and may not be modified' ),
 197                  esc_html( $option )
 198              )
 199          );
 200      }
 201  }
 202  
 203  /**
 204   * Prints option value after sanitizing for forms.
 205   *
 206   * @since 1.5.0
 207   *
 208   * @param string $option Option name.
 209   */
 210  function form_option( $option ) {
 211      echo esc_attr( get_option( $option ) );
 212  }
 213  
 214  /**
 215   * Loads and caches all autoloaded options, if available or all options.
 216   *
 217   * @since 2.2.0
 218   * @since 5.3.1 The `$force_cache` parameter was added.
 219   *
 220   * @global wpdb $wpdb WordPress database abstraction object.
 221   *
 222   * @param bool $force_cache Optional. Whether to force an update of the local cache
 223   *                          from the persistent cache. Default false.
 224   * @return array List of all options.
 225   */
 226  function wp_load_alloptions( $force_cache = false ) {
 227      global $wpdb;
 228  
 229      if ( ! wp_installing() || ! is_multisite() ) {
 230          $alloptions = wp_cache_get( 'alloptions', 'options', $force_cache );
 231      } else {
 232          $alloptions = false;
 233      }
 234  
 235      if ( ! $alloptions ) {
 236          $suppress      = $wpdb->suppress_errors();
 237          $alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE autoload = 'yes'" );
 238          if ( ! $alloptions_db ) {
 239              $alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" );
 240          }
 241          $wpdb->suppress_errors( $suppress );
 242  
 243          $alloptions = array();
 244          foreach ( (array) $alloptions_db as $o ) {
 245              $alloptions[ $o->option_name ] = $o->option_value;
 246          }
 247  
 248          if ( ! wp_installing() || ! is_multisite() ) {
 249              /**
 250               * Filters all options before caching them.
 251               *
 252               * @since 4.9.0
 253               *
 254               * @param array $alloptions Array with all options.
 255               */
 256              $alloptions = apply_filters( 'pre_cache_alloptions', $alloptions );
 257  
 258              wp_cache_add( 'alloptions', $alloptions, 'options' );
 259          }
 260      }
 261  
 262      /**
 263       * Filters all options after retrieving them.
 264       *
 265       * @since 4.9.0
 266       *
 267       * @param array $alloptions Array with all options.
 268       */
 269      return apply_filters( 'alloptions', $alloptions );
 270  }
 271  
 272  /**
 273   * Loads and caches certain often requested site options if is_multisite() and a persistent cache is not being used.
 274   *
 275   * @since 3.0.0
 276   *
 277   * @global wpdb $wpdb WordPress database abstraction object.
 278   *
 279   * @param int $network_id Optional site ID for which to query the options. Defaults to the current site.
 280   */
 281  function wp_load_core_site_options( $network_id = null ) {
 282      global $wpdb;
 283  
 284      if ( ! is_multisite() || wp_using_ext_object_cache() || wp_installing() ) {
 285          return;
 286      }
 287  
 288      if ( empty( $network_id ) ) {
 289          $network_id = get_current_network_id();
 290      }
 291  
 292      $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' );
 293  
 294      $core_options_in = "'" . implode( "', '", $core_options ) . "'";
 295      $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 ) );
 296  
 297      foreach ( $options as $option ) {
 298          $key                = $option->meta_key;
 299          $cache_key          = "{$network_id}:$key";
 300          $option->meta_value = maybe_unserialize( $option->meta_value );
 301  
 302          wp_cache_set( $cache_key, $option->meta_value, 'site-options' );
 303      }
 304  }
 305  
 306  /**
 307   * Updates the value of an option that was already added.
 308   *
 309   * You do not need to serialize values. If the value needs to be serialized,
 310   * then it will be serialized before it is inserted into the database.
 311   * Remember, resources cannot be serialized or added as an option.
 312   *
 313   * If the option does not exist, it will be created.
 314  
 315   * This function is designed to work with or without a logged-in user. In terms of security,
 316   * plugin developers should check the current user's capabilities before updating any options.
 317   *
 318   * @since 1.0.0
 319   * @since 4.2.0 The `$autoload` parameter was added.
 320   *
 321   * @global wpdb $wpdb WordPress database abstraction object.
 322   *
 323   * @param string      $option   Name of the option to update. Expected to not be SQL-escaped.
 324   * @param mixed       $value    Option value. Must be serializable if non-scalar. Expected to not be SQL-escaped.
 325   * @param string|bool $autoload Optional. Whether to load the option when WordPress starts up. For existing options,
 326   *                              `$autoload` can only be updated using `update_option()` if `$value` is also changed.
 327   *                              Accepts 'yes'|true to enable or 'no'|false to disable. For non-existent options,
 328   *                              the default value is 'yes'. Default null.
 329   * @return bool True if the value was updated, false otherwise.
 330   */
 331  function update_option( $option, $value, $autoload = null ) {
 332      global $wpdb;
 333  
 334      $option = trim( $option );
 335      if ( empty( $option ) ) {
 336          return false;
 337      }
 338  
 339      /*
 340       * Until a proper _deprecated_option() function can be introduced,
 341       * redirect requests to deprecated keys to the new, correct ones.
 342       */
 343      $deprecated_keys = array(
 344          'blacklist_keys'    => 'disallowed_keys',
 345          'comment_whitelist' => 'comment_previously_approved',
 346      );
 347  
 348      if ( ! wp_installing() && isset( $deprecated_keys[ $option ] ) ) {
 349          _deprecated_argument(
 350              __FUNCTION__,
 351              '5.5.0',
 352              sprintf(
 353                  /* translators: 1: Deprecated option key, 2: New option key. */
 354                  __( 'The "%1$s" option key has been renamed to "%2$s".' ),
 355                  $option,
 356                  $deprecated_keys[ $option ]
 357              )
 358          );
 359          return update_option( $deprecated_keys[ $option ], $value, $autoload );
 360      }
 361  
 362      wp_protect_special_option( $option );
 363  
 364      if ( is_object( $value ) ) {
 365          $value = clone $value;
 366      }
 367  
 368      $value     = sanitize_option( $option, $value );
 369      $old_value = get_option( $option );
 370  
 371      /**
 372       * Filters a specific option before its value is (maybe) serialized and updated.
 373       *
 374       * The dynamic portion of the hook name, `$option`, refers to the option name.
 375       *
 376       * @since 2.6.0
 377       * @since 4.4.0 The `$option` parameter was added.
 378       *
 379       * @param mixed  $value     The new, unserialized option value.
 380       * @param mixed  $old_value The old option value.
 381       * @param string $option    Option name.
 382       */
 383      $value = apply_filters( "pre_update_option_{$option}", $value, $old_value, $option );
 384  
 385      /**
 386       * Filters an option before its value is (maybe) serialized and updated.
 387       *
 388       * @since 3.9.0
 389       *
 390       * @param mixed  $value     The new, unserialized option value.
 391       * @param string $option    Name of the option.
 392       * @param mixed  $old_value The old option value.
 393       */
 394      $value = apply_filters( 'pre_update_option', $value, $option, $old_value );
 395  
 396      /*
 397       * If the new and old values are the same, no need to update.
 398       *
 399       * Unserialized values will be adequate in most cases. If the unserialized
 400       * data differs, the (maybe) serialized data is checked to avoid
 401       * unnecessary database calls for otherwise identical object instances.
 402       *
 403       * See https://core.trac.wordpress.org/ticket/38903
 404       */
 405      if ( $value === $old_value || maybe_serialize( $value ) === maybe_serialize( $old_value ) ) {
 406          return false;
 407      }
 408  
 409      /** This filter is documented in wp-includes/option.php */
 410      if ( apply_filters( "default_option_{$option}", false, $option, false ) === $old_value ) {
 411          // Default setting for new options is 'yes'.
 412          if ( null === $autoload ) {
 413              $autoload = 'yes';
 414          }
 415  
 416          return add_option( $option, $value, '', $autoload );
 417      }
 418  
 419      $serialized_value = maybe_serialize( $value );
 420  
 421      /**
 422       * Fires immediately before an option value is updated.
 423       *
 424       * @since 2.9.0
 425       *
 426       * @param string $option    Name of the option to update.
 427       * @param mixed  $old_value The old option value.
 428       * @param mixed  $value     The new option value.
 429       */
 430      do_action( 'update_option', $option, $old_value, $value );
 431  
 432      $update_args = array(
 433          'option_value' => $serialized_value,
 434      );
 435  
 436      if ( null !== $autoload ) {
 437          $update_args['autoload'] = ( 'no' === $autoload || false === $autoload ) ? 'no' : 'yes';
 438      }
 439  
 440      $result = $wpdb->update( $wpdb->options, $update_args, array( 'option_name' => $option ) );
 441      if ( ! $result ) {
 442          return false;
 443      }
 444  
 445      $notoptions = wp_cache_get( 'notoptions', 'options' );
 446  
 447      if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
 448          unset( $notoptions[ $option ] );
 449          wp_cache_set( 'notoptions', $notoptions, 'options' );
 450      }
 451  
 452      if ( ! wp_installing() ) {
 453          $alloptions = wp_load_alloptions( true );
 454          if ( isset( $alloptions[ $option ] ) ) {
 455              $alloptions[ $option ] = $serialized_value;
 456              wp_cache_set( 'alloptions', $alloptions, 'options' );
 457          } else {
 458              wp_cache_set( $option, $serialized_value, 'options' );
 459          }
 460      }
 461  
 462      /**
 463       * Fires after the value of a specific option has been successfully updated.
 464       *
 465       * The dynamic portion of the hook name, `$option`, refers to the option name.
 466       *
 467       * @since 2.0.1
 468       * @since 4.4.0 The `$option` parameter was added.
 469       *
 470       * @param mixed  $old_value The old option value.
 471       * @param mixed  $value     The new option value.
 472       * @param string $option    Option name.
 473       */
 474      do_action( "update_option_{$option}", $old_value, $value, $option );
 475  
 476      /**
 477       * Fires after the value of an option has been successfully updated.
 478       *
 479       * @since 2.9.0
 480       *
 481       * @param string $option    Name of the updated option.
 482       * @param mixed  $old_value The old option value.
 483       * @param mixed  $value     The new option value.
 484       */
 485      do_action( 'updated_option', $option, $old_value, $value );
 486  
 487      return true;
 488  }
 489  
 490  /**
 491   * Adds a new option.
 492   *
 493   * You do not need to serialize values. If the value needs to be serialized,
 494   * then it will be serialized before it is inserted into the database.
 495   * Remember, resources cannot be serialized or added as an option.
 496   *
 497   * You can create options without values and then update the values later.
 498   * Existing options will not be updated and checks are performed to ensure that you
 499   * aren't adding a protected WordPress option. Care should be taken to not name
 500   * options the same as the ones which are protected.
 501   *
 502   * @since 1.0.0
 503   *
 504   * @global wpdb $wpdb WordPress database abstraction object.
 505   *
 506   * @param string      $option     Name of the option to add. Expected to not be SQL-escaped.
 507   * @param mixed       $value      Optional. Option value. Must be serializable if non-scalar.
 508   *                                Expected to not be SQL-escaped.
 509   * @param string      $deprecated Optional. Description. Not used anymore.
 510   * @param string|bool $autoload   Optional. Whether to load the option when WordPress starts up.
 511   *                                Default is enabled. Accepts 'no' to disable for legacy reasons.
 512   * @return bool True if the option was added, false otherwise.
 513   */
 514  function add_option( $option, $value = '', $deprecated = '', $autoload = 'yes' ) {
 515      global $wpdb;
 516  
 517      if ( ! empty( $deprecated ) ) {
 518          _deprecated_argument( __FUNCTION__, '2.3.0' );
 519      }
 520  
 521      $option = trim( $option );
 522      if ( empty( $option ) ) {
 523          return false;
 524      }
 525  
 526      /*
 527       * Until a proper _deprecated_option() function can be introduced,
 528       * redirect requests to deprecated keys to the new, correct ones.
 529       */
 530      $deprecated_keys = array(
 531          'blacklist_keys'    => 'disallowed_keys',
 532          'comment_whitelist' => 'comment_previously_approved',
 533      );
 534  
 535      if ( ! wp_installing() && isset( $deprecated_keys[ $option ] ) ) {
 536          _deprecated_argument(
 537              __FUNCTION__,
 538              '5.5.0',
 539              sprintf(
 540                  /* translators: 1: Deprecated option key, 2: New option key. */
 541                  __( 'The "%1$s" option key has been renamed to "%2$s".' ),
 542                  $option,
 543                  $deprecated_keys[ $option ]
 544              )
 545          );
 546          return add_option( $deprecated_keys[ $option ], $value, $deprecated, $autoload );
 547      }
 548  
 549      wp_protect_special_option( $option );
 550  
 551      if ( is_object( $value ) ) {
 552          $value = clone $value;
 553      }
 554  
 555      $value = sanitize_option( $option, $value );
 556  
 557      // Make sure the option doesn't already exist.
 558      // We can check the 'notoptions' cache before we ask for a DB query.
 559      $notoptions = wp_cache_get( 'notoptions', 'options' );
 560  
 561      if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) {
 562          /** This filter is documented in wp-includes/option.php */
 563          if ( apply_filters( "default_option_{$option}", false, $option, false ) !== get_option( $option ) ) {
 564              return false;
 565          }
 566      }
 567  
 568      $serialized_value = maybe_serialize( $value );
 569      $autoload         = ( 'no' === $autoload || false === $autoload ) ? 'no' : 'yes';
 570  
 571      /**
 572       * Fires before an option is added.
 573       *
 574       * @since 2.9.0
 575       *
 576       * @param string $option Name of the option to add.
 577       * @param mixed  $value  Value of the option.
 578       */
 579      do_action( 'add_option', $option, $value );
 580  
 581      $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 ) );
 582      if ( ! $result ) {
 583          return false;
 584      }
 585  
 586      if ( ! wp_installing() ) {
 587          if ( 'yes' === $autoload ) {
 588              $alloptions            = wp_load_alloptions( true );
 589              $alloptions[ $option ] = $serialized_value;
 590              wp_cache_set( 'alloptions', $alloptions, 'options' );
 591          } else {
 592              wp_cache_set( $option, $serialized_value, 'options' );
 593          }
 594      }
 595  
 596      // This option exists now.
 597      $notoptions = wp_cache_get( 'notoptions', 'options' ); // Yes, again... we need it to be fresh.
 598  
 599      if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
 600          unset( $notoptions[ $option ] );
 601          wp_cache_set( 'notoptions', $notoptions, 'options' );
 602      }
 603  
 604      /**
 605       * Fires after a specific option has been added.
 606       *
 607       * The dynamic portion of the hook name, `$option`, refers to the option name.
 608       *
 609       * @since 2.5.0 As "add_option_{$name}"
 610       * @since 3.0.0
 611       *
 612       * @param string $option Name of the option to add.
 613       * @param mixed  $value  Value of the option.
 614       */
 615      do_action( "add_option_{$option}", $option, $value );
 616  
 617      /**
 618       * Fires after an option has been added.
 619       *
 620       * @since 2.9.0
 621       *
 622       * @param string $option Name of the added option.
 623       * @param mixed  $value  Value of the option.
 624       */
 625      do_action( 'added_option', $option, $value );
 626  
 627      return true;
 628  }
 629  
 630  /**
 631   * Removes option by name. Prevents removal of protected WordPress options.
 632   *
 633   * @since 1.2.0
 634   *
 635   * @global wpdb $wpdb WordPress database abstraction object.
 636   *
 637   * @param string $option Name of the option to delete. Expected to not be SQL-escaped.
 638   * @return bool True if the option was deleted, false otherwise.
 639   */
 640  function delete_option( $option ) {
 641      global $wpdb;
 642  
 643      $option = trim( $option );
 644      if ( empty( $option ) ) {
 645          return false;
 646      }
 647  
 648      wp_protect_special_option( $option );
 649  
 650      // Get the ID, if no ID then return.
 651      $row = $wpdb->get_row( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s", $option ) );
 652      if ( is_null( $row ) ) {
 653          return false;
 654      }
 655  
 656      /**
 657       * Fires immediately before an option is deleted.
 658       *
 659       * @since 2.9.0
 660       *
 661       * @param string $option Name of the option to delete.
 662       */
 663      do_action( 'delete_option', $option );
 664  
 665      $result = $wpdb->delete( $wpdb->options, array( 'option_name' => $option ) );
 666  
 667      if ( ! wp_installing() ) {
 668          if ( 'yes' === $row->autoload ) {
 669              $alloptions = wp_load_alloptions( true );
 670              if ( is_array( $alloptions ) && isset( $alloptions[ $option ] ) ) {
 671                  unset( $alloptions[ $option ] );
 672                  wp_cache_set( 'alloptions', $alloptions, 'options' );
 673              }
 674          } else {
 675              wp_cache_delete( $option, 'options' );
 676          }
 677      }
 678  
 679      if ( $result ) {
 680  
 681          /**
 682           * Fires after a specific option has been deleted.
 683           *
 684           * The dynamic portion of the hook name, `$option`, refers to the option name.
 685           *
 686           * @since 3.0.0
 687           *
 688           * @param string $option Name of the deleted option.
 689           */
 690          do_action( "delete_option_{$option}", $option );
 691  
 692          /**
 693           * Fires after an option has been deleted.
 694           *
 695           * @since 2.9.0
 696           *
 697           * @param string $option Name of the deleted option.
 698           */
 699          do_action( 'deleted_option', $option );
 700  
 701          return true;
 702      }
 703  
 704      return false;
 705  }
 706  
 707  /**
 708   * Deletes a transient.
 709   *
 710   * @since 2.8.0
 711   *
 712   * @param string $transient Transient name. Expected to not be SQL-escaped.
 713   * @return bool True if the transient was deleted, false otherwise.
 714   */
 715  function delete_transient( $transient ) {
 716  
 717      /**
 718       * Fires immediately before a specific transient is deleted.
 719       *
 720       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
 721       *
 722       * @since 3.0.0
 723       *
 724       * @param string $transient Transient name.
 725       */
 726      do_action( "delete_transient_{$transient}", $transient );
 727  
 728      if ( wp_using_ext_object_cache() ) {
 729          $result = wp_cache_delete( $transient, 'transient' );
 730      } else {
 731          $option_timeout = '_transient_timeout_' . $transient;
 732          $option         = '_transient_' . $transient;
 733          $result         = delete_option( $option );
 734  
 735          if ( $result ) {
 736              delete_option( $option_timeout );
 737          }
 738      }
 739  
 740      if ( $result ) {
 741  
 742          /**
 743           * Fires after a transient is deleted.
 744           *
 745           * @since 3.0.0
 746           *
 747           * @param string $transient Deleted transient name.
 748           */
 749          do_action( 'deleted_transient', $transient );
 750      }
 751  
 752      return $result;
 753  }
 754  
 755  /**
 756   * Retrieves the value of a transient.
 757   *
 758   * If the transient does not exist, does not have a value, or has expired,
 759   * then the return value will be false.
 760   *
 761   * @since 2.8.0
 762   *
 763   * @param string $transient Transient name. Expected to not be SQL-escaped.
 764   * @return mixed Value of transient.
 765   */
 766  function get_transient( $transient ) {
 767  
 768      /**
 769       * Filters the value of an existing transient before it is retrieved.
 770       *
 771       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
 772       *
 773       * Returning a truthy value from the filter will effectively short-circuit retrieval
 774       * and return the passed value instead.
 775       *
 776       * @since 2.8.0
 777       * @since 4.4.0 The `$transient` parameter was added
 778       *
 779       * @param mixed  $pre_transient The default value to return if the transient does not exist.
 780       *                              Any value other than false will short-circuit the retrieval
 781       *                              of the transient, and return that value.
 782       * @param string $transient     Transient name.
 783       */
 784      $pre = apply_filters( "pre_transient_{$transient}", false, $transient );
 785  
 786      if ( false !== $pre ) {
 787          return $pre;
 788      }
 789  
 790      if ( wp_using_ext_object_cache() ) {
 791          $value = wp_cache_get( $transient, 'transient' );
 792      } else {
 793          $transient_option = '_transient_' . $transient;
 794          if ( ! wp_installing() ) {
 795              // If option is not in alloptions, it is not autoloaded and thus has a timeout.
 796              $alloptions = wp_load_alloptions();
 797              if ( ! isset( $alloptions[ $transient_option ] ) ) {
 798                  $transient_timeout = '_transient_timeout_' . $transient;
 799                  $timeout           = get_option( $transient_timeout );
 800                  if ( false !== $timeout && $timeout < time() ) {
 801                      delete_option( $transient_option );
 802                      delete_option( $transient_timeout );
 803                      $value = false;
 804                  }
 805              }
 806          }
 807  
 808          if ( ! isset( $value ) ) {
 809              $value = get_option( $transient_option );
 810          }
 811      }
 812  
 813      /**
 814       * Filters an existing transient's value.
 815       *
 816       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
 817       *
 818       * @since 2.8.0
 819       * @since 4.4.0 The `$transient` parameter was added
 820       *
 821       * @param mixed  $value     Value of transient.
 822       * @param string $transient Transient name.
 823       */
 824      return apply_filters( "transient_{$transient}", $value, $transient );
 825  }
 826  
 827  /**
 828   * Sets/updates the value of a transient.
 829   *
 830   * You do not need to serialize values. If the value needs to be serialized,
 831   * then it will be serialized before it is set.
 832   *
 833   * @since 2.8.0
 834   *
 835   * @param string $transient  Transient name. Expected to not be SQL-escaped.
 836   *                           Must be 172 characters or fewer in length.
 837   * @param mixed  $value      Transient value. Must be serializable if non-scalar.
 838   *                           Expected to not be SQL-escaped.
 839   * @param int    $expiration Optional. Time until expiration in seconds. Default 0 (no expiration).
 840   * @return bool True if the value was set, false otherwise.
 841   */
 842  function set_transient( $transient, $value, $expiration = 0 ) {
 843  
 844      $expiration = (int) $expiration;
 845  
 846      /**
 847       * Filters a specific transient before its value is set.
 848       *
 849       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
 850       *
 851       * @since 3.0.0
 852       * @since 4.2.0 The `$expiration` parameter was added.
 853       * @since 4.4.0 The `$transient` parameter was added.
 854       *
 855       * @param mixed  $value      New value of transient.
 856       * @param int    $expiration Time until expiration in seconds.
 857       * @param string $transient  Transient name.
 858       */
 859      $value = apply_filters( "pre_set_transient_{$transient}", $value, $expiration, $transient );
 860  
 861      /**
 862       * Filters the expiration for a transient before its value is set.
 863       *
 864       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
 865       *
 866       * @since 4.4.0
 867       *
 868       * @param int    $expiration Time until expiration in seconds. Use 0 for no expiration.
 869       * @param mixed  $value      New value of transient.
 870       * @param string $transient  Transient name.
 871       */
 872      $expiration = apply_filters( "expiration_of_transient_{$transient}", $expiration, $value, $transient );
 873  
 874      if ( wp_using_ext_object_cache() ) {
 875          $result = wp_cache_set( $transient, $value, 'transient', $expiration );
 876      } else {
 877          $transient_timeout = '_transient_timeout_' . $transient;
 878          $transient_option  = '_transient_' . $transient;
 879  
 880          if ( false === get_option( $transient_option ) ) {
 881              $autoload = 'yes';
 882              if ( $expiration ) {
 883                  $autoload = 'no';
 884                  add_option( $transient_timeout, time() + $expiration, '', 'no' );
 885              }
 886              $result = add_option( $transient_option, $value, '', $autoload );
 887          } else {
 888              // If expiration is requested, but the transient has no timeout option,
 889              // delete, then re-create transient rather than update.
 890              $update = true;
 891  
 892              if ( $expiration ) {
 893                  if ( false === get_option( $transient_timeout ) ) {
 894                      delete_option( $transient_option );
 895                      add_option( $transient_timeout, time() + $expiration, '', 'no' );
 896                      $result = add_option( $transient_option, $value, '', 'no' );
 897                      $update = false;
 898                  } else {
 899                      update_option( $transient_timeout, time() + $expiration );
 900                  }
 901              }
 902  
 903              if ( $update ) {
 904                  $result = update_option( $transient_option, $value );
 905              }
 906          }
 907      }
 908  
 909      if ( $result ) {
 910  
 911          /**
 912           * Fires after the value for a specific transient has been set.
 913           *
 914           * The dynamic portion of the hook name, `$transient`, refers to the transient name.
 915           *
 916           * @since 3.0.0
 917           * @since 3.6.0 The `$value` and `$expiration` parameters were added.
 918           * @since 4.4.0 The `$transient` parameter was added.
 919           *
 920           * @param mixed  $value      Transient value.
 921           * @param int    $expiration Time until expiration in seconds.
 922           * @param string $transient  The name of the transient.
 923           */
 924          do_action( "set_transient_{$transient}", $value, $expiration, $transient );
 925  
 926          /**
 927           * Fires after the value for a transient has been set.
 928           *
 929           * @since 3.0.0
 930           * @since 3.6.0 The `$value` and `$expiration` parameters were added.
 931           *
 932           * @param string $transient  The name of the transient.
 933           * @param mixed  $value      Transient value.
 934           * @param int    $expiration Time until expiration in seconds.
 935           */
 936          do_action( 'setted_transient', $transient, $value, $expiration );
 937      }
 938  
 939      return $result;
 940  }
 941  
 942  /**
 943   * Deletes all expired transients.
 944   *
 945   * The multi-table delete syntax is used to delete the transient record
 946   * from table a, and the corresponding transient_timeout record from table b.
 947   *
 948   * @since 4.9.0
 949   *
 950   * @param bool $force_db Optional. Force cleanup to run against the database even when an external object cache is used.
 951   */
 952  function delete_expired_transients( $force_db = false ) {
 953      global $wpdb;
 954  
 955      if ( ! $force_db && wp_using_ext_object_cache() ) {
 956          return;
 957      }
 958  
 959      $wpdb->query(
 960          $wpdb->prepare(
 961              "DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b
 962              WHERE a.option_name LIKE %s
 963              AND a.option_name NOT LIKE %s
 964              AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) )
 965              AND b.option_value < %d",
 966              $wpdb->esc_like( '_transient_' ) . '%',
 967              $wpdb->esc_like( '_transient_timeout_' ) . '%',
 968              time()
 969          )
 970      );
 971  
 972      if ( ! is_multisite() ) {
 973          // Single site stores site transients in the options table.
 974          $wpdb->query(
 975              $wpdb->prepare(
 976                  "DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b
 977                  WHERE a.option_name LIKE %s
 978                  AND a.option_name NOT LIKE %s
 979                  AND b.option_name = CONCAT( '_site_transient_timeout_', SUBSTRING( a.option_name, 17 ) )
 980                  AND b.option_value < %d",
 981                  $wpdb->esc_like( '_site_transient_' ) . '%',
 982                  $wpdb->esc_like( '_site_transient_timeout_' ) . '%',
 983                  time()
 984              )
 985          );
 986      } elseif ( is_multisite() && is_main_site() && is_main_network() ) {
 987          // Multisite stores site transients in the sitemeta table.
 988          $wpdb->query(
 989              $wpdb->prepare(
 990                  "DELETE a, b FROM {$wpdb->sitemeta} a, {$wpdb->sitemeta} b
 991                  WHERE a.meta_key LIKE %s
 992                  AND a.meta_key NOT LIKE %s
 993                  AND b.meta_key = CONCAT( '_site_transient_timeout_', SUBSTRING( a.meta_key, 17 ) )
 994                  AND b.meta_value < %d",
 995                  $wpdb->esc_like( '_site_transient_' ) . '%',
 996                  $wpdb->esc_like( '_site_transient_timeout_' ) . '%',
 997                  time()
 998              )
 999          );
1000      }
1001  }
1002  
1003  /**
1004   * Saves and restores user interface settings stored in a cookie.
1005   *
1006   * Checks if the current user-settings cookie is updated and stores it. When no
1007   * cookie exists (different browser used), adds the last saved cookie restoring
1008   * the settings.
1009   *
1010   * @since 2.7.0
1011   */
1012  function wp_user_settings() {
1013  
1014      if ( ! is_admin() || wp_doing_ajax() ) {
1015          return;
1016      }
1017  
1018      $user_id = get_current_user_id();
1019      if ( ! $user_id ) {
1020          return;
1021      }
1022  
1023      if ( ! is_user_member_of_blog() ) {
1024          return;
1025      }
1026  
1027      $settings = (string) get_user_option( 'user-settings', $user_id );
1028  
1029      if ( isset( $_COOKIE[ 'wp-settings-' . $user_id ] ) ) {
1030          $cookie = preg_replace( '/[^A-Za-z0-9=&_]/', '', $_COOKIE[ 'wp-settings-' . $user_id ] );
1031  
1032          // No change or both empty.
1033          if ( $cookie == $settings ) {
1034              return;
1035          }
1036  
1037          $last_saved = (int) get_user_option( 'user-settings-time', $user_id );
1038          $current    = isset( $_COOKIE[ 'wp-settings-time-' . $user_id ] ) ? preg_replace( '/[^0-9]/', '', $_COOKIE[ 'wp-settings-time-' . $user_id ] ) : 0;
1039  
1040          // The cookie is newer than the saved value. Update the user_option and leave the cookie as-is.
1041          if ( $current > $last_saved ) {
1042              update_user_option( $user_id, 'user-settings', $cookie, false );
1043              update_user_option( $user_id, 'user-settings-time', time() - 5, false );
1044              return;
1045          }
1046      }
1047  
1048      // The cookie is not set in the current browser or the saved value is newer.
1049      $secure = ( 'https' === parse_url( admin_url(), PHP_URL_SCHEME ) );
1050      setcookie( 'wp-settings-' . $user_id, $settings, time() + YEAR_IN_SECONDS, SITECOOKIEPATH, null, $secure );
1051      setcookie( 'wp-settings-time-' . $user_id, time(), time() + YEAR_IN_SECONDS, SITECOOKIEPATH, null, $secure );
1052      $_COOKIE[ 'wp-settings-' . $user_id ] = $settings;
1053  }
1054  
1055  /**
1056   * Retrieves user interface setting value based on setting name.
1057   *
1058   * @since 2.7.0
1059   *
1060   * @param string $name    The name of the setting.
1061   * @param string $default Optional default value to return when $name is not set.
1062   * @return mixed The last saved user setting or the default value/false if it doesn't exist.
1063   */
1064  function get_user_setting( $name, $default = false ) {
1065      $all_user_settings = get_all_user_settings();
1066  
1067      return isset( $all_user_settings[ $name ] ) ? $all_user_settings[ $name ] : $default;
1068  }
1069  
1070  /**
1071   * Adds or updates user interface setting.
1072   *
1073   * Both $name and $value can contain only ASCII letters, numbers, hyphens, and underscores.
1074   *
1075   * This function has to be used before any output has started as it calls setcookie().
1076   *
1077   * @since 2.8.0
1078   *
1079   * @param string $name  The name of the setting.
1080   * @param string $value The value for the setting.
1081   * @return bool|null True if set successfully, false otherwise.
1082   *                   Null if the current user is not a member of the site.
1083   */
1084  function set_user_setting( $name, $value ) {
1085      if ( headers_sent() ) {
1086          return false;
1087      }
1088  
1089      $all_user_settings          = get_all_user_settings();
1090      $all_user_settings[ $name ] = $value;
1091  
1092      return wp_set_all_user_settings( $all_user_settings );
1093  }
1094  
1095  /**
1096   * Deletes user interface settings.
1097   *
1098   * Deleting settings would reset them to the defaults.
1099   *
1100   * This function has to be used before any output has started as it calls setcookie().
1101   *
1102   * @since 2.7.0
1103   *
1104   * @param string $names The name or array of names of the setting to be deleted.
1105   * @return bool|null True if deleted successfully, false otherwise.
1106   *                   Null if the current user is not a member of the site.
1107   */
1108  function delete_user_setting( $names ) {
1109      if ( headers_sent() ) {
1110          return false;
1111      }
1112  
1113      $all_user_settings = get_all_user_settings();
1114      $names             = (array) $names;
1115      $deleted           = false;
1116  
1117      foreach ( $names as $name ) {
1118          if ( isset( $all_user_settings[ $name ] ) ) {
1119              unset( $all_user_settings[ $name ] );
1120              $deleted = true;
1121          }
1122      }
1123  
1124      if ( $deleted ) {
1125          return wp_set_all_user_settings( $all_user_settings );
1126      }
1127  
1128      return false;
1129  }
1130  
1131  /**
1132   * Retrieves all user interface settings.
1133   *
1134   * @since 2.7.0
1135   *
1136   * @global array $_updated_user_settings
1137   *
1138   * @return array The last saved user settings or empty array.
1139   */
1140  function get_all_user_settings() {
1141      global $_updated_user_settings;
1142  
1143      $user_id = get_current_user_id();
1144      if ( ! $user_id ) {
1145          return array();
1146      }
1147  
1148      if ( isset( $_updated_user_settings ) && is_array( $_updated_user_settings ) ) {
1149          return $_updated_user_settings;
1150      }
1151  
1152      $user_settings = array();
1153  
1154      if ( isset( $_COOKIE[ 'wp-settings-' . $user_id ] ) ) {
1155          $cookie = preg_replace( '/[^A-Za-z0-9=&_-]/', '', $_COOKIE[ 'wp-settings-' . $user_id ] );
1156  
1157          if ( strpos( $cookie, '=' ) ) { // '=' cannot be 1st char.
1158              parse_str( $cookie, $user_settings );
1159          }
1160      } else {
1161          $option = get_user_option( 'user-settings', $user_id );
1162  
1163          if ( $option && is_string( $option ) ) {
1164              parse_str( $option, $user_settings );
1165          }
1166      }
1167  
1168      $_updated_user_settings = $user_settings;
1169      return $user_settings;
1170  }
1171  
1172  /**
1173   * Private. Sets all user interface settings.
1174   *
1175   * @since 2.8.0
1176   * @access private
1177   *
1178   * @global array $_updated_user_settings
1179   *
1180   * @param array $user_settings User settings.
1181   * @return bool|null True if set successfully, false if the current user could not be found.
1182   *                   Null if the current user is not a member of the site.
1183   */
1184  function wp_set_all_user_settings( $user_settings ) {
1185      global $_updated_user_settings;
1186  
1187      $user_id = get_current_user_id();
1188      if ( ! $user_id ) {
1189          return false;
1190      }
1191  
1192      if ( ! is_user_member_of_blog() ) {
1193          return;
1194      }
1195  
1196      $settings = '';
1197      foreach ( $user_settings as $name => $value ) {
1198          $_name  = preg_replace( '/[^A-Za-z0-9_-]+/', '', $name );
1199          $_value = preg_replace( '/[^A-Za-z0-9_-]+/', '', $value );
1200  
1201          if ( ! empty( $_name ) ) {
1202              $settings .= $_name . '=' . $_value . '&';
1203          }
1204      }
1205  
1206      $settings = rtrim( $settings, '&' );
1207      parse_str( $settings, $_updated_user_settings );
1208  
1209      update_user_option( $user_id, 'user-settings', $settings, false );
1210      update_user_option( $user_id, 'user-settings-time', time(), false );
1211  
1212      return true;
1213  }
1214  
1215  /**
1216   * Deletes the user settings of the current user.
1217   *
1218   * @since 2.7.0
1219   */
1220  function delete_all_user_settings() {
1221      $user_id = get_current_user_id();
1222      if ( ! $user_id ) {
1223          return;
1224      }
1225  
1226      update_user_option( $user_id, 'user-settings', '', false );
1227      setcookie( 'wp-settings-' . $user_id, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH );
1228  }
1229  
1230  /**
1231   * Retrieve an option value for the current network based on name of option.
1232   *
1233   * @since 2.8.0
1234   * @since 4.4.0 The `$use_cache` parameter was deprecated.
1235   * @since 4.4.0 Modified into wrapper for get_network_option()
1236   *
1237   * @see get_network_option()
1238   *
1239   * @param string $option     Name of the option to retrieve. Expected to not be SQL-escaped.
1240   * @param mixed  $default    Optional. Value to return if the option doesn't exist. Default false.
1241   * @param bool   $deprecated Whether to use cache. Multisite only. Always set to true.
1242   * @return mixed Value set for the option.
1243   */
1244  function get_site_option( $option, $default = false, $deprecated = true ) {
1245      return get_network_option( null, $option, $default );
1246  }
1247  
1248  /**
1249   * Adds a new option for the current network.
1250   *
1251   * Existing options will not be updated. Note that prior to 3.3 this wasn't the case.
1252   *
1253   * @since 2.8.0
1254   * @since 4.4.0 Modified into wrapper for add_network_option()
1255   *
1256   * @see add_network_option()
1257   *
1258   * @param string $option Name of the option to add. Expected to not be SQL-escaped.
1259   * @param mixed  $value  Option value, can be anything. Expected to not be SQL-escaped.
1260   * @return bool True if the option was added, false otherwise.
1261   */
1262  function add_site_option( $option, $value ) {
1263      return add_network_option( null, $option, $value );
1264  }
1265  
1266  /**
1267   * Removes a option by name for the current network.
1268   *
1269   * @since 2.8.0
1270   * @since 4.4.0 Modified into wrapper for delete_network_option()
1271   *
1272   * @see delete_network_option()
1273   *
1274   * @param string $option Name of the option to delete. Expected to not be SQL-escaped.
1275   * @return bool True if the option was deleted, false otherwise.
1276   */
1277  function delete_site_option( $option ) {
1278      return delete_network_option( null, $option );
1279  }
1280  
1281  /**
1282   * Updates the value of an option that was already added for the current network.
1283   *
1284   * @since 2.8.0
1285   * @since 4.4.0 Modified into wrapper for update_network_option()
1286   *
1287   * @see update_network_option()
1288   *
1289   * @param string $option Name of the option. Expected to not be SQL-escaped.
1290   * @param mixed  $value  Option value. Expected to not be SQL-escaped.
1291   * @return bool True if the value was updated, false otherwise.
1292   */
1293  function update_site_option( $option, $value ) {
1294      return update_network_option( null, $option, $value );
1295  }
1296  
1297  /**
1298   * Retrieves a network's option value based on the option name.
1299   *
1300   * @since 4.4.0
1301   *
1302   * @see get_option()
1303   *
1304   * @global wpdb $wpdb WordPress database abstraction object.
1305   *
1306   * @param int    $network_id ID of the network. Can be null to default to the current network ID.
1307   * @param string $option     Name of the option to retrieve. Expected to not be SQL-escaped.
1308   * @param mixed  $default    Optional. Value to return if the option doesn't exist. Default false.
1309   * @return mixed Value set for the option.
1310   */
1311  function get_network_option( $network_id, $option, $default = false ) {
1312      global $wpdb;
1313  
1314      if ( $network_id && ! is_numeric( $network_id ) ) {
1315          return false;
1316      }
1317  
1318      $network_id = (int) $network_id;
1319  
1320      // Fallback to the current network if a network ID is not specified.
1321      if ( ! $network_id ) {
1322          $network_id = get_current_network_id();
1323      }
1324  
1325      /**
1326       * Filters the value of an existing network option before it is retrieved.
1327       *
1328       * The dynamic portion of the hook name, `$option`, refers to the option name.
1329       *
1330       * Returning a truthy value from the filter will effectively short-circuit retrieval
1331       * and return the passed value instead.
1332       *
1333       * @since 2.9.0 As 'pre_site_option_' . $key
1334       * @since 3.0.0
1335       * @since 4.4.0 The `$option` parameter was added.
1336       * @since 4.7.0 The `$network_id` parameter was added.
1337       * @since 4.9.0 The `$default` parameter was added.
1338       *
1339       * @param mixed  $pre_option The value to return instead of the option value. This differs
1340       *                           from `$default`, which is used as the fallback value in the event
1341       *                           the option doesn't exist elsewhere in get_network_option().
1342       *                           Default false (to skip past the short-circuit).
1343       * @param string $option     Option name.
1344       * @param int    $network_id ID of the network.
1345       * @param mixed  $default    The fallback value to return if the option does not exist.
1346       *                           Default false.
1347       */
1348      $pre = apply_filters( "pre_site_option_{$option}", false, $option, $network_id, $default );
1349  
1350      if ( false !== $pre ) {
1351          return $pre;
1352      }
1353  
1354      // Prevent non-existent options from triggering multiple queries.
1355      $notoptions_key = "$network_id:notoptions";
1356      $notoptions     = wp_cache_get( $notoptions_key, 'site-options' );
1357  
1358      if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
1359  
1360          /**
1361           * Filters a specific default network option.
1362           *
1363           * The dynamic portion of the hook name, `$option`, refers to the option name.
1364           *
1365           * @since 3.4.0
1366           * @since 4.4.0 The `$option` parameter was added.
1367           * @since 4.7.0 The `$network_id` parameter was added.
1368           *
1369           * @param mixed  $default    The value to return if the site option does not exist
1370           *                           in the database.
1371           * @param string $option     Option name.
1372           * @param int    $network_id ID of the network.
1373           */
1374          return apply_filters( "default_site_option_{$option}", $default, $option, $network_id );
1375      }
1376  
1377      if ( ! is_multisite() ) {
1378          /** This filter is documented in wp-includes/option.php */
1379          $default = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id );
1380          $value   = get_option( $option, $default );
1381      } else {
1382          $cache_key = "$network_id:$option";
1383          $value     = wp_cache_get( $cache_key, 'site-options' );
1384  
1385          if ( ! isset( $value ) || false === $value ) {
1386              $row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
1387  
1388              // Has to be get_row() instead of get_var() because of funkiness with 0, false, null values.
1389              if ( is_object( $row ) ) {
1390                  $value = $row->meta_value;
1391                  $value = maybe_unserialize( $value );
1392                  wp_cache_set( $cache_key, $value, 'site-options' );
1393              } else {
1394                  if ( ! is_array( $notoptions ) ) {
1395                      $notoptions = array();
1396                  }
1397  
1398                  $notoptions[ $option ] = true;
1399                  wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
1400  
1401                  /** This filter is documented in wp-includes/option.php */
1402                  $value = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id );
1403              }
1404          }
1405      }
1406  
1407      if ( ! is_array( $notoptions ) ) {
1408          $notoptions = array();
1409          wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
1410      }
1411  
1412      /**
1413       * Filters the value of an existing network option.
1414       *
1415       * The dynamic portion of the hook name, `$option`, refers to the option name.
1416       *
1417       * @since 2.9.0 As 'site_option_' . $key
1418       * @since 3.0.0
1419       * @since 4.4.0 The `$option` parameter was added.
1420       * @since 4.7.0 The `$network_id` parameter was added.
1421       *
1422       * @param mixed  $value      Value of network option.
1423       * @param string $option     Option name.
1424       * @param int    $network_id ID of the network.
1425       */
1426      return apply_filters( "site_option_{$option}", $value, $option, $network_id );
1427  }
1428  
1429  /**
1430   * Adds a new network option.
1431   *
1432   * Existing options will not be updated.
1433   *
1434   * @since 4.4.0
1435   *
1436   * @see add_option()
1437   *
1438   * @global wpdb $wpdb WordPress database abstraction object.
1439   *
1440   * @param int    $network_id ID of the network. Can be null to default to the current network ID.
1441   * @param string $option     Name of the option to add. Expected to not be SQL-escaped.
1442   * @param mixed  $value      Option value, can be anything. Expected to not be SQL-escaped.
1443   * @return bool True if the option was added, false otherwise.
1444   */
1445  function add_network_option( $network_id, $option, $value ) {
1446      global $wpdb;
1447  
1448      if ( $network_id && ! is_numeric( $network_id ) ) {
1449          return false;
1450      }
1451  
1452      $network_id = (int) $network_id;
1453  
1454      // Fallback to the current network if a network ID is not specified.
1455      if ( ! $network_id ) {
1456          $network_id = get_current_network_id();
1457      }
1458  
1459      wp_protect_special_option( $option );
1460  
1461      /**
1462       * Filters the value of a specific network option before it is added.
1463       *
1464       * The dynamic portion of the hook name, `$option`, refers to the option name.
1465       *
1466       * @since 2.9.0 As 'pre_add_site_option_' . $key
1467       * @since 3.0.0
1468       * @since 4.4.0 The `$option` parameter was added.
1469       * @since 4.7.0 The `$network_id` parameter was added.
1470       *
1471       * @param mixed  $value      Value of network option.
1472       * @param string $option     Option name.
1473       * @param int    $network_id ID of the network.
1474       */
1475      $value = apply_filters( "pre_add_site_option_{$option}", $value, $option, $network_id );
1476  
1477      $notoptions_key = "$network_id:notoptions";
1478  
1479      if ( ! is_multisite() ) {
1480          $result = add_option( $option, $value, '', 'no' );
1481      } else {
1482          $cache_key = "$network_id:$option";
1483  
1484          // Make sure the option doesn't already exist.
1485          // We can check the 'notoptions' cache before we ask for a DB query.
1486          $notoptions = wp_cache_get( $notoptions_key, 'site-options' );
1487  
1488          if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) {
1489              if ( false !== get_network_option( $network_id, $option, false ) ) {
1490                  return false;
1491              }
1492          }
1493  
1494          $value = sanitize_option( $option, $value );
1495  
1496          $serialized_value = maybe_serialize( $value );
1497          $result           = $wpdb->insert(
1498              $wpdb->sitemeta,
1499              array(
1500                  'site_id'    => $network_id,
1501                  'meta_key'   => $option,
1502                  'meta_value' => $serialized_value,
1503              )
1504          );
1505  
1506          if ( ! $result ) {
1507              return false;
1508          }
1509  
1510          wp_cache_set( $cache_key, $value, 'site-options' );
1511  
1512          // This option exists now.
1513          $notoptions = wp_cache_get( $notoptions_key, 'site-options' ); // Yes, again... we need it to be fresh.
1514  
1515          if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
1516              unset( $notoptions[ $option ] );
1517              wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
1518          }
1519      }
1520  
1521      if ( $result ) {
1522  
1523          /**
1524           * Fires after a specific network option has been successfully added.
1525           *
1526           * The dynamic portion of the hook name, `$option`, refers to the option name.
1527           *
1528           * @since 2.9.0 As "add_site_option_{$key}"
1529           * @since 3.0.0
1530           * @since 4.7.0 The `$network_id` parameter was added.
1531           *
1532           * @param string $option     Name of the network option.
1533           * @param mixed  $value      Value of the network option.
1534           * @param int    $network_id ID of the network.
1535           */
1536          do_action( "add_site_option_{$option}", $option, $value, $network_id );
1537  
1538          /**
1539           * Fires after a network option has been successfully added.
1540           *
1541           * @since 3.0.0
1542           * @since 4.7.0 The `$network_id` parameter was added.
1543           *
1544           * @param string $option     Name of the network option.
1545           * @param mixed  $value      Value of the network option.
1546           * @param int    $network_id ID of the network.
1547           */
1548          do_action( 'add_site_option', $option, $value, $network_id );
1549  
1550          return true;
1551      }
1552  
1553      return false;
1554  }
1555  
1556  /**
1557   * Removes a network option by name.
1558   *
1559   * @since 4.4.0
1560   *
1561   * @see delete_option()
1562   *
1563   * @global wpdb $wpdb WordPress database abstraction object.
1564   *
1565   * @param int    $network_id ID of the network. Can be null to default to the current network ID.
1566   * @param string $option     Name of the option to delete. Expected to not be SQL-escaped.
1567   * @return bool True if the option was deleted, false otherwise.
1568   */
1569  function delete_network_option( $network_id, $option ) {
1570      global $wpdb;
1571  
1572      if ( $network_id && ! is_numeric( $network_id ) ) {
1573          return false;
1574      }
1575  
1576      $network_id = (int) $network_id;
1577  
1578      // Fallback to the current network if a network ID is not specified.
1579      if ( ! $network_id ) {
1580          $network_id = get_current_network_id();
1581      }
1582  
1583      /**
1584       * Fires immediately before a specific network option is deleted.
1585       *
1586       * The dynamic portion of the hook name, `$option`, refers to the option name.
1587       *
1588       * @since 3.0.0
1589       * @since 4.4.0 The `$option` parameter was added.
1590       * @since 4.7.0 The `$network_id` parameter was added.
1591       *
1592       * @param string $option     Option name.
1593       * @param int    $network_id ID of the network.
1594       */
1595      do_action( "pre_delete_site_option_{$option}", $option, $network_id );
1596  
1597      if ( ! is_multisite() ) {
1598          $result = delete_option( $option );
1599      } else {
1600          $row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM {$wpdb->sitemeta} WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
1601          if ( is_null( $row ) || ! $row->meta_id ) {
1602              return false;
1603          }
1604          $cache_key = "$network_id:$option";
1605          wp_cache_delete( $cache_key, 'site-options' );
1606  
1607          $result = $wpdb->delete(
1608              $wpdb->sitemeta,
1609              array(
1610                  'meta_key' => $option,
1611                  'site_id'  => $network_id,
1612              )
1613          );
1614      }
1615  
1616      if ( $result ) {
1617  
1618          /**
1619           * Fires after a specific network option has been deleted.
1620           *
1621           * The dynamic portion of the hook name, `$option`, refers to the option name.
1622           *
1623           * @since 2.9.0 As "delete_site_option_{$key}"
1624           * @since 3.0.0
1625           * @since 4.7.0 The `$network_id` parameter was added.
1626           *
1627           * @param string $option     Name of the network option.
1628           * @param int    $network_id ID of the network.
1629           */
1630          do_action( "delete_site_option_{$option}", $option, $network_id );
1631  
1632          /**
1633           * Fires after a network option has been deleted.
1634           *
1635           * @since 3.0.0
1636           * @since 4.7.0 The `$network_id` parameter was added.
1637           *
1638           * @param string $option     Name of the network option.
1639           * @param int    $network_id ID of the network.
1640           */
1641          do_action( 'delete_site_option', $option, $network_id );
1642  
1643          return true;
1644      }
1645  
1646      return false;
1647  }
1648  
1649  /**
1650   * Updates the value of a network option that was already added.
1651   *
1652   * @since 4.4.0
1653   *
1654   * @see update_option()
1655   *
1656   * @global wpdb $wpdb WordPress database abstraction object.
1657   *
1658   * @param int    $network_id ID of the network. Can be null to default to the current network ID.
1659   * @param string $option     Name of the option. Expected to not be SQL-escaped.
1660   * @param mixed  $value      Option value. Expected to not be SQL-escaped.
1661   * @return bool True if the value was updated, false otherwise.
1662   */
1663  function update_network_option( $network_id, $option, $value ) {
1664      global $wpdb;
1665  
1666      if ( $network_id && ! is_numeric( $network_id ) ) {
1667          return false;
1668      }
1669  
1670      $network_id = (int) $network_id;
1671  
1672      // Fallback to the current network if a network ID is not specified.
1673      if ( ! $network_id ) {
1674          $network_id = get_current_network_id();
1675      }
1676  
1677      wp_protect_special_option( $option );
1678  
1679      $old_value = get_network_option( $network_id, $option, false );
1680  
1681      /**
1682       * Filters a specific network option before its value is updated.
1683       *
1684       * The dynamic portion of the hook name, `$option`, refers to the option name.
1685       *
1686       * @since 2.9.0 As 'pre_update_site_option_' . $key
1687       * @since 3.0.0
1688       * @since 4.4.0 The `$option` parameter was added.
1689       * @since 4.7.0 The `$network_id` parameter was added.
1690       *
1691       * @param mixed  $value      New value of the network option.
1692       * @param mixed  $old_value  Old value of the network option.
1693       * @param string $option     Option name.
1694       * @param int    $network_id ID of the network.
1695       */
1696      $value = apply_filters( "pre_update_site_option_{$option}", $value, $old_value, $option, $network_id );
1697  
1698      /*
1699       * If the new and old values are the same, no need to update.
1700       *
1701       * Unserialized values will be adequate in most cases. If the unserialized
1702       * data differs, the (maybe) serialized data is checked to avoid
1703       * unnecessary database calls for otherwise identical object instances.
1704       *
1705       * See https://core.trac.wordpress.org/ticket/44956
1706       */
1707      if ( $value === $old_value || maybe_serialize( $value ) === maybe_serialize( $old_value ) ) {
1708          return false;
1709      }
1710  
1711      if ( false === $old_value ) {
1712          return add_network_option( $network_id, $option, $value );
1713      }
1714  
1715      $notoptions_key = "$network_id:notoptions";
1716      $notoptions     = wp_cache_get( $notoptions_key, 'site-options' );
1717  
1718      if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
1719          unset( $notoptions[ $option ] );
1720          wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
1721      }
1722  
1723      if ( ! is_multisite() ) {
1724          $result = update_option( $option, $value, 'no' );
1725      } else {
1726          $value = sanitize_option( $option, $value );
1727  
1728          $serialized_value = maybe_serialize( $value );
1729          $result           = $wpdb->update(
1730              $wpdb->sitemeta,
1731              array( 'meta_value' => $serialized_value ),
1732              array(
1733                  'site_id'  => $network_id,
1734                  'meta_key' => $option,
1735              )
1736          );
1737  
1738          if ( $result ) {
1739              $cache_key = "$network_id:$option";
1740              wp_cache_set( $cache_key, $value, 'site-options' );
1741          }
1742      }
1743  
1744      if ( $result ) {
1745  
1746          /**
1747           * Fires after the value of a specific network option has been successfully updated.
1748           *
1749           * The dynamic portion of the hook name, `$option`, refers to the option name.
1750           *
1751           * @since 2.9.0 As "update_site_option_{$key}"
1752           * @since 3.0.0
1753           * @since 4.7.0 The `$network_id` parameter was added.
1754           *
1755           * @param string $option     Name of the network option.
1756           * @param mixed  $value      Current value of the network option.
1757           * @param mixed  $old_value  Old value of the network option.
1758           * @param int    $network_id ID of the network.
1759           */
1760          do_action( "update_site_option_{$option}", $option, $value, $old_value, $network_id );
1761  
1762          /**
1763           * Fires after the value of a network option has been successfully updated.
1764           *
1765           * @since 3.0.0
1766           * @since 4.7.0 The `$network_id` parameter was added.
1767           *
1768           * @param string $option     Name of the network option.
1769           * @param mixed  $value      Current value of the network option.
1770           * @param mixed  $old_value  Old value of the network option.
1771           * @param int    $network_id ID of the network.
1772           */
1773          do_action( 'update_site_option', $option, $value, $old_value, $network_id );
1774  
1775          return true;
1776      }
1777  
1778      return false;
1779  }
1780  
1781  /**
1782   * Deletes a site transient.
1783   *
1784   * @since 2.9.0
1785   *
1786   * @param string $transient Transient name. Expected to not be SQL-escaped.
1787   * @return bool True if the transient was deleted, false otherwise.
1788   */
1789  function delete_site_transient( $transient ) {
1790  
1791      /**
1792       * Fires immediately before a specific site transient is deleted.
1793       *
1794       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1795       *
1796       * @since 3.0.0
1797       *
1798       * @param string $transient Transient name.
1799       */
1800      do_action( "delete_site_transient_{$transient}", $transient );
1801  
1802      if ( wp_using_ext_object_cache() ) {
1803          $result = wp_cache_delete( $transient, 'site-transient' );
1804      } else {
1805          $option_timeout = '_site_transient_timeout_' . $transient;
1806          $option         = '_site_transient_' . $transient;
1807          $result         = delete_site_option( $option );
1808  
1809          if ( $result ) {
1810              delete_site_option( $option_timeout );
1811          }
1812      }
1813  
1814      if ( $result ) {
1815  
1816          /**
1817           * Fires after a transient is deleted.
1818           *
1819           * @since 3.0.0
1820           *
1821           * @param string $transient Deleted transient name.
1822           */
1823          do_action( 'deleted_site_transient', $transient );
1824      }
1825  
1826      return $result;
1827  }
1828  
1829  /**
1830   * Retrieves the value of a site transient.
1831   *
1832   * If the transient does not exist, does not have a value, or has expired,
1833   * then the return value will be false.
1834   *
1835   * @since 2.9.0
1836   *
1837   * @see get_transient()
1838   *
1839   * @param string $transient Transient name. Expected to not be SQL-escaped.
1840   * @return mixed Value of transient.
1841   */
1842  function get_site_transient( $transient ) {
1843  
1844      /**
1845       * Filters the value of an existing site transient before it is retrieved.
1846       *
1847       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1848       *
1849       * Returning a truthy value from the filter will effectively short-circuit retrieval
1850       * and return the passed value instead.
1851       *
1852       * @since 2.9.0
1853       * @since 4.4.0 The `$transient` parameter was added.
1854       *
1855       * @param mixed  $pre_site_transient The default value to return if the site transient does not exist.
1856       *                                   Any value other than false will short-circuit the retrieval
1857       *                                   of the transient, and return that value.
1858       * @param string $transient          Transient name.
1859       */
1860      $pre = apply_filters( "pre_site_transient_{$transient}", false, $transient );
1861  
1862      if ( false !== $pre ) {
1863          return $pre;
1864      }
1865  
1866      if ( wp_using_ext_object_cache() ) {
1867          $value = wp_cache_get( $transient, 'site-transient' );
1868      } else {
1869          // Core transients that do not have a timeout. Listed here so querying timeouts can be avoided.
1870          $no_timeout       = array( 'update_core', 'update_plugins', 'update_themes' );
1871          $transient_option = '_site_transient_' . $transient;
1872          if ( ! in_array( $transient, $no_timeout, true ) ) {
1873              $transient_timeout = '_site_transient_timeout_' . $transient;
1874              $timeout           = get_site_option( $transient_timeout );
1875              if ( false !== $timeout && $timeout < time() ) {
1876                  delete_site_option( $transient_option );
1877                  delete_site_option( $transient_timeout );
1878                  $value = false;
1879              }
1880          }
1881  
1882          if ( ! isset( $value ) ) {
1883              $value = get_site_option( $transient_option );
1884          }
1885      }
1886  
1887      /**
1888       * Filters the value of an existing site transient.
1889       *
1890       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1891       *
1892       * @since 2.9.0
1893       * @since 4.4.0 The `$transient` parameter was added.
1894       *
1895       * @param mixed  $value     Value of site transient.
1896       * @param string $transient Transient name.
1897       */
1898      return apply_filters( "site_transient_{$transient}", $value, $transient );
1899  }
1900  
1901  /**
1902   * Sets/updates the value of a site transient.
1903   *
1904   * You do not need to serialize values. If the value needs to be serialized,
1905   * then it will be serialized before it is set.
1906   *
1907   * @since 2.9.0
1908   *
1909   * @see set_transient()
1910   *
1911   * @param string $transient  Transient name. Expected to not be SQL-escaped. Must be
1912   *                           167 characters or fewer in length.
1913   * @param mixed  $value      Transient value. Expected to not be SQL-escaped.
1914   * @param int    $expiration Optional. Time until expiration in seconds. Default 0 (no expiration).
1915   * @return bool True if the value was set, false otherwise.
1916   */
1917  function set_site_transient( $transient, $value, $expiration = 0 ) {
1918  
1919      /**
1920       * Filters the value of a specific site transient before it is set.
1921       *
1922       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1923       *
1924       * @since 3.0.0
1925       * @since 4.4.0 The `$transient` parameter was added.
1926       *
1927       * @param mixed  $value     New value of site transient.
1928       * @param string $transient Transient name.
1929       */
1930      $value = apply_filters( "pre_set_site_transient_{$transient}", $value, $transient );
1931  
1932      $expiration = (int) $expiration;
1933  
1934      /**
1935       * Filters the expiration for a site transient before its value is set.
1936       *
1937       * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1938       *
1939       * @since 4.4.0
1940       *
1941       * @param int    $expiration Time until expiration in seconds. Use 0 for no expiration.
1942       * @param mixed  $value      New value of site transient.
1943       * @param string $transient  Transient name.
1944       */
1945      $expiration = apply_filters( "expiration_of_site_transient_{$transient}", $expiration, $value, $transient );
1946  
1947      if ( wp_using_ext_object_cache() ) {
1948          $result = wp_cache_set( $transient, $value, 'site-transient', $expiration );
1949      } else {
1950          $transient_timeout = '_site_transient_timeout_' . $transient;
1951          $option            = '_site_transient_' . $transient;
1952  
1953          if ( false === get_site_option( $option ) ) {
1954              if ( $expiration ) {
1955                  add_site_option( $transient_timeout, time() + $expiration );
1956              }
1957              $result = add_site_option( $option, $value );
1958          } else {
1959              if ( $expiration ) {
1960                  update_site_option( $transient_timeout, time() + $expiration );
1961              }
1962              $result = update_site_option( $option, $value );
1963          }
1964      }
1965  
1966      if ( $result ) {
1967  
1968          /**
1969           * Fires after the value for a specific site transient has been set.
1970           *
1971           * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1972           *
1973           * @since 3.0.0
1974           * @since 4.4.0 The `$transient` parameter was added
1975           *
1976           * @param mixed  $value      Site transient value.
1977           * @param int    $expiration Time until expiration in seconds.
1978           * @param string $transient  Transient name.
1979           */
1980          do_action( "set_site_transient_{$transient}", $value, $expiration, $transient );
1981  
1982          /**
1983           * Fires after the value for a site transient has been set.
1984           *
1985           * @since 3.0.0
1986           *
1987           * @param string $transient  The name of the site transient.
1988           * @param mixed  $value      Site transient value.
1989           * @param int    $expiration Time until expiration in seconds.
1990           */
1991          do_action( 'setted_site_transient', $transient, $value, $expiration );
1992      }
1993  
1994      return $result;
1995  }
1996  
1997  /**
1998   * Registers default settings available in WordPress.
1999   *
2000   * The settings registered here are primarily useful for the REST API, so this
2001   * does not encompass all settings available in WordPress.
2002   *
2003   * @since 4.7.0
2004   */
2005  function register_initial_settings() {
2006      register_setting(
2007          'general',
2008          'blogname',
2009          array(
2010              'show_in_rest' => array(
2011                  'name' => 'title',
2012              ),
2013              'type'         => 'string',
2014              'description'  => __( 'Site title.' ),
2015          )
2016      );
2017  
2018      register_setting(
2019          'general',
2020          'blogdescription',
2021          array(
2022              'show_in_rest' => array(
2023                  'name' => 'description',
2024              ),
2025              'type'         => 'string',
2026              'description'  => __( 'Site tagline.' ),
2027          )
2028      );
2029  
2030      if ( ! is_multisite() ) {
2031          register_setting(
2032              'general',
2033              'siteurl',
2034              array(
2035                  'show_in_rest' => array(
2036                      'name'   => 'url',
2037                      'schema' => array(
2038                          'format' => 'uri',
2039                      ),
2040                  ),
2041                  'type'         => 'string',
2042                  'description'  => __( 'Site URL.' ),
2043              )
2044          );
2045      }
2046  
2047      if ( ! is_multisite() ) {
2048          register_setting(
2049              'general',
2050              'admin_email',
2051              array(
2052                  'show_in_rest' => array(
2053                      'name'   => 'email',
2054                      'schema' => array(
2055                          'format' => 'email',
2056                      ),
2057                  ),
2058                  'type'         => 'string',
2059                  'description'  => __( 'This address is used for admin purposes, like new user notification.' ),
2060              )
2061          );
2062      }
2063  
2064      register_setting(
2065          'general',
2066          'timezone_string',
2067          array(
2068              'show_in_rest' => array(
2069                  'name' => 'timezone',
2070              ),
2071              'type'         => 'string',
2072              'description'  => __( 'A city in the same timezone as you.' ),
2073          )
2074      );
2075  
2076      register_setting(
2077          'general',
2078          'date_format',
2079          array(
2080              'show_in_rest' => true,
2081              'type'         => 'string',
2082              'description'  => __( 'A date format for all date strings.' ),
2083          )
2084      );
2085  
2086      register_setting(
2087          'general',
2088          'time_format',
2089          array(
2090              'show_in_rest' => true,
2091              'type'         => 'string',
2092              'description'  => __( 'A time format for all time strings.' ),
2093          )
2094      );
2095  
2096      register_setting(
2097          'general',
2098          'start_of_week',
2099          array(
2100              'show_in_rest' => true,
2101              'type'         => 'integer',
2102              'description'  => __( 'A day number of the week that the week should start on.' ),
2103          )
2104      );
2105  
2106      register_setting(
2107          'general',
2108          'WPLANG',
2109          array(
2110              'show_in_rest' => array(
2111                  'name' => 'language',
2112              ),
2113              'type'         => 'string',
2114              'description'  => __( 'WordPress locale code.' ),
2115              'default'      => 'en_US',
2116          )
2117      );
2118  
2119      register_setting(
2120          'writing',
2121          'use_smilies',
2122          array(
2123              'show_in_rest' => true,
2124              'type'         => 'boolean',
2125              'description'  => __( 'Convert emoticons like :-) and :-P to graphics on display.' ),
2126              'default'      => true,
2127          )
2128      );
2129  
2130      register_setting(
2131          'writing',
2132          'default_category',
2133          array(
2134              'show_in_rest' => true,
2135              'type'         => 'integer',
2136              'description'  => __( 'Default post category.' ),
2137          )
2138      );
2139  
2140      register_setting(
2141          'writing',
2142          'default_post_format',
2143          array(
2144              'show_in_rest' => true,
2145              'type'         => 'string',
2146              'description'  => __( 'Default post format.' ),
2147          )
2148      );
2149  
2150      register_setting(
2151          'reading',
2152          'posts_per_page',
2153          array(
2154              'show_in_rest' => true,
2155              'type'         => 'integer',
2156              'description'  => __( 'Blog pages show at most.' ),
2157              'default'      => 10,
2158          )
2159      );
2160  
2161      register_setting(
2162          'discussion',
2163          'default_ping_status',
2164          array(
2165              'show_in_rest' => array(
2166                  'schema' => array(
2167                      'enum' => array( 'open', 'closed' ),
2168                  ),
2169              ),
2170              'type'         => 'string',
2171              'description'  => __( 'Allow link notifications from other blogs (pingbacks and trackbacks) on new articles.' ),
2172          )
2173      );
2174  
2175      register_setting(
2176          'discussion',
2177          'default_comment_status',
2178          array(
2179              'show_in_rest' => array(
2180                  'schema' => array(
2181                      'enum' => array( 'open', 'closed' ),
2182                  ),
2183              ),
2184              'type'         => 'string',
2185              'description'  => __( 'Allow people to submit comments on new posts.' ),
2186          )
2187      );
2188  }
2189  
2190  /**
2191   * Registers a setting and its data.
2192   *
2193   * @since 2.7.0
2194   * @since 4.7.0 `$args` can be passed to set flags on the setting, similar to `register_meta()`.
2195   * @since 5.5.0 `$new_whitelist_options` was renamed to `$new_allowed_options`.
2196   *              Please consider writing more inclusive code.
2197   *
2198   * @global array $new_allowed_options
2199   * @global array $wp_registered_settings
2200   *
2201   * @param string $option_group A settings group name. Should correspond to an allowed option key name.
2202   *                             Default allowed option key names include 'general', 'discussion', 'media',
2203   *                             'reading', 'writing', 'misc', 'options', and 'privacy'.
2204   * @param string $option_name The name of an option to sanitize and save.
2205   * @param array  $args {
2206   *     Data used to describe the setting when registered.
2207   *
2208   *     @type string     $type              The type of data associated with this setting.
2209   *                                         Valid values are 'string', 'boolean', 'integer', 'number', 'array', and 'object'.
2210   *     @type string     $description       A description of the data attached to this setting.
2211   *     @type callable   $sanitize_callback A callback function that sanitizes the option's value.
2212   *     @type bool|array $show_in_rest      Whether data associated with this setting should be included in the REST API.
2213   *                                         When registering complex settings, this argument may optionally be an
2214   *                                         array with a 'schema' key.
2215   *     @type mixed      $default           Default value when calling `get_option()`.
2216   * }
2217   */
2218  function register_setting( $option_group, $option_name, $args = array() ) {
2219      global $new_allowed_options, $wp_registered_settings;
2220  
2221      /*
2222       * In 5.5.0, the `$new_whitelist_options` global variable was renamed to `$new_allowed_options`.
2223       * Please consider writing more inclusive code.
2224       */
2225      $GLOBALS['new_whitelist_options'] = &$new_allowed_options;
2226  
2227      $defaults = array(
2228          'type'              => 'string',
2229          'group'             => $option_group,
2230          'description'       => '',
2231          'sanitize_callback' => null,
2232          'show_in_rest'      => false,
2233      );
2234  
2235      // Back-compat: old sanitize callback is added.
2236      if ( is_callable( $args ) ) {
2237          $args = array(
2238              'sanitize_callback' => $args,
2239          );
2240      }
2241  
2242      /**
2243       * Filters the registration arguments when registering a setting.
2244       *
2245       * @since 4.7.0
2246       *
2247       * @param array  $args         Array of setting registration arguments.
2248       * @param array  $defaults     Array of default arguments.
2249       * @param string $option_group Setting group.
2250       * @param string $option_name  Setting name.
2251       */
2252      $args = apply_filters( 'register_setting_args', $args, $defaults, $option_group, $option_name );
2253  
2254      $args = wp_parse_args( $args, $defaults );
2255  
2256      // Require an item schema when registering settings with an array type.
2257      if ( false !== $args['show_in_rest'] && 'array' === $args['type'] && ( ! is_array( $args['show_in_rest'] ) || ! isset( $args['show_in_rest']['schema']['items'] ) ) ) {
2258          _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' );
2259      }
2260  
2261      if ( ! is_array( $wp_registered_settings ) ) {
2262          $wp_registered_settings = array();
2263      }
2264  
2265      if ( 'misc' === $option_group ) {
2266          _deprecated_argument(
2267              __FUNCTION__,
2268              '3.0.0',
2269              sprintf(
2270                  /* translators: %s: misc */
2271                  __( 'The "%s" options group has been removed. Use another settings group.' ),
2272                  'misc'
2273              )
2274          );
2275          $option_group = 'general';
2276      }
2277  
2278      if ( 'privacy' === $option_group ) {
2279          _deprecated_argument(
2280              __FUNCTION__,
2281              '3.5.0',
2282              sprintf(
2283                  /* translators: %s: privacy */
2284                  __( 'The "%s" options group has been removed. Use another settings group.' ),
2285                  'privacy'
2286              )
2287          );
2288          $option_group = 'reading';
2289      }
2290  
2291      $new_allowed_options[ $option_group ][] = $option_name;
2292  
2293      if ( ! empty( $args['sanitize_callback'] ) ) {
2294          add_filter( "sanitize_option_{$option_name}", $args['sanitize_callback'] );
2295      }
2296      if ( array_key_exists( 'default', $args ) ) {
2297          add_filter( "default_option_{$option_name}", 'filter_default_option', 10, 3 );
2298      }
2299  
2300      /**
2301       * Fires immediately before the setting is registered but after its filters are in place.
2302       *
2303       * @since 5.5.0
2304       *
2305       * @param string $option_group Setting group.
2306       * @param string $option_name  Setting name.
2307       * @param array  $args         Array of setting registration arguments.
2308       */
2309      do_action( 'register_setting', $option_group, $option_name, $args );
2310  
2311      $wp_registered_settings[ $option_name ] = $args;
2312  }
2313  
2314  /**
2315   * Unregisters a setting.
2316   *
2317   * @since 2.7.0
2318   * @since 4.7.0 `$sanitize_callback` was deprecated. The callback from `register_setting()` is now used instead.
2319   * @since 5.5.0 `$new_whitelist_options` was renamed to `$new_allowed_options`.
2320   *              Please consider writing more inclusive code.
2321   *
2322   * @global array $new_allowed_options
2323   * @global array $wp_registered_settings
2324   *
2325   * @param string   $option_group The settings group name used during registration.
2326   * @param string   $option_name  The name of the option to unregister.
2327   * @param callable $deprecated   Deprecated.
2328   */
2329  function unregister_setting( $option_group, $option_name, $deprecated = '' ) {
2330      global $new_allowed_options, $wp_registered_settings;
2331  
2332      /*
2333       * In 5.5.0, the `$new_whitelist_options` global variable was renamed to `$new_allowed_options`.
2334       * Please consider writing more inclusive code.
2335       */
2336      $GLOBALS['new_whitelist_options'] = &$new_allowed_options;
2337  
2338      if ( 'misc' === $option_group ) {
2339          _deprecated_argument(
2340              __FUNCTION__,
2341              '3.0.0',
2342              sprintf(
2343                  /* translators: %s: misc */
2344                  __( 'The "%s" options group has been removed. Use another settings group.' ),
2345                  'misc'
2346              )
2347          );
2348          $option_group = 'general';
2349      }
2350  
2351      if ( 'privacy' === $option_group ) {
2352          _deprecated_argument(
2353              __FUNCTION__,
2354              '3.5.0',
2355              sprintf(
2356                  /* translators: %s: privacy */
2357                  __( 'The "%s" options group has been removed. Use another settings group.' ),
2358                  'privacy'
2359              )
2360          );
2361          $option_group = 'reading';
2362      }
2363  
2364      $pos = array_search( $option_name, (array) $new_allowed_options[ $option_group ], true );
2365  
2366      if ( false !== $pos ) {
2367          unset( $new_allowed_options[ $option_group ][ $pos ] );
2368      }
2369  
2370      if ( '' !== $deprecated ) {
2371          _deprecated_argument(
2372              __FUNCTION__,
2373              '4.7.0',
2374              sprintf(
2375                  /* translators: 1: $sanitize_callback, 2: register_setting() */
2376                  __( '%1$s is deprecated. The callback from %2$s is used instead.' ),
2377                  '<code>$sanitize_callback</code>',
2378                  '<code>register_setting()</code>'
2379              )
2380          );
2381          remove_filter( "sanitize_option_{$option_name}", $deprecated );
2382      }
2383  
2384      if ( isset( $wp_registered_settings[ $option_name ] ) ) {
2385          // Remove the sanitize callback if one was set during registration.
2386          if ( ! empty( $wp_registered_settings[ $option_name ]['sanitize_callback'] ) ) {
2387              remove_filter( "sanitize_option_{$option_name}", $wp_registered_settings[ $option_name ]['sanitize_callback'] );
2388          }
2389  
2390          // Remove the default filter if a default was provided during registration.
2391          if ( array_key_exists( 'default', $wp_registered_settings[ $option_name ] ) ) {
2392              remove_filter( "default_option_{$option_name}", 'filter_default_option', 10 );
2393          }
2394  
2395          /**
2396           * Fires immediately before the setting is unregistered and after its filters have been removed.
2397           *
2398           * @since 5.5.0
2399           *
2400           * @param string $option_group Setting group.
2401           * @param string $option_name  Setting name.
2402           */
2403          do_action( 'unregister_setting', $option_group, $option_name );
2404  
2405          unset( $wp_registered_settings[ $option_name ] );
2406      }
2407  }
2408  
2409  /**
2410   * Retrieves an array of registered settings.
2411   *
2412   * @since 4.7.0
2413   *
2414   * @global array $wp_registered_settings
2415   *
2416   * @return array List of registered settings, keyed by option name.
2417   */
2418  function get_registered_settings() {
2419      global $wp_registered_settings;
2420  
2421      if ( ! is_array( $wp_registered_settings ) ) {
2422          return array();
2423      }
2424  
2425      return $wp_registered_settings;
2426  }
2427  
2428  /**
2429   * Filters the default value for the option.
2430   *
2431   * For settings which register a default setting in `register_setting()`, this
2432   * function is added as a filter to `default_option_{$option}`.
2433   *
2434   * @since 4.7.0
2435   *
2436   * @param mixed  $default        Existing default value to return.
2437   * @param string $option         Option name.
2438   * @param bool   $passed_default Was `get_option()` passed a default value?
2439   * @return mixed Filtered default value.
2440   */
2441  function filter_default_option( $default, $option, $passed_default ) {
2442      if ( $passed_default ) {
2443          return $default;
2444      }
2445  
2446      $registered = get_registered_settings();
2447      if ( empty( $registered[ $option ] ) ) {
2448          return $default;
2449      }
2450  
2451      return $registered[ $option ]['default'];
2452  }


Generated: Fri Oct 30 01:00:03 2020 Cross-referenced by PHPXref 0.7.1