Issues (4967)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/wp-includes/option.php (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Option API
4
 *
5
 * @package WordPress
6
 * @subpackage Option
7
 */
8
9
/**
10
 * Retrieves an option value based on an option name.
11
 *
12
 * If the option does not exist or does not have a value, then the return value
13
 * will be false. This is useful to check whether you need to install an option
14
 * and is commonly used during installation of plugin options and to test
15
 * whether upgrading is required.
16
 *
17
 * If the option was serialized then it will be unserialized when it is returned.
18
 *
19
 * Any scalar values will be returned as strings. You may coerce the return type of
20
 * a given option by registering an {@see 'option_$option'} filter callback.
21
 *
22
 * @since 1.5.0
23
 *
24
 * @global wpdb $wpdb WordPress database abstraction object.
25
 *
26
 * @param string $option  Name of option to retrieve. Expected to not be SQL-escaped.
27
 * @param mixed  $default Optional. Default value to return if the option does not exist.
28
 * @return mixed Value set for the option.
29
 */
30
function get_option( $option, $default = false ) {
31
	global $wpdb;
32
33
	$option = trim( $option );
34
	if ( empty( $option ) )
35
		return false;
36
37
	/**
38
	 * Filters the value of an existing option before it is retrieved.
39
	 *
40
	 * The dynamic portion of the hook name, `$option`, refers to the option name.
41
	 *
42
	 * Passing a truthy value to the filter will short-circuit retrieving
43
	 * the option value, returning the passed value instead.
44
	 *
45
	 * @since 1.5.0
46
	 * @since 4.4.0 The `$option` parameter was added.
47
	 *
48
	 * @param bool|mixed $pre_option Value to return instead of the option value.
49
	 *                               Default false to skip it.
50
	 * @param string     $option     Option name.
51
	 */
52
	$pre = apply_filters( "pre_option_{$option}", false, $option );
53
	if ( false !== $pre )
54
		return $pre;
55
56
	if ( defined( 'WP_SETUP_CONFIG' ) )
57
		return false;
58
59
	// Distinguish between `false` as a default, and not passing one.
60
	$passed_default = func_num_args() > 1;
61
62
	if ( ! wp_installing() ) {
63
		// prevent non-existent options from triggering multiple queries
64
		$notoptions = wp_cache_get( 'notoptions', 'options' );
65
		if ( isset( $notoptions[ $option ] ) ) {
66
			/**
67
			 * Filters the default value for an option.
68
			 *
69
			 * The dynamic portion of the hook name, `$option`, refers to the option name.
70
			 *
71
			 * @since 3.4.0
72
			 * @since 4.4.0 The `$option` parameter was added.
73
			 * @since 4.7.0 The `$passed_default` parameter was added to distinguish between a `false` value and the default parameter value.
74
			 *
75
			 * @param mixed  $default The default value to return if the option does not exist
76
			 *                        in the database.
77
			 * @param string $option  Option name.
78
			 * @param bool   $passed_default Was `get_option()` passed a default value?
79
			 */
80
			return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
81
		}
82
83
		$alloptions = wp_load_alloptions();
84
85
		if ( isset( $alloptions[$option] ) ) {
86
			$value = $alloptions[$option];
87
		} else {
88
			$value = wp_cache_get( $option, 'options' );
89
90
			if ( false === $value ) {
91
				$row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
92
93
				// Has to be get_row instead of get_var because of funkiness with 0, false, null values
94
				if ( is_object( $row ) ) {
95
					$value = $row->option_value;
96
					wp_cache_add( $option, $value, 'options' );
97 View Code Duplication
				} else { // option does not exist, so we must cache its non-existence
98
					if ( ! is_array( $notoptions ) ) {
99
						 $notoptions = array();
100
					}
101
					$notoptions[$option] = true;
102
					wp_cache_set( 'notoptions', $notoptions, 'options' );
103
104
					/** This filter is documented in wp-includes/option.php */
105
					return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
106
				}
107
			}
108
		}
109
	} else {
110
		$suppress = $wpdb->suppress_errors();
111
		$row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
112
		$wpdb->suppress_errors( $suppress );
113
		if ( is_object( $row ) ) {
114
			$value = $row->option_value;
115
		} else {
116
			/** This filter is documented in wp-includes/option.php */
117
			return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
118
		}
119
	}
120
121
	// If home is not set use siteurl.
122
	if ( 'home' == $option && '' == $value )
123
		return get_option( 'siteurl' );
124
125
	if ( in_array( $option, array('siteurl', 'home', 'category_base', 'tag_base') ) )
126
		$value = untrailingslashit( $value );
127
128
	/**
129
	 * Filters the value of an existing option.
130
	 *
131
	 * The dynamic portion of the hook name, `$option`, refers to the option name.
132
	 *
133
	 * @since 1.5.0 As 'option_' . $setting
134
	 * @since 3.0.0
135
	 * @since 4.4.0 The `$option` parameter was added.
136
	 *
137
	 * @param mixed  $value  Value of the option. If stored serialized, it will be
138
	 *                       unserialized prior to being returned.
139
	 * @param string $option Option name.
140
	 */
141
	return apply_filters( "option_{$option}", maybe_unserialize( $value ), $option );
142
}
143
144
/**
145
 * Protect WordPress special option from being modified.
146
 *
147
 * Will die if $option is in protected list. Protected options are 'alloptions'
148
 * and 'notoptions' options.
149
 *
150
 * @since 2.2.0
151
 *
152
 * @param string $option Option name.
153
 */
154
function wp_protect_special_option( $option ) {
155
	if ( 'alloptions' === $option || 'notoptions' === $option )
156
		wp_die( sprintf( __( '%s is a protected WP option and may not be modified' ), esc_html( $option ) ) );
157
}
158
159
/**
160
 * Print option value after sanitizing for forms.
161
 *
162
 * @since 1.5.0
163
 *
164
 * @param string $option Option name.
165
 */
166
function form_option( $option ) {
167
	echo esc_attr( get_option( $option ) );
168
}
169
170
/**
171
 * Loads and caches all autoloaded options, if available or all options.
172
 *
173
 * @since 2.2.0
174
 *
175
 * @global wpdb $wpdb WordPress database abstraction object.
176
 *
177
 * @return array List of all options.
178
 */
179
function wp_load_alloptions() {
180
	global $wpdb;
181
182
	if ( ! wp_installing() || ! is_multisite() )
183
		$alloptions = wp_cache_get( 'alloptions', 'options' );
184
	else
185
		$alloptions = false;
186
187
	if ( !$alloptions ) {
188
		$suppress = $wpdb->suppress_errors();
189
		if ( !$alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE autoload = 'yes'" ) )
190
			$alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" );
191
		$wpdb->suppress_errors($suppress);
192
		$alloptions = array();
193
		foreach ( (array) $alloptions_db as $o ) {
194
			$alloptions[$o->option_name] = $o->option_value;
195
		}
196
		if ( ! wp_installing() || ! is_multisite() )
197
			wp_cache_add( 'alloptions', $alloptions, 'options' );
198
	}
199
200
	return $alloptions;
201
}
202
203
/**
204
 * Loads and caches certain often requested site options if is_multisite() and a persistent cache is not being used.
205
 *
206
 * @since 3.0.0
207
 *
208
 * @global wpdb $wpdb WordPress database abstraction object.
209
 *
210
 * @param int $site_id Optional site ID for which to query the options. Defaults to the current site.
211
 */
212
function wp_load_core_site_options( $site_id = null ) {
213
	global $wpdb;
214
215
	if ( ! is_multisite() || wp_using_ext_object_cache() || wp_installing() )
216
		return;
217
218
	if ( empty($site_id) )
219
		$site_id = $wpdb->siteid;
220
221
	$core_options = array('site_name', 'siteurl', 'active_sitewide_plugins', '_site_transient_timeout_theme_roots', '_site_transient_theme_roots', 'site_admins', 'can_compress_scripts', 'global_terms_enabled', 'ms_files_rewriting' );
222
223
	$core_options_in = "'" . implode("', '", $core_options) . "'";
224
	$options = $wpdb->get_results( $wpdb->prepare("SELECT meta_key, meta_value FROM $wpdb->sitemeta WHERE meta_key IN ($core_options_in) AND site_id = %d", $site_id) );
225
226
	foreach ( $options as $option ) {
227
		$key = $option->meta_key;
228
		$cache_key = "{$site_id}:$key";
229
		$option->meta_value = maybe_unserialize( $option->meta_value );
230
231
		wp_cache_set( $cache_key, $option->meta_value, 'site-options' );
232
	}
233
}
234
235
/**
236
 * Update the value of an option that was already added.
237
 *
238
 * You do not need to serialize values. If the value needs to be serialized, then
239
 * it will be serialized before it is inserted into the database. Remember,
240
 * resources can not be serialized or added as an option.
241
 *
242
 * If the option does not exist, then the option will be added with the option value,
243
 * with an `$autoload` value of 'yes'.
244
 *
245
 * @since 1.0.0
246
 * @since 4.2.0 The `$autoload` parameter was added.
247
 *
248
 * @global wpdb $wpdb WordPress database abstraction object.
249
 *
250
 * @param string      $option   Option name. Expected to not be SQL-escaped.
251
 * @param mixed       $value    Option value. Must be serializable if non-scalar. Expected to not be SQL-escaped.
252
 * @param string|bool $autoload Optional. Whether to load the option when WordPress starts up. For existing options,
253
 *                              `$autoload` can only be updated using `update_option()` if `$value` is also changed.
254
 *                              Accepts 'yes'|true to enable or 'no'|false to disable. For non-existent options,
255
 *                              the default value is 'yes'. Default null.
256
 * @return bool False if value was not updated and true if value was updated.
257
 */
258
function update_option( $option, $value, $autoload = null ) {
259
	global $wpdb;
260
261
	$option = trim($option);
262
	if ( empty($option) )
263
		return false;
264
265
	wp_protect_special_option( $option );
266
267
	if ( is_object( $value ) )
268
		$value = clone $value;
269
270
	$value = sanitize_option( $option, $value );
271
	$old_value = get_option( $option );
272
273
	/**
274
	 * Filters a specific option before its value is (maybe) serialized and updated.
275
	 *
276
	 * The dynamic portion of the hook name, `$option`, refers to the option name.
277
	 *
278
	 * @since 2.6.0
279
	 * @since 4.4.0 The `$option` parameter was added.
280
	 *
281
	 * @param mixed  $value     The new, unserialized option value.
282
	 * @param mixed  $old_value The old option value.
283
	 * @param string $option    Option name.
284
	 */
285
	$value = apply_filters( "pre_update_option_{$option}", $value, $old_value, $option );
286
287
	/**
288
	 * Filters an option before its value is (maybe) serialized and updated.
289
	 *
290
	 * @since 3.9.0
291
	 *
292
	 * @param mixed  $value     The new, unserialized option value.
293
	 * @param string $option    Name of the option.
294
	 * @param mixed  $old_value The old option value.
295
	 */
296
	$value = apply_filters( 'pre_update_option', $value, $option, $old_value );
297
298
	/*
299
	 * If the new and old values are the same, no need to update.
300
	 *
301
	 * Unserialized values will be adequate in most cases. If the unserialized
302
	 * data differs, the (maybe) serialized data is checked to avoid
303
	 * unnecessary database calls for otherwise identical object instances.
304
	 *
305
	 * See https://core.trac.wordpress.org/ticket/38903
306
	 */
307
	if ( $value === $old_value || maybe_serialize( $value ) === maybe_serialize( $old_value ) ) {
308
		return false;
309
	}
310
311
	/** This filter is documented in wp-includes/option.php */
312
	if ( apply_filters( "default_option_{$option}", false, $option, false ) === $old_value ) {
313
		// Default setting for new options is 'yes'.
314
		if ( null === $autoload ) {
315
			$autoload = 'yes';
316
		}
317
318
		return add_option( $option, $value, '', $autoload );
319
	}
320
321
	$serialized_value = maybe_serialize( $value );
322
323
	/**
324
	 * Fires immediately before an option value is updated.
325
	 *
326
	 * @since 2.9.0
327
	 *
328
	 * @param string $option    Name of the option to update.
329
	 * @param mixed  $old_value The old option value.
330
	 * @param mixed  $value     The new option value.
331
	 */
332
	do_action( 'update_option', $option, $old_value, $value );
333
334
	$update_args = array(
335
		'option_value' => $serialized_value,
336
	);
337
338
	if ( null !== $autoload ) {
339
		$update_args['autoload'] = ( 'no' === $autoload || false === $autoload ) ? 'no' : 'yes';
340
	}
341
342
	$result = $wpdb->update( $wpdb->options, $update_args, array( 'option_name' => $option ) );
343
	if ( ! $result )
344
		return false;
345
346
	$notoptions = wp_cache_get( 'notoptions', 'options' );
347
	if ( is_array( $notoptions ) && isset( $notoptions[$option] ) ) {
348
		unset( $notoptions[$option] );
349
		wp_cache_set( 'notoptions', $notoptions, 'options' );
350
	}
351
352 View Code Duplication
	if ( ! wp_installing() ) {
353
		$alloptions = wp_load_alloptions();
354
		if ( isset( $alloptions[$option] ) ) {
355
			$alloptions[ $option ] = $serialized_value;
356
			wp_cache_set( 'alloptions', $alloptions, 'options' );
357
		} else {
358
			wp_cache_set( $option, $serialized_value, 'options' );
359
		}
360
	}
361
362
	/**
363
	 * Fires after the value of a specific option has been successfully updated.
364
	 *
365
	 * The dynamic portion of the hook name, `$option`, refers to the option name.
366
	 *
367
	 * @since 2.0.1
368
	 * @since 4.4.0 The `$option` parameter was added.
369
	 *
370
	 * @param mixed  $old_value The old option value.
371
	 * @param mixed  $value     The new option value.
372
	 * @param string $option    Option name.
373
	 */
374
	do_action( "update_option_{$option}", $old_value, $value, $option );
375
376
	/**
377
	 * Fires after the value of an option has been successfully updated.
378
	 *
379
	 * @since 2.9.0
380
	 *
381
	 * @param string $option    Name of the updated option.
382
	 * @param mixed  $old_value The old option value.
383
	 * @param mixed  $value     The new option value.
384
	 */
385
	do_action( 'updated_option', $option, $old_value, $value );
386
	return true;
387
}
388
389
/**
390
 * Add a new option.
391
 *
392
 * You do not need to serialize values. If the value needs to be serialized, then
393
 * it will be serialized before it is inserted into the database. Remember,
394
 * resources can not be serialized or added as an option.
395
 *
396
 * You can create options without values and then update the values later.
397
 * Existing options will not be updated and checks are performed to ensure that you
398
 * aren't adding a protected WordPress option. Care should be taken to not name
399
 * options the same as the ones which are protected.
400
 *
401
 * @since 1.0.0
402
 *
403
 * @global wpdb $wpdb WordPress database abstraction object.
404
 *
405
 * @param string         $option      Name of option to add. Expected to not be SQL-escaped.
406
 * @param mixed          $value       Optional. Option value. Must be serializable if non-scalar. Expected to not be SQL-escaped.
407
 * @param string         $deprecated  Optional. Description. Not used anymore.
408
 * @param string|bool    $autoload    Optional. Whether to load the option when WordPress starts up.
409
 *                                    Default is enabled. Accepts 'no' to disable for legacy reasons.
410
 * @return bool False if option was not added and true if option was added.
411
 */
412
function add_option( $option, $value = '', $deprecated = '', $autoload = 'yes' ) {
413
	global $wpdb;
414
415
	if ( !empty( $deprecated ) )
416
		_deprecated_argument( __FUNCTION__, '2.3.0' );
417
418
	$option = trim($option);
419
	if ( empty($option) )
420
		return false;
421
422
	wp_protect_special_option( $option );
423
424
	if ( is_object($value) )
425
		$value = clone $value;
426
427
	$value = sanitize_option( $option, $value );
428
429
	// Make sure the option doesn't already exist. We can check the 'notoptions' cache before we ask for a db query
430
	$notoptions = wp_cache_get( 'notoptions', 'options' );
431 View Code Duplication
	if ( !is_array( $notoptions ) || !isset( $notoptions[$option] ) )
432
		/** This filter is documented in wp-includes/option.php */
433
		if ( apply_filters( "default_option_{$option}", false, $option, false ) !== get_option( $option ) )
434
			return false;
435
436
	$serialized_value = maybe_serialize( $value );
437
	$autoload = ( 'no' === $autoload || false === $autoload ) ? 'no' : 'yes';
438
439
	/**
440
	 * Fires before an option is added.
441
	 *
442
	 * @since 2.9.0
443
	 *
444
	 * @param string $option Name of the option to add.
445
	 * @param mixed  $value  Value of the option.
446
	 */
447
	do_action( 'add_option', $option, $value );
448
449
	$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 ) );
450
	if ( ! $result )
451
		return false;
452
453 View Code Duplication
	if ( ! wp_installing() ) {
454
		if ( 'yes' == $autoload ) {
455
			$alloptions = wp_load_alloptions();
456
			$alloptions[ $option ] = $serialized_value;
457
			wp_cache_set( 'alloptions', $alloptions, 'options' );
458
		} else {
459
			wp_cache_set( $option, $serialized_value, 'options' );
460
		}
461
	}
462
463
	// This option exists now
464
	$notoptions = wp_cache_get( 'notoptions', 'options' ); // yes, again... we need it to be fresh
465
	if ( is_array( $notoptions ) && isset( $notoptions[$option] ) ) {
466
		unset( $notoptions[$option] );
467
		wp_cache_set( 'notoptions', $notoptions, 'options' );
468
	}
469
470
	/**
471
	 * Fires after a specific option has been added.
472
	 *
473
	 * The dynamic portion of the hook name, `$option`, refers to the option name.
474
	 *
475
	 * @since 2.5.0 As "add_option_{$name}"
476
	 * @since 3.0.0
477
	 *
478
	 * @param string $option Name of the option to add.
479
	 * @param mixed  $value  Value of the option.
480
	 */
481
	do_action( "add_option_{$option}", $option, $value );
482
483
	/**
484
	 * Fires after an option has been added.
485
	 *
486
	 * @since 2.9.0
487
	 *
488
	 * @param string $option Name of the added option.
489
	 * @param mixed  $value  Value of the option.
490
	 */
491
	do_action( 'added_option', $option, $value );
492
	return true;
493
}
494
495
/**
496
 * Removes option by name. Prevents removal of protected WordPress options.
497
 *
498
 * @since 1.2.0
499
 *
500
 * @global wpdb $wpdb WordPress database abstraction object.
501
 *
502
 * @param string $option Name of option to remove. Expected to not be SQL-escaped.
503
 * @return bool True, if option is successfully deleted. False on failure.
504
 */
