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