PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 18.5
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v18.5
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
wordpress-seo / inc / options / class-wpseo-options.php

class-wpseo-options.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 18.5, at inc/options/class-wpseo-options.php

590 lines 16.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * WPSEO plugin file.
4 *
5 * @package WPSEO\Internals\Options
6 */
7
8 /**
9 * Overall Option Management class.
10 *
11 * Instantiates all the options and offers a number of utility methods to work with the options.
12 */
13 class WPSEO_Options {
14
15 /**
16 * The option values.
17 *
18 * @var array|null
19 */
20 protected static $option_values = null;
21
22 /**
23 * Options this class uses.
24 *
25 * @var array Array format: (string) option_name => (string) name of concrete class for the option.
26 */
27 public static $options = [
28 'wpseo' => 'WPSEO_Option_Wpseo',
29 'wpseo_titles' => 'WPSEO_Option_Titles',
30 'wpseo_social' => 'WPSEO_Option_Social',
31 'wpseo_ms' => 'WPSEO_Option_MS',
32 'wpseo_taxonomy_meta' => 'WPSEO_Taxonomy_Meta',
33 ];
34
35 /**
36 * Array of instantiated option objects.
37 *
38 * @var array
39 */
40 protected static $option_instances = [];
41
42 /**
43 * Array with the option names.
44 *
45 * @var array
46 */
47 protected static $option_names = [];
48
49 /**
50 * Instance of this class.
51 *
52 * @var WPSEO_Options
53 */
54 protected static $instance;
55
56 /**
57 * Instantiate all the WPSEO option management classes.
58 */
59 protected function __construct() {
60 $this->register_hooks();
61
62 foreach ( static::$options as $option_name => $option_class ) {
63 static::register_option( call_user_func( [ $option_class, 'get_instance' ] ) );
64 }
65 }
66
67 /**
68 * Register our hooks.
69 */
70 public function register_hooks() {
71 add_action( 'registered_taxonomy', [ $this, 'clear_cache' ] );
72 add_action( 'unregistered_taxonomy', [ $this, 'clear_cache' ] );
73 add_action( 'registered_post_type', [ $this, 'clear_cache' ] );
74 add_action( 'unregistered_post_type', [ $this, 'clear_cache' ] );
75 }
76
77 /**
78 * Get the singleton instance of this class.
79 *
80 * @return object
81 */
82 public static function get_instance() {
83 if ( ! ( static::$instance instanceof self ) ) {
84 static::$instance = new self();
85 }
86
87 return static::$instance;
88 }
89
90 /**
91 * Registers an option to the options list.
92 *
93 * @param WPSEO_Option $option_instance Instance of the option.
94 */
95 public static function register_option( WPSEO_Option $option_instance ) {
96 $option_name = $option_instance->get_option_name();
97
98 if ( $option_instance->multisite_only && ! static::is_multisite() ) {
99 unset( static::$options[ $option_name ], static::$option_names[ $option_name ] );
100
101 return;
102 }
103
104 $is_already_registered = array_key_exists( $option_name, static::$options );
105 if ( ! $is_already_registered ) {
106 static::$options[ $option_name ] = get_class( $option_instance );
107 }
108
109 if ( $option_instance->include_in_all === true ) {
110 static::$option_names[ $option_name ] = $option_name;
111 }
112
113 static::$option_instances[ $option_name ] = $option_instance;
114
115 if ( ! $is_already_registered ) {
116 static::clear_cache();
117 }
118 }
119
120 /**
121 * Get the group name of an option for use in the settings form.
122 *
123 * @param string $option_name The option for which you want to retrieve the option group name.
124 *
125 * @return string|bool
126 */
127 public static function get_group_name( $option_name ) {
128 if ( isset( static::$option_instances[ $option_name ] ) ) {
129 return static::$option_instances[ $option_name ]->group_name;
130 }
131
132 return false;
133 }
134
135 /**
136 * Get a specific default value for an option.
137 *
138 * @param string $option_name The option for which you want to retrieve a default.
139 * @param string $key The key within the option who's default you want.
140 *
141 * @return mixed
142 */
143 public static function get_default( $option_name, $key ) {
144 if ( isset( static::$option_instances[ $option_name ] ) ) {
145 $defaults = static::$option_instances[ $option_name ]->get_defaults();
146 if ( isset( $defaults[ $key ] ) ) {
147 return $defaults[ $key ];
148 }
149 }
150
151 return null;
152 }
153
154 /**
155 * Update a site_option.
156 *
157 * @param string $option_name The option name of the option to save.
158 * @param mixed $value The new value for the option.
159 *
160 * @return bool
161 */
162 public static function update_site_option( $option_name, $value ) {
163 if ( is_multisite() && isset( static::$option_instances[ $option_name ] ) ) {
164 return static::$option_instances[ $option_name ]->update_site_option( $value );
165 }
166
167 return false;
168 }
169
170 /**
171 * Get the instantiated option instance.
172 *
173 * @param string $option_name The option for which you want to retrieve the instance.
174 *
175 * @return object|bool
176 */
177 public static function get_option_instance( $option_name ) {
178 if ( isset( static::$option_instances[ $option_name ] ) ) {
179 return static::$option_instances[ $option_name ];
180 }
181
182 return false;
183 }
184
185 /**
186 * Retrieve an array of the options which should be included in get_all() and reset().
187 *
188 * @return array Array of option names.
189 */
190 public static function get_option_names() {
191 $option_names = array_values( static::$option_names );
192 if ( $option_names === [] ) {
193 foreach ( static::$option_instances as $option_name => $option_object ) {
194 if ( $option_object->include_in_all === true ) {
195 $option_names[] = $option_name;
196 }
197 }
198 }
199
200 /**
201 * Filter: wpseo_options - Allow developers to change the option name to include.
202 *
203 * @api array The option names to include in get_all and reset().
204 */
205 return apply_filters( 'wpseo_options', $option_names );
206 }
207
208 /**
209 * Retrieve all the options for the SEO plugin in one go.
210 *
211 * @return array Array combining the values of all the options.
212 */
213 public static function get_all() {
214 static::$option_values = static::get_options( static::get_option_names() );
215
216 return static::$option_values;
217 }
218
219 /**
220 * Retrieve one or more options for the SEO plugin.
221 *
222 * @param array $option_names An array of option names of the options you want to get.
223 *
224 * @return array Array combining the values of the requested options.
225 */
226 public static function get_options( array $option_names ) {
227 $options = [];
228 $option_names = array_filter( $option_names, 'is_string' );
229 foreach ( $option_names as $option_name ) {
230 if ( isset( static::$option_instances[ $option_name ] ) ) {
231 $option = static::get_option( $option_name );
232
233 if ( $option !== null ) {
234 $options = array_merge( $options, $option );
235 }
236 }
237 }
238
239 return $options;
240 }
241
242 /**
243 * Retrieve a single option for the SEO plugin.
244 *
245 * @param string $option_name The name of the option you want to get.
246 *
247 * @return array Array containing the requested option.
248 */
249 public static function get_option( $option_name ) {
250 $option = null;
251 if ( is_string( $option_name ) && ! empty( $option_name ) ) {
252 if ( isset( static::$option_instances[ $option_name ] ) ) {
253 if ( static::$option_instances[ $option_name ]->multisite_only !== true ) {
254 $option = get_option( $option_name );
255 }
256 else {
257 $option = get_site_option( $option_name );
258 }
259 }
260 }
261
262 return $option;
263 }
264
265 /**
266 * Retrieve a single field from any option for the SEO plugin. Keys are always unique.
267 *
268 * @param string $key The key it should return.
269 * @param mixed $default_value The default value that should be returned if the key isn't set.
270 *
271 * @return mixed Returns value if found, $default_value if not.
272 */
273 public static function get( $key, $default_value = null ) {
274 if ( static::$option_values === null ) {
275 static::prime_cache();
276 }
277 if ( isset( static::$option_values[ $key ] ) ) {
278 return static::$option_values[ $key ];
279 }
280
281 return $default_value;
282 }
283
284 /**
285 * Resets the cache to null.
286 */
287 public static function clear_cache() {
288 static::$option_values = null;
289 }
290
291 /**
292 * Primes our cache.
293 */
294 private static function prime_cache() {
295 static::$option_values = static::get_all();
296 static::$option_values = static::add_ms_option( static::$option_values );
297 }
298
299 /**
300 * Retrieve a single field from an option for the SEO plugin.
301 *
302 * @param string $key The key to set.
303 * @param mixed $value The value to set.
304 *
305 * @return mixed|null Returns value if found, $default if not.
306 */
307 public static function set( $key, $value ) {
308 $lookup_table = static::get_lookup_table();
309
310 if ( isset( $lookup_table[ $key ] ) ) {
311 return static::save_option( $lookup_table[ $key ], $key, $value );
312 }
313
314 $patterns = static::get_pattern_table();
315 foreach ( $patterns as $pattern => $option ) {
316 if ( strpos( $key, $pattern ) === 0 ) {
317 return static::save_option( $option, $key, $value );
318 }
319 }
320
321 static::$option_values[ $key ] = $value;
322 }
323
324 /**
325 * Get an option only if it's been auto-loaded.
326 *
327 * @param string $option The option to retrieve.
328 * @param mixed $default_value A default value to return.
329 *
330 * @return mixed
331 */
332 public static function get_autoloaded_option( $option, $default_value = false ) {
333 $value = wp_cache_get( $option, 'options' );
334 if ( $value === false ) {
335 $passed_default = func_num_args() > 1;
336
337 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Using WP native filter.
338 return apply_filters( "default_option_{$option}", $default_value, $option, $passed_default );
339 }
340
341 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Using WP native filter.
342 return apply_filters( "option_{$option}", maybe_unserialize( $value ), $option );
343 }
344
345 /**
346 * Run the clean up routine for one or all options.
347 *
348 * @param array|string|null $option_name Optional. the option you want to clean or an array of
349 * option names for the options you want to clean.
350 * If not set, all options will be cleaned.
351 * @param string|null $current_version Optional. Version from which to upgrade, if not set,
352 * version specific upgrades will be disregarded.
353 *
354 * @return void
355 */
356 public static function clean_up( $option_name = null, $current_version = null ) {
357 if ( isset( $option_name ) && is_string( $option_name ) && $option_name !== '' ) {
358 if ( isset( static::$option_instances[ $option_name ] ) ) {
359 static::$option_instances[ $option_name ]->clean( $current_version );
360 }
361 }
362 elseif ( isset( $option_name ) && is_array( $option_name ) && $option_name !== [] ) {
363 foreach ( $option_name as $option ) {
364 if ( isset( static::$option_instances[ $option ] ) ) {
365 static::$option_instances[ $option ]->clean( $current_version );
366 }
367 }
368 unset( $option );
369 }
370 else {
371 foreach ( static::$option_instances as $instance ) {
372 $instance->clean( $current_version );
373 }
374 unset( $instance );
375
376 // If we've done a full clean-up, we can safely remove this really old option.
377 delete_option( 'wpseo_indexation' );
378 }
379 }
380
381 /**
382 * Check that all options exist in the database and add any which don't.
383 *
384 * @return void
385 */
386 public static function ensure_options_exist() {
387 foreach ( static::$option_instances as $instance ) {
388 $instance->maybe_add_option();
389 }
390 }
391
392 /**
393 * Initialize some options on first install/activate/reset.
394 *
395 * @return void
396 */
397 public static function initialize() {
398 /* Force WooThemes to use Yoast SEO data. */
399 if ( function_exists( 'woo_version_init' ) ) {
400 update_option( 'seo_woo_use_third_party_data', 'true' );
401 }
402 }
403
404 /**
405 * Reset all options to their default values and rerun some tests.
406 *
407 * @return void
408 */
409 public static function reset() {
410 if ( ! is_multisite() ) {
411 $option_names = static::get_option_names();
412 if ( is_array( $option_names ) && $option_names !== [] ) {
413 foreach ( $option_names as $option_name ) {
414 delete_option( $option_name );
415 update_option( $option_name, get_option( $option_name ) );
416 }
417 }
418 unset( $option_names );
419 }
420 else {
421 // Reset MS blog based on network default blog setting.
422 static::reset_ms_blog( get_current_blog_id() );
423 }
424
425 static::initialize();
426 }
427
428 /**
429 * Initialize default values for a new multisite blog.
430 *
431 * @param bool $force_init Whether to always do the initialization routine (title/desc test).
432 *
433 * @return void
434 */
435 public static function maybe_set_multisite_defaults( $force_init = false ) {
436 $option = get_option( 'wpseo' );
437
438 if ( is_multisite() ) {
439 if ( $option['ms_defaults_set'] === false ) {
440 static::reset_ms_blog( get_current_blog_id() );
441 static::initialize();
442 }
443 elseif ( $force_init === true ) {
444 static::initialize();
445 }
446 }
447 }
448
449 /**
450 * Reset all options for a specific multisite blog to their default values based upon a
451 * specified default blog if one was chosen on the network page or the plugin defaults if it was not.
452 *
453 * @param int|string $blog_id Blog id of the blog for which to reset the options.
454 *
455 * @return void
456 */
457 public static function reset_ms_blog( $blog_id ) {
458 if ( is_multisite() ) {
459 $options = get_site_option( 'wpseo_ms' );
460 $option_names = static::get_option_names();
461
462 if ( is_array( $option_names ) && $option_names !== [] ) {
463 $base_blog_id = $blog_id;
464 if ( $options['defaultblog'] !== '' && $options['defaultblog'] !== 0 ) {
465 $base_blog_id = $options['defaultblog'];
466 }
467
468 foreach ( $option_names as $option_name ) {
469 delete_blog_option( $blog_id, $option_name );
470
471 $new_option = get_blog_option( $base_blog_id, $option_name );
472
473 /* Remove sensitive, theme dependent and site dependent info. */
474 if ( isset( static::$option_instances[ $option_name ] ) && static::$option_instances[ $option_name ]->ms_exclude !== [] ) {
475 foreach ( static::$option_instances[ $option_name ]->ms_exclude as $key ) {
476 unset( $new_option[ $key ] );
477 }
478 }
479
480 if ( $option_name === 'wpseo' ) {
481 $new_option['ms_defaults_set'] = true;
482 }
483
484 update_blog_option( $blog_id, $option_name, $new_option );
485 }
486 }
487 }
488 }
489
490 /**
491 * Saves the option to the database.
492 *
493 * @param string $wpseo_options_group_name The name for the wpseo option group in the database.
494 * @param string $option_name The name for the option to set.
495 * @param mixed $option_value The value for the option.
496 *
497 * @return bool Returns true if the option is successfully saved in the database.
498 */
499 public static function save_option( $wpseo_options_group_name, $option_name, $option_value ) {
500 $options = static::get_option( $wpseo_options_group_name );
501 $options[ $option_name ] = $option_value;
502
503 if ( isset( static::$option_instances[ $wpseo_options_group_name ] ) && static::$option_instances[ $wpseo_options_group_name ]->multisite_only === true ) {
504 static::update_site_option( $wpseo_options_group_name, $options );
505 }
506 else {
507 update_option( $wpseo_options_group_name, $options );
508 }
509
510 // Check if everything got saved properly.
511 $saved_option = static::get_option( $wpseo_options_group_name );
512
513 // Clear our cache.
514 static::clear_cache();
515
516 return $saved_option[ $option_name ] === $options[ $option_name ];
517 }
518
519 /**
520 * Adds the multisite options to the option stack if relevant.
521 *
522 * @param array $option The currently present options settings.
523 *
524 * @return array Options possibly including multisite.
525 */
526 protected static function add_ms_option( $option ) {
527 if ( ! is_multisite() ) {
528 return $option;
529 }
530
531 $ms_option = static::get_option( 'wpseo_ms' );
532 if ( $ms_option === null ) {
533 return $option;
534 }
535
536 return array_merge( $option, $ms_option );
537 }
538
539 /**
540 * Checks if installation is multisite.
541 *
542 * @return bool True when is multisite.
543 */
544 protected static function is_multisite() {
545 static $is_multisite;
546
547 if ( $is_multisite === null ) {
548 $is_multisite = is_multisite();
549 }
550
551 return $is_multisite;
552 }
553
554 /**
555 * Retrieves a lookup table to find in which option_group a key is stored.
556 *
557 * @return array The lookup table.
558 */
559 private static function get_lookup_table() {
560 $lookup_table = [];
561
562
563 foreach ( array_keys( static::$options ) as $option_name ) {
564 $full_option = static::get_option( $option_name );
565 foreach ( $full_option as $key => $value ) {
566 $lookup_table[ $key ] = $option_name;
567 }
568 }
569
570 return $lookup_table;
571 }
572
573 /**
574 * Retrieves a lookup table to find in which option_group a key is stored.
575 *
576 * @return array The lookup table.
577 */
578 private static function get_pattern_table() {
579 $pattern_table = [];
580 foreach ( static::$options as $option_name => $option_class ) {
581 $instance = call_user_func( [ $option_class, 'get_instance' ] );
582 foreach ( $instance->get_patterns() as $key ) {
583 $pattern_table[ $key ] = $option_name;
584 }
585 }
586
587 return $pattern_table;
588 }
589 }
590