505
function delete_option( $option ) {
506
	global $wpdb;
507
508
	$option = trim( $option );
509
	if ( empty( $option ) )
510
		return false;
511
512
	wp_protect_special_option( $option );
513
514
	// Get the ID, if no ID then return
515
	$row = $wpdb->get_row( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s", $option ) );
516
	if ( is_null( $row ) )
517
		return false;
518
519
	/**
520
	 * Fires immediately before an option is deleted.
521
	 *
522
	 * @since 2.9.0
523
	 *
524
	 * @param string $option Name of the option to delete.
525
	 */
526
	do_action( 'delete_option', $option );
527
528
	$result = $wpdb->delete( $wpdb->options, array( 'option_name' => $option ) );
529 View Code Duplication
	if ( ! wp_installing() ) {
530
		if ( 'yes' == $row->autoload ) {
531
			$alloptions = wp_load_alloptions();
532
			if ( is_array( $alloptions ) && isset( $alloptions[$option] ) ) {
533
				unset( $alloptions[$option] );
534
				wp_cache_set( 'alloptions', $alloptions, 'options' );
535
			}
536
		} else {
537
			wp_cache_delete( $option, 'options' );
538
		}
539
	}
540
	if ( $result ) {
541
542
		/**
543
		 * Fires after a specific option has been deleted.
544
		 *
545
		 * The dynamic portion of the hook name, `$option`, refers to the option name.
546
		 *
547
		 * @since 3.0.0
548
		 *
549
		 * @param string $option Name of the deleted option.
550
		 */
551
		do_action( "delete_option_{$option}", $option );
552
553
		/**
554
		 * Fires after an option has been deleted.
555
		 *
556
		 * @since 2.9.0
557
		 *
558
		 * @param string $option Name of the deleted option.
559
		 */
560
		do_action( 'deleted_option', $option );
561
		return true;
562
	}
563
	return false;
564
}
565
566
/**
567
 * Delete a transient.
568
 *
569
 * @since 2.8.0
570
 *
571
 * @param string $transient Transient name. Expected to not be SQL-escaped.
572
 * @return bool true if successful, false otherwise
573
 */
574 View Code Duplication
function delete_transient( $transient ) {
0 ignored issues
show
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
575
576
	/**
577
	 * Fires immediately before a specific transient is deleted.
578
	 *
579
	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
580
	 *
581
	 * @since 3.0.0
582
	 *
583
	 * @param string $transient Transient name.
584
	 */
585
	do_action( "delete_transient_{$transient}", $transient );
586
587
	if ( wp_using_ext_object_cache() ) {
588
		$result = wp_cache_delete( $transient, 'transient' );
589
	} else {
590
		$option_timeout = '_transient_timeout_' . $transient;
591
		$option = '_transient_' . $transient;
592
		$result = delete_option( $option );
593
		if ( $result )
594
			delete_option( $option_timeout );
595
	}
596
597
	if ( $result ) {
598
599
		/**
600
		 * Fires after a transient is deleted.
601
		 *
602
		 * @since 3.0.0
603
		 *
604
		 * @param string $transient Deleted transient name.
605
		 */
606
		do_action( 'deleted_transient', $transient );
607
	}
608
609
	return $result;
610
}
611
612
/**
613
 * Get the value of a transient.
614
 *
615
 * If the transient does not exist, does not have a value, or has expired,
616
 * then the return value will be false.
617
 *
618
 * @since 2.8.0
619
 *
620
 * @param string $transient Transient name. Expected to not be SQL-escaped.
621
 * @return mixed Value of transient.
622
 */
623
function get_transient( $transient ) {
624
625
	/**
626
	 * Filters the value of an existing transient.
627
	 *
628
	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
629
	 *
630
	 * Passing a truthy value to the filter will effectively short-circuit retrieval
631
	 * of the transient, returning the passed value instead.
632
	 *
633
	 * @since 2.8.0
634
	 * @since 4.4.0 The `$transient` parameter was added
635
	 *
636
	 * @param mixed  $pre_transient The default value to return if the transient does not exist.
637
	 *                              Any value other than false will short-circuit the retrieval
638
	 *                              of the transient, and return the returned value.
639
	 * @param string $transient     Transient name.
640
	 */
641
	$pre = apply_filters( "pre_transient_{$transient}", false, $transient );
642
	if ( false !== $pre )
643
		return $pre;
644
645
	if ( wp_using_ext_object_cache() ) {
646
		$value = wp_cache_get( $transient, 'transient' );
647
	} else {
648
		$transient_option = '_transient_' . $transient;
649
		if ( ! wp_installing() ) {
650
			// If option is not in alloptions, it is not autoloaded and thus has a timeout
651
			$alloptions = wp_load_alloptions();
652 View Code Duplication
			if ( !isset( $alloptions[$transient_option] ) ) {
653
				$transient_timeout = '_transient_timeout_' . $transient;
654
				$timeout = get_option( $transient_timeout );
655
				if ( false !== $timeout && $timeout < time() ) {
656
					delete_option( $transient_option  );
657
					delete_option( $transient_timeout );
658
					$value = false;
659
				}
660
			}
661
		}
662
663
		if ( ! isset( $value ) )
664
			$value = get_option( $transient_option );
665
	}
666
667
	/**
668
	 * Filters an existing transient's value.
669
	 *
670
	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
671
	 *
672
	 * @since 2.8.0
673
	 * @since 4.4.0 The `$transient` parameter was added
674
	 *
675
	 * @param mixed  $value     Value of transient.
676
	 * @param string $transient Transient name.
677
	 */
678
	return apply_filters( "transient_{$transient}", $value, $transient );
679
}
680
681
/**
682
 * Set/update the value of a transient.
683
 *
684
 * You do not need to serialize values. If the value needs to be serialized, then
685
 * it will be serialized before it is set.
686
 *
687
 * @since 2.8.0
688
 *
689
 * @param string $transient  Transient name. Expected to not be SQL-escaped. Must be
690
 *                           172 characters or fewer in length.
691
 * @param mixed  $value      Transient value. Must be serializable if non-scalar.
692
 *                           Expected to not be SQL-escaped.
693
 * @param int    $expiration Optional. Time until expiration in seconds. Default 0 (no expiration).
694
 * @return bool False if value was not set and true if value was set.
695
 */
696
function set_transient( $transient, $value, $expiration = 0 ) {
697
698
	$expiration = (int) $expiration;
699
700
	/**
701
	 * Filters a specific transient before its value is set.
702
	 *
703
	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
704
	 *
705
	 * @since 3.0.0
706
	 * @since 4.2.0 The `$expiration` parameter was added.
707
	 * @since 4.4.0 The `$transient` parameter was added.
708
	 *
709
	 * @param mixed  $value      New value of transient.
710
	 * @param int    $expiration Time until expiration in seconds.
711
	 * @param string $transient  Transient name.
712
	 */
713
	$value = apply_filters( "pre_set_transient_{$transient}", $value, $expiration, $transient );
714
715
	/**
716
	 * Filters the expiration for a transient before its value is set.
717
	 *
718
	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
719
	 *
720
	 * @since 4.4.0
721
	 *
722
	 * @param int    $expiration Time until expiration in seconds. Use 0 for no expiration.
723
	 * @param mixed  $value      New value of transient.
724
	 * @param string $transient  Transient name.
725
	 */
726
	$expiration = apply_filters( "expiration_of_transient_{$transient}", $expiration, $value, $transient );
727
728
	if ( wp_using_ext_object_cache() ) {
729
		$result = wp_cache_set( $transient, $value, 'transient', $expiration );
730
	} else {
731
		$transient_timeout = '_transient_timeout_' . $transient;
732
		$transient_option = '_transient_' . $transient;
733
		if ( false === get_option( $transient_option ) ) {
734
			$autoload = 'yes';
735
			if ( $expiration ) {
736
				$autoload = 'no';
737
				add_option( $transient_timeout, time() + $expiration, '', 'no' );
738
			}
739
			$result = add_option( $transient_option, $value, '', $autoload );
740
		} else {
741
			// If expiration is requested, but the transient has no timeout option,
742
			// delete, then re-create transient rather than update.
743
			$update = true;
744
			if ( $expiration ) {
745
				if ( false === get_option( $transient_timeout ) ) {
746
					delete_option( $transient_option );
747
					add_option( $transient_timeout, time() + $expiration, '', 'no' );
748
					$result = add_option( $transient_option, $value, '', 'no' );
749
					$update = false;
750
				} else {
751
					update_option( $transient_timeout, time() + $expiration );
752
				}
753
			}
754
			if ( $update ) {
755
				$result = update_option( $transient_option, $value );
756
			}
757
		}
758
	}
759
760
	if ( $result ) {
0 ignored issues
show
The variable $result does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
761
762
		/**
763
		 * Fires after the value for a specific transient has been set.
764
		 *
765
		 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
766
		 *
767
		 * @since 3.0.0
768
		 * @since 3.6.0 The `$value` and `$expiration` parameters were added.
769
		 * @since 4.4.0 The `$transient` parameter was added.
770
		 *
771
		 * @param mixed  $value      Transient value.
772
		 * @param int    $expiration Time until expiration in seconds.
773
		 * @param string $transient  The name of the transient.
774
		 */
775
		do_action( "set_transient_{$transient}", $value, $expiration, $transient );
776
777
		/**
778
		 * Fires after the value for a transient has been set.
779
		 *
780
		 * @since 3.0.0
781
		 * @since 3.6.0 The `$value` and `$expiration` parameters were added.
782
		 *
783
		 * @param string $transient  The name of the transient.
784
		 * @param mixed  $value      Transient value.
785
		 * @param int    $expiration Time until expiration in seconds.
786
		 */
787
		do_action( 'setted_transient', $transient, $value, $expiration );
788
	}
789
	return $result;
790
}
791
792
/**
793
 * Saves and restores user interface settings stored in a cookie.
794
 *
795
 * Checks if the current user-settings cookie is updated and stores it. When no
796
 * cookie exists (different browser used), adds the last saved cookie restoring
797
 * the settings.
798
 *
799
 * @since 2.7.0
800
 */
801
function wp_user_settings() {
802
803
	if ( ! is_admin() || wp_doing_ajax() ) {
804
		return;
805
	}
806
807
	if ( ! $user_id = get_current_user_id() ) {
808
		return;
809
	}
810
811
	if ( ! is_user_member_of_blog() ) {
812
		return;
813
	}
814
815
	$settings = (string) get_user_option( 'user-settings', $user_id );
816
817
	if ( isset( $_COOKIE['wp-settings-' . $user_id] ) ) {
818
		$cookie = preg_replace( '/[^A-Za-z0-9=&_]/', '', $_COOKIE['wp-settings-' . $user_id] );
819
820
		// No change or both empty
821
		if ( $cookie == $settings )
822
			return;
823
824
		$last_saved = (int) get_user_option( 'user-settings-time', $user_id );
825
		$current = isset( $_COOKIE['wp-settings-time-' . $user_id]) ? preg_replace( '/[^0-9]/', '', $_COOKIE['wp-settings-time-' . $user_id] ) : 0;
826
827
		// The cookie is newer than the saved value. Update the user_option and leave the cookie as-is
828
		if ( $current > $last_saved ) {
829
			update_user_option( $user_id, 'user-settings', $cookie, false );
830
			update_user_option( $user_id, 'user-settings-time', time() - 5, false );
831
			return;
832
		}
833
	}
834
835
	// The cookie is not set in the current browser or the saved value is newer.
836
	$secure = ( 'https' === parse_url( admin_url(), PHP_URL_SCHEME ) );
837
	setcookie( 'wp-settings-' . $user_id, $settings, time() + YEAR_IN_SECONDS, SITECOOKIEPATH, null, $secure );
838
	setcookie( 'wp-settings-time-' . $user_id, time(), time() + YEAR_IN_SECONDS, SITECOOKIEPATH, null, $secure );
839
	$_COOKIE['wp-settings-' . $user_id] = $settings;
840
}
841
842
/**
843
 * Retrieve user interface setting value based on setting name.
844
 *
845
 * @since 2.7.0
846
 *
847
 * @param string $name    The name of the setting.
848
 * @param string $default Optional default value to return when $name is not set.
849
 * @return mixed the last saved user setting or the default value/false if it doesn't exist.
850
 */
851
function get_user_setting( $name, $default = false ) {
852
	$all_user_settings = get_all_user_settings();
853
854
	return isset( $all_user_settings[$name] ) ? $all_user_settings[$name] : $default;
855
}
856
857
/**
858
 * Add or update user interface setting.
859
 *
860
 * Both $name and $value can contain only ASCII letters, numbers and underscores.
861
 *
862
 * This function has to be used before any output has started as it calls setcookie().
863
 *
864
 * @since 2.8.0
865
 *
866
 * @param string $name  The name of the setting.
867
 * @param string $value The value for the setting.
868
 * @return bool|null True if set successfully, false if not. Null if the current user can't be established.
869
 */
870
function set_user_setting( $name, $value ) {
871
	if ( headers_sent() ) {
872
		return false;
873
	}
874
875
	$all_user_settings = get_all_user_settings();
876
	$all_user_settings[$name] = $value;
877
878
	return wp_set_all_user_settings( $all_user_settings );
879
}
880
881
/**
882
 * Delete user interface settings.
883
 *
884
 * Deleting settings would reset them to the defaults.
885
 *
886
 * This function has to be used before any output has started as it calls setcookie().
887
 *
888
 * @since 2.7.0
889
 *
890
 * @param string $names The name or array of names of the setting to be deleted.
891
 * @return bool|null True if deleted successfully, false if not. Null if the current user can't be established.
892
 */
893
function delete_user_setting( $names ) {
894
	if ( headers_sent() ) {
895
		return false;
896
	}
897
898
	$all_user_settings = get_all_user_settings();
899
	$names = (array) $names;
900
	$deleted = false;
901
902
	foreach ( $names as $name ) {
903
		if ( isset( $all_user_settings[$name] ) ) {
904
			unset( $all_user_settings[$name] );
905
			$deleted = true;
906
		}
907
	}
908
909
	if ( $deleted ) {
910
		return wp_set_all_user_settings( $all_user_settings );
911
	}
912
913
	return false;
914
}
915
916
/**
917
 * Retrieve all user interface settings.
918
 *
919
 * @since 2.7.0
920
 *
921
 * @global array $_updated_user_settings
922
 *
923
 * @return array the last saved user settings or empty array.
0 ignored issues
show
Should the return type not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
924
 */
925
function get_all_user_settings() {
926
	global $_updated_user_settings;
927
928
	if ( ! $user_id = get_current_user_id() ) {
929
		return array();
930
	}
931
932
	if ( isset( $_updated_user_settings ) && is_array( $_updated_user_settings ) ) {
933
		return $_updated_user_settings;
934
	}
935
936
	$user_settings = array();
937
938
	if ( isset( $_COOKIE['wp-settings-' . $user_id] ) ) {
939
		$cookie = preg_replace( '/[^A-Za-z0-9=&_-]/', '', $_COOKIE['wp-settings-' . $user_id] );
940
941
		if ( strpos( $cookie, '=' ) ) { // '=' cannot be 1st char
942
			parse_str( $cookie, $user_settings );
943
		}
944
	} else {
945
		$option = get_user_option( 'user-settings', $user_id );
946
947
		if ( $option && is_string( $option ) ) {
948
			parse_str( $option, $user_settings );
949
		}
950
	}
951
952
	$_updated_user_settings = $user_settings;
953
	return $user_settings;
954
}
955
956
/**
957
 * Private. Set all user interface settings.
958
 *
959
 * @since 2.8.0
960
 * @access private
961
 *
962
 * @global array $_updated_user_settings
963
 *
964
 * @param array $user_settings User settings.
965
 * @return bool|null False if the current user can't be found, null if the current
966
 *                   user is not a super admin or a member of the site, otherwise true.
967
 */
968
function wp_set_all_user_settings( $user_settings ) {
969
	global $_updated_user_settings;
970
971
	if ( ! $user_id = get_current_user_id() ) {
972
		return false;
973
	}
974
975
	if ( ! is_user_member_of_blog() ) {
976
		return;
977
	}
978
979
	$settings = '';
980
	foreach ( $user_settings as $name => $value ) {
981
		$_name = preg_replace( '/[^A-Za-z0-9_-]+/', '', $name );
982
		$_value = preg_replace( '/[^A-Za-z0-9_-]+/', '', $value );
983
984
		if ( ! empty( $_name ) ) {
985
			$settings .= $_name . '=' . $_value . '&';
986
		}
987
	}
988
989
	$settings = rtrim( $settings, '&' );
990
	parse_str( $settings, $_updated_user_settings );
991
992
	update_user_option( $user_id, 'user-settings', $settings, false );
993
	update_user_option( $user_id, 'user-settings-time', time(), false );
994
995
	return true;
996
}
997
998
/**
999
 * Delete the user settings of the current user.
1000
 *
1001
 * @since 2.7.0
1002
 */
1003
function delete_all_user_settings() {
1004
	if ( ! $user_id = get_current_user_id() ) {
1005
		return;
1006
	}
1007
1008
	update_user_option( $user_id, 'user-settings', '', false );
1009
	setcookie( 'wp-settings-' . $user_id, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH );
1010
}
1011
1012
/**
1013
 * Retrieve an option value for the current network based on name of option.
1014
 *
1015
 * @since 2.8.0
1016
 * @since 4.4.0 The `$use_cache` parameter was deprecated.
1017
 * @since 4.4.0 Modified into wrapper for get_network_option()
1018
 *
1019
 * @see get_network_option()
1020
 *
1021
 * @param string $option     Name of option to retrieve. Expected to not be SQL-escaped.
1022
 * @param mixed  $default    Optional value to return if option doesn't exist. Default false.
1023
 * @param bool   $deprecated Whether to use cache. Multisite only. Always set to true.
1024
 * @return mixed Value set for the option.
1025
 */
1026
function get_site_option( $option, $default = false, $deprecated = true ) {
0 ignored issues
show
The parameter $deprecated is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1027
	return get_network_option( null, $option, $default );
1028
}
1029
1030
/**
1031
 * Add a new option for the current network.
1032
 *
1033
 * Existing options will not be updated. Note that prior to 3.3 this wasn't the case.
1034
 *
1035
 * @since 2.8.0
1036
 * @since 4.4.0 Modified into wrapper for add_network_option()
1037
 *
1038
 * @see add_network_option()
1039
 *
1040
 * @param string $option Name of option to add. Expected to not be SQL-escaped.
1041
 * @param mixed  $value  Option value, can be anything. Expected to not be SQL-escaped.
1042
 * @return bool False if the option was not added. True if the option was added.
1043
 */
1044
function add_site_option( $option, $value ) {
1045
	return add_network_option( null, $option, $value );
1046
}
1047
1048
/**
1049
 * Removes a option by name for the current network.
1050
 *
1051
 * @since 2.8.0
1052
 * @since 4.4.0 Modified into wrapper for delete_network_option()
1053
 *
1054
 * @see delete_network_option()
1055
 *
1056
 * @param string $option Name of option to remove. Expected to not be SQL-escaped.
1057
 * @return bool True, if succeed. False, if failure.
1058
 */
1059
function delete_site_option( $option ) {
1060
	return delete_network_option( null, $option );
1061
}
1062
1063
/**
1064
 * Update the value of an option that was already added for the current network.
1065
 *
1066
 * @since 2.8.0
1067
 * @since 4.4.0 Modified into wrapper for update_network_option()
1068
 *
1069
 * @see update_network_option()
1070
 *
1071
 * @param string $option Name of option. Expected to not be SQL-escaped.
1072
 * @param mixed  $value  Option value. Expected to not be SQL-escaped.
1073
 * @return bool False if value was not updated. True if value was updated.
1074
 */
1075
function update_site_option( $option, $value ) {
1076
	return update_network_option( null, $option, $value );
1077
}
1078
1079
/**
1080
 * Retrieve a network's option value based on the option name.
1081
 *
1082
 * @since 4.4.0
1083
 *
1084
 * @see get_option()
1085
 *
1086
 * @global wpdb $wpdb
1087
 *
1088
 * @param int      $network_id ID of the network. Can be null to default to the current network ID.
1089
 * @param string   $option     Name of option to retrieve. Expected to not be SQL-escaped.
1090
 * @param mixed    $default    Optional. Value to return if the option doesn't exist. Default false.
1091
 * @return mixed Value set for the option.
1092
 */
1093
function get_network_option( $network_id, $option, $default = false ) {
1094
	global $wpdb;
1095
1096
	if ( $network_id && ! is_numeric( $network_id ) ) {
1097
		return false;
1098
	}
1099
1100
	$network_id = (int) $network_id;
1101
1102
	// Fallback to the current network if a network ID is not specified.
1103
	if ( ! $network_id ) {
1104
		$network_id = get_current_network_id();
1105
	}
1106
1107
	/**
1108
	 * Filters an existing network option before it is retrieved.
1109
	 *
1110
	 * The dynamic portion of the hook name, `$option`, refers to the option name.
1111
	 *
1112
	 * Passing a truthy value to the filter will effectively short-circuit retrieval,
1113
	 * returning the passed value instead.
1114
	 *
1115
	 * @since 2.9.0 As 'pre_site_option_' . $key
1116
	 * @since 3.0.0
1117
	 * @since 4.4.0 The `$option` parameter was added.
1118
	 * @since 4.7.0 The `$network_id` parameter was added.
1119
	 *
1120
	 * @param mixed  $pre_option The default value to return if the option does not exist.
1121
	 * @param string $option     Option name.
1122
	 * @param int    $network_id ID of the network.
1123
	 */
1124
	$pre = apply_filters( "pre_site_option_{$option}", false, $option, $network_id );
1125
1126
	if ( false !== $pre ) {
1127
		return $pre;
1128
	}
1129
1130
	// prevent non-existent options from triggering multiple queries
1131
	$notoptions_key = "$network_id:notoptions";
1132
	$notoptions = wp_cache_get( $notoptions_key, 'site-options' );
1133
1134
	if ( isset( $notoptions[ $option ] ) ) {
1135
1136
		/**
1137
		 * Filters a specific default network option.
1138
		 *
1139
		 * The dynamic portion of the hook name, `$option`, refers to the option name.
1140
		 *
1141
		 * @since 3.4.0
1142
		 * @since 4.4.0 The `$option` parameter was added.
1143
		 * @since 4.7.0 The `$network_id` parameter was added.
1144
		 *
1145
		 * @param mixed  $default    The value to return if the site option does not exist
1146
		 *                           in the database.
1147
		 * @param string $option     Option name.
1148
		 * @param int    $network_id ID of the network.
1149
		 */
1150
		return apply_filters( "default_site_option_{$option}", $default, $option, $network_id );
1151
	}
1152
1153
	if ( ! is_multisite() ) {
1154
		/** This filter is documented in wp-includes/option.php */
1155
		$default = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id );
1156
		$value = get_option( $option, $default );
1157
	} else {
1158
		$cache_key = "$network_id:$option";
1159
		$value = wp_cache_get( $cache_key, 'site-options' );
1160
1161
		if ( ! isset( $value ) || false === $value ) {
1162
			$row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
1163
1164
			// Has to be get_row instead of get_var because of funkiness with 0, false, null values
1165
			if ( is_object( $row ) ) {
1166
				$value = $row->meta_value;
1167
				$value = maybe_unserialize( $value );
1168
				wp_cache_set( $cache_key, $value, 'site-options' );
1169 View Code Duplication
			} else {
1170
				if ( ! is_array( $notoptions ) ) {
1171
					$notoptions = array();
1172
				}
1173
				$notoptions[ $option ] = true;
1174
				wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
1175
1176
				/** This filter is documented in wp-includes/option.php */
1177
				$value = apply_filters( 'default_site_option_' . $option, $default, $option, $network_id );
1178
			}
1179
		}
1180
	}
1181
1182
	/**
1183
	 * Filters the value of an existing network option.
1184
	 *
1185
	 * The dynamic portion of the hook name, `$option`, refers to the option name.
1186
	 *
1187
	 * @since 2.9.0 As 'site_option_' . $key
1188
	 * @since 3.0.0
1189
	 * @since 4.4.0 The `$option` parameter was added.
1190
	 * @since 4.7.0 The `$network_id` parameter was added.
1191
	 *
1192
	 * @param mixed  $value      Value of network option.
1193
	 * @param string $option     Option name.
1194
	 * @param int    $network_id ID of the network.
1195
	 */
1196
	return apply_filters( "site_option_{$option}", $value, $option, $network_id );
1197
}
1198
1199
/**
1200
 * Add a new network option.
1201
 *
1202
 * Existing options will not be updated.
1203
 *
1204
 * @since 4.4.0
1205
 *
1206
 * @see add_option()
1207
 *
1208
 * @global wpdb $wpdb
1209
 *
1210
 * @param int    $network_id ID of the network. Can be null to default to the current network ID.
1211
 * @param string $option     Name of option to add. Expected to not be SQL-escaped.
1212
 * @param mixed  $value      Option value, can be anything. Expected to not be SQL-escaped.
1213
 * @return bool False if option was not added and true if option was added.
1214
 */
