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