Make WordPress Core

Ticket #43360: option.php

File option.php, 66.3 KB (added by farhan.noor, 7 years ago)

Patch

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