1215
function add_network_option( $network_id, $option, $value ) {
1216
	global $wpdb;
1217
1218
	if ( $network_id && ! is_numeric( $network_id ) ) {
1219
		return false;
1220
	}
1221
1222
	$network_id = (int) $network_id;
1223
1224
	// Fallback to the current network if a network ID is not specified.
1225
	if ( ! $network_id ) {
1226
		$network_id = get_current_network_id();
1227
	}
1228
1229
	wp_protect_special_option( $option );
1230
1231
	/**
1232
	 * Filters the value of a specific network option before it is added.
1233
	 *
1234
	 * The dynamic portion of the hook name, `$option`, refers to the option name.
1235
	 *
1236
	 * @since 2.9.0 As 'pre_add_site_option_' . $key
1237
	 * @since 3.0.0
1238
	 * @since 4.4.0 The `$option` parameter was added.
1239
	 * @since 4.7.0 The `$network_id` parameter was added.
1240
	 *
1241
	 * @param mixed  $value      Value of network option.
1242
	 * @param string $option     Option name.
1243
	 * @param int    $network_id ID of the network.
1244
	 */
1245
	$value = apply_filters( "pre_add_site_option_{$option}", $value, $option, $network_id );
1246
1247
	$notoptions_key = "$network_id:notoptions";
1248
1249
	if ( ! is_multisite() ) {
1250
		$result = add_option( $option, $value, '', 'no' );
1251
	} else {
1252
		$cache_key = "$network_id:$option";
1253
1254
		// Make sure the option doesn't already exist. We can check the 'notoptions' cache before we ask for a db query
1255
		$notoptions = wp_cache_get( $notoptions_key, 'site-options' );
1256 View Code Duplication
		if ( ! is_array( $notoptions ) || ! isset( $notoptions[ $option ] ) ) {
1257
			if ( false !== get_network_option( $network_id, $option, false ) ) {
1258
				return false;
1259
			}
1260
		}
1261
1262
		$value = sanitize_option( $option, $value );
1263
1264
		$serialized_value = maybe_serialize( $value );
1265
		$result = $wpdb->insert( $wpdb->sitemeta, array( 'site_id'    => $network_id, 'meta_key'   => $option, 'meta_value' => $serialized_value ) );
1266
1267
		if ( ! $result ) {
1268
			return false;
1269
		}
1270
1271
		wp_cache_set( $cache_key, $value, 'site-options' );
1272
1273
		// This option exists now
1274
		$notoptions = wp_cache_get( $notoptions_key, 'site-options' ); // yes, again... we need it to be fresh
1275 View Code Duplication
		if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
1276
			unset( $notoptions[ $option ] );
1277
			wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
1278
		}
1279
	}
1280
1281
	if ( $result ) {
1282
1283
		/**
1284
		 * Fires after a specific network option has been successfully added.
1285
		 *
1286
		 * The dynamic portion of the hook name, `$option`, refers to the option name.
1287
		 *
1288
		 * @since 2.9.0 As "add_site_option_{$key}"
1289
		 * @since 3.0.0
1290
		 * @since 4.7.0 The `$network_id` parameter was added.
1291
		 *
1292
		 * @param string $option     Name of the network option.
1293
		 * @param mixed  $value      Value of the network option.
1294
		 * @param int    $network_id ID of the network.
1295
		 */
1296
		do_action( "add_site_option_{$option}", $option, $value, $network_id );
1297
1298
		/**
1299
		 * Fires after a network option has been successfully added.
1300
		 *
1301
		 * @since 3.0.0
1302
		 * @since 4.7.0 The `$network_id` parameter was added.
1303
		 *
1304
		 * @param string $option     Name of the network option.
1305
		 * @param mixed  $value      Value of the network option.
1306
		 * @param int    $network_id ID of the network.
1307
		 */
1308
		do_action( 'add_site_option', $option, $value, $network_id );
1309
1310
		return true;
1311
	}
1312
1313
	return false;
1314
}
1315
1316
/**
1317
 * Removes a network option by name.
1318
 *
1319
 * @since 4.4.0
1320
 *
1321
 * @see delete_option()
1322
 *
1323
 * @global wpdb $wpdb
1324
 *
1325
 * @param int    $network_id ID of the network. Can be null to default to the current network ID.
1326
 * @param string $option     Name of option to remove. Expected to not be SQL-escaped.
1327
 * @return bool True, if succeed. False, if failure.
1328
 */
1329
function delete_network_option( $network_id, $option ) {
1330
	global $wpdb;
1331
1332
	if ( $network_id && ! is_numeric( $network_id ) ) {
1333
		return false;
1334
	}
1335
1336
	$network_id = (int) $network_id;
1337
1338
	// Fallback to the current network if a network ID is not specified.
1339
	if ( ! $network_id ) {
1340
		$network_id = get_current_network_id();
1341
	}
1342
1343
	/**
1344
	 * Fires immediately before a specific network option is deleted.
1345
	 *
1346
	 * The dynamic portion of the hook name, `$option`, refers to the option name.
1347
	 *
1348
	 * @since 3.0.0
1349
	 * @since 4.4.0 The `$option` parameter was added.
1350
	 * @since 4.7.0 The `$network_id` parameter was added.
1351
	 *
1352
	 * @param string $option     Option name.
1353
	 * @param int    $network_id ID of the network.
1354
	 */
1355
	do_action( "pre_delete_site_option_{$option}", $option, $network_id );
1356
1357
	if ( ! is_multisite() ) {
1358
		$result = delete_option( $option );
1359
	} else {
1360
		$row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM {$wpdb->sitemeta} WHERE meta_key = %s AND site_id = %d", $option, $network_id ) );
1361
		if ( is_null( $row ) || ! $row->meta_id ) {
1362
			return false;
1363
		}
1364
		$cache_key = "$network_id:$option";
1365
		wp_cache_delete( $cache_key, 'site-options' );
1366
1367
		$result = $wpdb->delete( $wpdb->sitemeta, array( 'meta_key' => $option, 'site_id' => $network_id ) );
1368
	}
1369
1370
	if ( $result ) {
1371
1372
		/**
1373
		 * Fires after a specific network option has been deleted.
1374
		 *
1375
		 * The dynamic portion of the hook name, `$option`, refers to the option name.
1376
		 *
1377
		 * @since 2.9.0 As "delete_site_option_{$key}"
1378
		 * @since 3.0.0
1379
		 * @since 4.7.0 The `$network_id` parameter was added.
1380
		 *
1381
		 * @param string $option     Name of the network option.
1382
		 * @param int    $network_id ID of the network.
1383
		 */
1384
		do_action( "delete_site_option_{$option}", $option, $network_id );
1385
1386
		/**
1387
		 * Fires after a network option has been deleted.
1388
		 *
1389
		 * @since 3.0.0
1390
		 * @since 4.7.0 The `$network_id` parameter was added.
1391
		 *
1392
		 * @param string $option     Name of the network option.
1393
		 * @param int    $network_id ID of the network.
1394
		 */
1395
		do_action( 'delete_site_option', $option, $network_id );
1396
1397
		return true;
1398
	}
1399
1400
	return false;
1401
}
1402
1403
/**
1404
 * Update the value of a network option that was already added.
1405
 *
1406
 * @since 4.4.0
1407
 *
1408
 * @see update_option()
1409
 *
1410
 * @global wpdb $wpdb
1411
 *
1412
 * @param int      $network_id ID of the network. Can be null to default to the current network ID.
1413
 * @param string   $option     Name of option. Expected to not be SQL-escaped.
1414
 * @param mixed    $value      Option value. Expected to not be SQL-escaped.
1415
 * @return bool False if value was not updated and true if value was updated.
1416
 */
1417
function update_network_option( $network_id, $option, $value ) {
1418
	global $wpdb;
1419
1420
	if ( $network_id && ! is_numeric( $network_id ) ) {
1421
		return false;
1422
	}
1423
1424
	$network_id = (int) $network_id;
1425
1426
	// Fallback to the current network if a network ID is not specified.
1427
	if ( ! $network_id ) {
1428
		$network_id = get_current_network_id();
1429
	}
1430
1431
	wp_protect_special_option( $option );
1432
1433
	$old_value = get_network_option( $network_id, $option, false );
1434
1435
	/**
1436
	 * Filters a specific network option before its value is updated.
1437
	 *
1438
	 * The dynamic portion of the hook name, `$option`, refers to the option name.
1439
	 *
1440
	 * @since 2.9.0 As 'pre_update_site_option_' . $key
1441
	 * @since 3.0.0
1442
	 * @since 4.4.0 The `$option` parameter was added.
1443
	 * @since 4.7.0 The `$network_id` parameter was added.
1444
	 *
1445
	 * @param mixed  $value      New value of the network option.
1446
	 * @param mixed  $old_value  Old value of the network option.
1447
	 * @param string $option     Option name.
1448
	 * @param int    $network_id ID of the network.
1449
	 */
1450
	$value = apply_filters( "pre_update_site_option_{$option}", $value, $old_value, $option, $network_id );
1451
1452
	if ( $value === $old_value ) {
1453
		return false;
1454
	}
1455
1456
	if ( false === $old_value ) {
1457
		return add_network_option( $network_id, $option, $value );
1458
	}
1459
1460
	$notoptions_key = "$network_id:notoptions";
1461
	$notoptions = wp_cache_get( $notoptions_key, 'site-options' );
1462 View Code Duplication
	if ( is_array( $notoptions ) && isset( $notoptions[ $option ] ) ) {
1463
		unset( $notoptions[ $option ] );
1464
		wp_cache_set( $notoptions_key, $notoptions, 'site-options' );
1465
	}
1466
1467
	if ( ! is_multisite() ) {
1468
		$result = update_option( $option, $value, 'no' );
1469
	} else {
1470
		$value = sanitize_option( $option, $value );
1471
1472
		$serialized_value = maybe_serialize( $value );
1473
		$result = $wpdb->update( $wpdb->sitemeta, array( 'meta_value' => $serialized_value ), array( 'site_id' => $network_id, 'meta_key' => $option ) );
1474
1475
		if ( $result ) {
1476
			$cache_key = "$network_id:$option";
1477
			wp_cache_set( $cache_key, $value, 'site-options' );
1478
		}
1479
	}
1480
1481
	if ( $result ) {
1482
1483
		/**
1484
		 * Fires after the value of a specific network option has been successfully updated.
1485
		 *
1486
		 * The dynamic portion of the hook name, `$option`, refers to the option name.
1487
		 *
1488
		 * @since 2.9.0 As "update_site_option_{$key}"
1489
		 * @since 3.0.0
1490
		 * @since 4.7.0 The `$network_id` parameter was added.
1491
		 *
1492
		 * @param string $option     Name of the network option.
1493
		 * @param mixed  $value      Current value of the network option.
1494
		 * @param mixed  $old_value  Old value of the network option.
1495
		 * @param int    $network_id ID of the network.
1496
		 */
1497
		do_action( "update_site_option_{$option}", $option, $value, $old_value, $network_id );
1498
1499
		/**
1500
		 * Fires after the value of a network option has been successfully updated.
1501
		 *
1502
		 * @since 3.0.0
1503
		 * @since 4.7.0 The `$network_id` parameter was added.
1504
		 *
1505
		 * @param string $option     Name of the network option.
1506
		 * @param mixed  $value      Current value of the network option.
1507
		 * @param mixed  $old_value  Old value of the network option.
1508
		 * @param int    $network_id ID of the network.
1509
		 */
1510
		do_action( 'update_site_option', $option, $value, $old_value, $network_id );
1511
1512
		return true;
1513
	}
1514
1515
	return false;
1516
}
1517
1518
/**
1519
 * Delete a site transient.
1520
 *
1521
 * @since 2.9.0
1522
 *
1523
 * @param string $transient Transient name. Expected to not be SQL-escaped.
1524
 * @return bool True if successful, false otherwise
1525
 */
1526 View Code Duplication
function delete_site_transient( $transient ) {
0 ignored issues
show
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1527
1528
	/**
1529
	 * Fires immediately before a specific site transient is deleted.
1530
	 *
1531
	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1532
	 *
1533
	 * @since 3.0.0
1534
	 *
1535
	 * @param string $transient Transient name.
1536
	 */
1537
	do_action( "delete_site_transient_{$transient}", $transient );
1538
1539
	if ( wp_using_ext_object_cache() ) {
1540
		$result = wp_cache_delete( $transient, 'site-transient' );
1541
	} else {
1542
		$option_timeout = '_site_transient_timeout_' . $transient;
1543
		$option = '_site_transient_' . $transient;
1544
		$result = delete_site_option( $option );
1545
		if ( $result )
1546
			delete_site_option( $option_timeout );
1547
	}
1548
	if ( $result ) {
1549
1550
		/**
1551
		 * Fires after a transient is deleted.
1552
		 *
1553
		 * @since 3.0.0
1554
		 *
1555
		 * @param string $transient Deleted transient name.
1556
		 */
1557
		do_action( 'deleted_site_transient', $transient );
1558
	}
1559
1560
	return $result;
1561
}
1562
1563
/**
1564
 * Get the value of a site transient.
1565
 *
1566
 * If the transient does not exist, does not have a value, or has expired,
1567
 * then the return value will be false.
1568
 *
1569
 * @since 2.9.0
1570
 *
1571
 * @see get_transient()
1572
 *
1573
 * @param string $transient Transient name. Expected to not be SQL-escaped.
1574
 * @return mixed Value of transient.
1575
 */
1576
function get_site_transient( $transient ) {
1577
1578
	/**
1579
	 * Filters the value of an existing site transient.
1580
	 *
1581
	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1582
	 *
1583
	 * Passing a truthy value to the filter will effectively short-circuit retrieval,
1584
	 * returning the passed value instead.
1585
	 *
1586
	 * @since 2.9.0
1587
	 * @since 4.4.0 The `$transient` parameter was added.
1588
	 *
1589
	 * @param mixed  $pre_site_transient The default value to return if the site transient does not exist.
1590
	 *                                   Any value other than false will short-circuit the retrieval
1591
	 *                                   of the transient, and return the returned value.
1592
	 * @param string $transient          Transient name.
1593
	 */
1594
	$pre = apply_filters( "pre_site_transient_{$transient}", false, $transient );
1595
1596
	if ( false !== $pre )
1597
		return $pre;
1598
1599
	if ( wp_using_ext_object_cache() ) {
1600
		$value = wp_cache_get( $transient, 'site-transient' );
1601
	} else {
1602
		// Core transients that do not have a timeout. Listed here so querying timeouts can be avoided.
1603
		$no_timeout = array('update_core', 'update_plugins', 'update_themes');
1604
		$transient_option = '_site_transient_' . $transient;
1605 View Code Duplication
		if ( ! in_array( $transient, $no_timeout ) ) {
1606
			$transient_timeout = '_site_transient_timeout_' . $transient;
1607
			$timeout = get_site_option( $transient_timeout );
1608
			if ( false !== $timeout && $timeout < time() ) {
1609
				delete_site_option( $transient_option  );
1610
				delete_site_option( $transient_timeout );
1611
				$value = false;
1612
			}
1613
		}
1614
1615
		if ( ! isset( $value ) )
1616
			$value = get_site_option( $transient_option );
1617
	}
1618
1619
	/**
1620
	 * Filters the value of an existing site transient.
1621
	 *
1622
	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1623
	 *
1624
	 * @since 2.9.0
1625
	 * @since 4.4.0 The `$transient` parameter was added.
1626
	 *
1627
	 * @param mixed  $value     Value of site transient.
1628
	 * @param string $transient Transient name.
1629
	 */
1630
	return apply_filters( "site_transient_{$transient}", $value, $transient );
1631
}
1632
1633
/**
1634
 * Set/update the value of a site transient.
1635
 *
1636
 * You do not need to serialize values, if the value needs to be serialize, then
1637
 * it will be serialized before it is set.
1638
 *
1639
 * @since 2.9.0
1640
 *
1641
 * @see set_transient()
1642
 *
1643
 * @param string $transient  Transient name. Expected to not be SQL-escaped. Must be
1644
 *                           167 characters or fewer in length.
1645
 * @param mixed  $value      Transient value. Expected to not be SQL-escaped.
1646
 * @param int    $expiration Optional. Time until expiration in seconds. Default 0 (no expiration).
1647
 * @return bool False if value was not set and true if value was set.
1648
 */
1649
function set_site_transient( $transient, $value, $expiration = 0 ) {
1650
1651
	/**
1652
	 * Filters the value of a specific site transient before it is set.
1653
	 *
1654
	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1655
	 *
1656
	 * @since 3.0.0
1657
	 * @since 4.4.0 The `$transient` parameter was added.
1658
	 *
1659
	 * @param mixed  $value     New value of site transient.
1660
	 * @param string $transient Transient name.
1661
	 */
1662
	$value = apply_filters( "pre_set_site_transient_{$transient}", $value, $transient );
1663
1664
	$expiration = (int) $expiration;
1665
1666
	/**
1667
	 * Filters the expiration for a site transient before its value is set.
1668
	 *
1669
	 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1670
	 *
1671
	 * @since 4.4.0
1672
	 *
1673
	 * @param int    $expiration Time until expiration in seconds. Use 0 for no expiration.
1674
	 * @param mixed  $value      New value of site transient.
1675
	 * @param string $transient  Transient name.
1676
	 */
1677
	$expiration = apply_filters( "expiration_of_site_transient_{$transient}", $expiration, $value, $transient );
1678
1679
	if ( wp_using_ext_object_cache() ) {
1680
		$result = wp_cache_set( $transient, $value, 'site-transient', $expiration );
1681
	} else {
1682
		$transient_timeout = '_site_transient_timeout_' . $transient;
1683
		$option = '_site_transient_' . $transient;
1684
		if ( false === get_site_option( $option ) ) {
1685
			if ( $expiration )
1686
				add_site_option( $transient_timeout, time() + $expiration );
1687
			$result = add_site_option( $option, $value );
1688
		} else {
1689
			if ( $expiration )
1690
				update_site_option( $transient_timeout, time() + $expiration );
1691
			$result = update_site_option( $option, $value );
1692
		}
1693
	}
1694
	if ( $result ) {
1695
1696
		/**
1697
		 * Fires after the value for a specific site transient has been set.
1698
		 *
1699
		 * The dynamic portion of the hook name, `$transient`, refers to the transient name.
1700
		 *
1701
		 * @since 3.0.0
1702
		 * @since 4.4.0 The `$transient` parameter was added
1703
		 *
1704
		 * @param mixed  $value      Site transient value.
1705
		 * @param int    $expiration Time until expiration in seconds.
1706
		 * @param string $transient  Transient name.
1707
		 */
1708
		do_action( "set_site_transient_{$transient}", $value, $expiration, $transient );
1709
1710
		/**
1711
		 * Fires after the value for a site transient has been set.
1712
		 *
1713
		 * @since 3.0.0
1714
		 *
1715
		 * @param string $transient  The name of the site transient.
1716
		 * @param mixed  $value      Site transient value.
1717
		 * @param int    $expiration Time until expiration in seconds.
1718
		 */
1719
		do_action( 'setted_site_transient', $transient, $value, $expiration );
1720
	}
1721
	return $result;
1722
}
1723
1724
/**
1725
 * Register default settings available in WordPress.
1726
 *
1727
 * The settings registered here are primarily useful for the REST API, so this
1728
 * does not encompass all settings available in WordPress.
1729
 *
1730
 * @since 4.7.0
1731
 */
1732
function register_initial_settings() {
1733
	register_setting( 'general', 'blogname', array(
1734
		'show_in_rest' => array(
1735
			'name' => 'title',
1736
		),
1737
		'type'         => 'string',
1738
		'description'  => __( 'Site title.' ),
1739
	) );
1740
1741
	register_setting( 'general', 'blogdescription', array(
1742
		'show_in_rest' => array(
1743
			'name' => 'description',
1744
		),
1745
		'type'         => 'string',
1746
		'description'  => __( 'Site tagline.' ),
1747
	) );
1748
1749 View Code Duplication
	if ( ! is_multisite() ) {
1750
		register_setting( 'general', 'siteurl', array(
1751
			'show_in_rest' => array(
1752
				'name'    => 'url',
1753
				'schema'  => array(
1754
					'format' => 'uri',
1755
				),
1756
			),
1757
			'type'         => 'string',
1758
			'description'  => __( 'Site URL.' ),
1759
		) );
1760
	}
1761
1762 View Code Duplication
	if ( ! is_multisite() ) {
1763
		register_setting( 'general', 'admin_email', array(
1764
			'show_in_rest' => array(
1765
				'name'    => 'email',
1766
				'schema'  => array(
1767
					'format' => 'email',
1768
				),
1769
			),
1770
			'type'         => 'string',
1771
			'description'  => __( 'This address is used for admin purposes, like new user notification.' ),
1772
		) );
1773
	}
1774
1775
	register_setting( 'general', 'timezone_string', array(
1776
		'show_in_rest' => array(
1777
			'name' => 'timezone',
1778
		),
1779
		'type'         => 'string',
1780
		'description'  => __( 'A city in the same timezone as you.' ),
1781
	) );
1782
1783
	register_setting( 'general', 'date_format', array(
1784
		'show_in_rest' => true,
1785
		'type'         => 'string',
1786
		'description'  => __( 'A date format for all date strings.' ),
1787
	) );
1788
1789
	register_setting( 'general', 'time_format', array(
1790
		'show_in_rest' => true,
1791
		'type'         => 'string',
1792
		'description'  => __( 'A time format for all time strings.' ),
1793
	) );
1794
1795
	register_setting( 'general', 'start_of_week', array(
1796
		'show_in_rest' => true,
1797
		'type'         => 'integer',
1798
		'description'  => __( 'A day number of the week that the week should start on.' ),
1799
	) );
1800
1801
	register_setting( 'general', 'WPLANG', array(
1802
		'show_in_rest' => array(
1803
			'name' => 'language',
1804
		),
1805
		'type'         => 'string',
1806
		'description'  => __( 'WordPress locale code.' ),
1807
		'default'      => 'en_US',
1808
	) );
1809
1810
	register_setting( 'writing', 'use_smilies', array(
1811
		'show_in_rest' => true,
1812
		'type'         => 'boolean',
1813
		'description'  => __( 'Convert emoticons like :-) and :-P to graphics on display.' ),
1814
		'default'      => true,
1815
	) );
1816
1817
	register_setting( 'writing', 'default_category', array(
1818
		'show_in_rest' => true,
1819
		'type'         => 'integer',
1820
		'description'  => __( 'Default post category.' ),
1821
	) );
1822
1823
	register_setting( 'writing', 'default_post_format', array(
1824
		'show_in_rest' => true,
1825
		'type'         => 'string',
1826
		'description'  => __( 'Default post format.' ),
1827
	) );
1828
1829
	register_setting( 'reading', 'posts_per_page', array(
1830
		'show_in_rest' => true,
1831
		'type'         => 'integer',
1832
		'description'  => __( 'Blog pages show at most.' ),
1833
		'default'      => 10,
1834
	) );
1835
1836
	register_setting( 'discussion', 'default_ping_status', array(
1837
		'show_in_rest' => array(
1838
			'schema'   => array(
1839
				'enum' => array( 'open', 'closed' ),
1840
			),
1841
		),
1842
		'type'         => 'string',
1843
		'description'  => __( 'Allow link notifications from other blogs (pingbacks and trackbacks) on new articles.' ),
1844
	) );
1845
1846
	register_setting( 'discussion', 'default_comment_status', array(
1847
		'show_in_rest' => array(
1848
			'schema'   => array(
1849
				'enum' => array( 'open', 'closed' ),
1850
			),
1851
		),
1852
		'type'         => 'string',
1853
		'description'  => __( 'Allow people to post comments on new articles.' ),
1854
	) );
1855
1856
}
1857
1858
/**
1859
 * Register a setting and its data.
1860
 *
1861
 * @since 2.7.0
1862
 * @since 4.7.0 `$args` can be passed to set flags on the setting, similar to `register_meta()`.
1863
 *
1864
 * @global array $new_whitelist_options
1865
 * @global array $wp_registered_settings
1866
 *
1867
 * @param string $option_group A settings group name. Should correspond to a whitelisted option key name.
1868
 * 	Default whitelisted option key names include "general," "discussion," and "reading," among others.
1869
 * @param string $option_name The name of an option to sanitize and save.
1870
 * @param array  $args {
1871
 *     Data used to describe the setting when registered.
1872
 *
1873
 *     @type string   $type              The type of data associated with this setting.
1874
 *                                       Valid values are 'string', 'boolean', 'integer', and 'number'.
1875
 *     @type string   $description       A description of the data attached to this setting.
1876
 *     @type callable $sanitize_callback A callback function that sanitizes the option's value.
1877
 *     @type bool     $show_in_rest      Whether data associated with this setting should be included in the REST API.
1878
 *     @type mixed    $default           Default value when calling `get_option()`.
1879
 * }
1880
 */
1881
function register_setting( $option_group, $option_name, $args = array() ) {
1882
	global $new_whitelist_options, $wp_registered_settings;
1883
1884
	$defaults = array(
1885
		'type'              => 'string',
1886
		'group'             => $option_group,
1887
		'description'       => '',
1888
		'sanitize_callback' => null,
1889
		'show_in_rest'      => false,
1890
	);
1891
1892
	// Back-compat: old sanitize callback is added.
1893
	if ( is_callable( $args ) ) {
1894
		$args = array(
1895
			'sanitize_callback' => $args,
1896
		);
1897
	}
1898
1899
	/**
1900
	 * Filters the registration arguments when registering a setting.
1901
	 *
1902
	 * @since 4.7.0
1903
	 *
1904
	 * @param array  $args         Array of setting registration arguments.
1905
	 * @param array  $defaults     Array of default arguments.
1906
	 * @param string $option_group Setting group.
1907
	 * @param string $option_name  Setting name.
1908
	 */
1909
	$args = apply_filters( 'register_setting_args', $args, $defaults, $option_group, $option_name );
1910
	$args = wp_parse_args( $args, $defaults );
1911
1912
	if ( ! is_array( $wp_registered_settings ) ) {
1913
		$wp_registered_settings = array();
1914
	}
1915
1916 View Code Duplication
	if ( 'misc' == $option_group ) {
1917
		_deprecated_argument( __FUNCTION__, '3.0.0',
1918
			/* translators: %s: misc */
1919
			sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ),
1920
				'misc'
1921
			)
1922
		);
1923
		$option_group = 'general';
1924
	}
1925
1926 View Code Duplication
	if ( 'privacy' == $option_group ) {
1927
		_deprecated_argument( __FUNCTION__, '3.5.0',
1928
			/* translators: %s: privacy */
1929
			sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ),
1930
				'privacy'
1931
			)
1932
		);
1933
		$option_group = 'reading';
1934
	}
1935
1936
	$new_whitelist_options[ $option_group ][] = $option_name;
1937
	if ( ! empty( $args['sanitize_callback'] ) ) {
1938
		add_filter( "sanitize_option_{$option_name}", $args['sanitize_callback'] );
1939
	}
1940
	if ( array_key_exists( 'default', $args ) ) {
1941
		add_filter( "default_option_{$option_name}", 'filter_default_option', 10, 3 );
1942
	}
1943
1944
	$wp_registered_settings[ $option_name ] = $args;
1945
}
1946
1947
/**
1948
 * Unregister a setting.
1949
 *
1950
 * @since 2.7.0
1951
 * @since 4.7.0 `$sanitize_callback` was deprecated. The callback from `register_setting()` is now used instead.
1952
 *
1953
 * @global array $new_whitelist_options
1954
 *
1955
 * @param string   $option_group      The settings group name used during registration.
1956
 * @param string   $option_name       The name of the option to unregister.
1957
 * @param callable $deprecated        Deprecated.
1958
 */
1959
function unregister_setting( $option_group, $option_name, $deprecated = '' ) {
1960
	global $new_whitelist_options, $wp_registered_settings;
1961
1962 View Code Duplication
	if ( 'misc' == $option_group ) {
1963
		_deprecated_argument( __FUNCTION__, '3.0.0',
1964
			/* translators: %s: misc */
1965
			sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ),
1966
				'misc'
1967
			)
1968
		);
1969
		$option_group = 'general';
1970
	}
1971
1972 View Code Duplication
	if ( 'privacy' == $option_group ) {
1973
		_deprecated_argument( __FUNCTION__, '3.5.0',
1974
			/* translators: %s: privacy */
1975
			sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ),
1976
				'privacy'
1977
			)
1978
		);
1979
		$option_group = 'reading';
1980
	}
1981
1982
	$pos = array_search( $option_name, (array) $new_whitelist_options[ $option_group ] );
1983
	if ( $pos !== false ) {
1984
		unset( $new_whitelist_options[ $option_group ][ $pos ] );
1985
	}
1986
	if ( '' !== $deprecated ) {
1987
		_deprecated_argument( __FUNCTION__, '4.7.0',
1988
			/* translators: 1: $sanitize_callback, 2: register_setting() */
1989
			sprintf( __( '%1$s is deprecated. The callback from %2$s is used instead.' ),
1990
				'<code>$sanitize_callback</code>',
1991
				'<code>register_setting()</code>'
1992
			)
1993
		);
1994
		remove_filter( "sanitize_option_{$option_name}", $deprecated );
1995
	}
1996
1997
	if ( isset( $wp_registered_settings[ $option_name ] ) ) {
1998
		// Remove the sanitize callback if one was set during registration.
1999
		if ( ! empty( $wp_registered_settings[ $option_name ]['sanitize_callback'] ) ) {
2000
			remove_filter( "sanitize_option_{$option_name}", $wp_registered_settings[ $option_name ]['sanitize_callback'] );
2001
		}
2002
2003
		unset( $wp_registered_settings[ $option_name ] );
2004
	}
2005
}
2006
2007
/**
2008
 * Retrieves an array of registered settings.
2009
 *
2010
 * @since 4.7.0
2011
 *
2012
 * @return array List of registered settings, keyed by option name.
2013
 */
2014
function get_registered_settings() {
2015
	global $wp_registered_settings;
2016
2017
	if ( ! is_array( $wp_registered_settings ) ) {
2018
		return array();
2019
	}
2020
2021
	return $wp_registered_settings;
2022
}
2023
2024
/**
2025
 * Filter the default value for the option.
2026
 *
2027
 * For settings which register a default setting in `register_setting()`, this
2028
 * function is added as a filter to `default_option_{$option}`.
2029
 *
2030
 * @since 4.7.0
2031
 *
2032
 * @param mixed $default Existing default value to return.
2033
 * @param string $option Option name.
2034
 * @param bool $passed_default Was `get_option()` passed a default value?
2035
 * @return mixed Filtered default value.
2036
 */
2037
function filter_default_option( $default, $option, $passed_default ) {
2038
	if ( $passed_default ) {
2039
		return $default;
2040
	}
2041
2042
	$registered = get_registered_settings();
2043
	if ( empty( $registered[ $option ] ) ) {
2044
		return $default;
2045
	}
2046
2047
	return $registered[ $option ]['default'];
2048
}
2049