PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 All 508 releases
← All changes | jetpack_vendor/automattic/jetpack-sync/src/class-settings.php +749 -0 16.2-beta → 16.3 View file →
@@ -1,0 +1,749 @@
1 +<?php
2 +/**
3 + * Sync settings.
4 + *
5 + * @package automattic/jetpack-sync
6 + */
7 +
8 +namespace Automattic\Jetpack\Sync;
9 +
10 +use Automattic\Jetpack\Constants;
11 +use Automattic\Jetpack\Sync\Queue\Queue_Storage_Table;
12 +
13 +/**
14 + * Class to manage the sync settings.
15 + */
16 +class Settings {
17 + /**
18 + * Prefix, used for the sync settings option names.
19 + *
20 + * @access public
21 + *
22 + * @var string
23 + */
24 + const SETTINGS_OPTION_PREFIX = 'jetpack_sync_settings_';
25 +
26 + /**
27 + * A whitelist of valid settings.
28 + *
29 + * @access public
30 + * @static
31 + *
32 + * @var array
33 + */
34 + public static $valid_settings = array(
35 + 'dequeue_max_bytes' => true,
36 + 'upload_max_bytes' => true,
37 + 'upload_max_rows' => true,
38 + 'sync_wait_time' => true,
39 + 'sync_wait_threshold' => true,
40 + 'enqueue_wait_time' => true,
41 + 'max_queue_size' => true,
42 + 'max_queue_lag' => true,
43 + 'queue_max_writes_sec' => true,
44 + 'post_types_blacklist' => true,
45 + 'taxonomies_blacklist' => true,
46 + 'disable' => true,
47 + 'network_disable' => true,
48 + 'render_filtered_content' => true,
49 + 'post_meta_whitelist' => true,
50 + 'comment_meta_whitelist' => true,
51 + 'max_enqueue_full_sync' => true,
52 + 'max_queue_size_full_sync' => true,
53 + 'sync_via_cron' => true,
54 + 'cron_sync_time_limit' => true,
55 + 'known_importers' => true,
56 + 'term_relationships_full_sync_item_size' => true,
57 + 'sync_sender_enabled' => true,
58 + 'full_sync_sender_enabled' => true,
59 + 'full_sync_send_duration' => true,
60 + 'full_sync_limits' => true,
61 + 'checksum_disable' => true,
62 + 'dedicated_sync_enabled' => true,
63 + 'custom_queue_table_enabled' => true,
64 + 'wpcom_rest_api_enabled' => true,
65 + 'sync_actions_blacklist' => true,
66 + );
67 +
68 + /**
69 + * Whether WordPress is currently running an import.
70 + *
71 + * @access public
72 + * @static
73 + *
74 + * @var null|boolean
75 + */
76 + public static $is_importing;
77 +
78 + /**
79 + * Whether WordPress is currently running a WP cron request.
80 + *
81 + * @access public
82 + * @static
83 + *
84 + * @var null|boolean
85 + */
86 + public static $is_doing_cron;
87 +
88 + /**
89 + * Whether we're currently syncing.
90 + *
91 + * @access public
92 + * @static
93 + *
94 + * @var null|boolean
95 + */
96 + public static $is_syncing;
97 +
98 + /**
99 + * Whether we're currently sending sync items.
100 + *
101 + * @access public
102 + * @static
103 + *
104 + * @var null|boolean
105 + */
106 + public static $is_sending;
107 +
108 + /**
109 + * Retrieve all settings with their current values.
110 + *
111 + * @access public
112 + * @static
113 + *
114 + * @return array All current settings.
115 + */
116 + public static function get_settings() {
117 + $settings = array();
118 + foreach ( array_keys( self::$valid_settings ) as $setting ) {
119 + $settings[ $setting ] = static::get_setting( $setting );
120 + }
121 +
122 + return $settings;
123 + }
124 +
125 + /**
126 + * Fetches the setting. It saves it if the setting doesn't exist, so that it gets
127 + * autoloaded on page load rather than re-queried every time.
128 + *
129 + * @access public
130 + * @static
131 + *
132 + * @param string $setting The setting name.
133 + * @return mixed The setting value.
134 + */
135 + public static function get_setting( $setting ) {
136 + if ( ! isset( self::$valid_settings[ $setting ] ) ) {
137 + return false;
138 + }
139 +
140 + if ( self::is_network_setting( $setting ) ) {
141 + if ( is_multisite() ) {
142 + $value = get_site_option( self::SETTINGS_OPTION_PREFIX . $setting );
143 + } else {
144 + // On single sites just return the default setting.
145 + return Defaults::get_default_setting( $setting );
146 + }
147 + } else {
148 + $value = get_option( self::SETTINGS_OPTION_PREFIX . $setting );
149 + }
150 +
151 + if ( false === $value ) { // No default value is set.
152 + $value = Defaults::get_default_setting( $setting );
153 + if ( self::is_network_setting( $setting ) ) {
154 + update_site_option( self::SETTINGS_OPTION_PREFIX . $setting, $value );
155 + } else {
156 + // We set one so that it gets autoloaded.
157 + update_option( self::SETTINGS_OPTION_PREFIX . $setting, $value, true );
158 + }
159 + }
160 +
161 + if ( is_numeric( $value ) ) {
162 + $value = (int) $value;
163 + }
164 + $default_array_value = null;
165 + switch ( $setting ) {
166 + case 'post_types_blacklist':
167 + $default_array_value = Defaults::$blacklisted_post_types;
168 + break;
169 + case 'taxonomies_blacklist':
170 + $default_array_value = Defaults::$blacklisted_taxonomies;
171 + break;
172 + case 'post_meta_whitelist':
173 + $default_array_value = Defaults::get_post_meta_whitelist();
174 + break;
175 + case 'comment_meta_whitelist':
176 + $default_array_value = Defaults::get_comment_meta_whitelist();
177 + break;
178 + case 'known_importers':
179 + $default_array_value = Defaults::get_known_importers();
180 + break;
181 + }
182 +
183 + if ( $default_array_value ) {
184 + if ( is_array( $value ) ) {
185 + $value = array_unique( array_merge( $value, $default_array_value ) );
186 + } else {
187 + $value = $default_array_value;
188 + }
189 + }
190 +
191 + return $value;
192 + }
193 +
194 + /**
195 + * Change multiple settings in the same time.
196 + *
197 + * @access public
198 + * @static
199 + *
200 + * @param array $new_settings The new settings.
201 + */
202 + public static function update_settings( $new_settings ) {
203 + $validated_settings = array_intersect_key( $new_settings, self::$valid_settings );
204 + foreach ( $validated_settings as $setting => $value ) {
205 +
206 + /**
207 + * Custom table migration logic.
208 + *
209 + * This needs to happen before the option is updated, to avoid race conditions where we update the option,
210 + * but haven't yet created the table or can't create it.
211 + *
212 + * On high-traffic sites this can lead to Sync trying to write in a non-existent table.
213 + *
214 + * So to avoid this, we're going to first try to initialize everything and then update the option.
215 + */
216 + if ( 'custom_queue_table_enabled' === $setting ) {
217 + // Need to check the current value in the database to make sure we're not doing anything weird.
218 + $old_value = get_option( self::SETTINGS_OPTION_PREFIX . $setting, null );
219 +
220 + if ( ! $old_value && $value ) {
221 + /**
222 + * The custom table has been enabled.
223 + *
224 + * - Initialize the custom table
225 + * - Migrate the data
226 + *
227 + * If something fails, migrate back to the options table and clean up everything about the custom table.
228 + */
229 + $init_result = Queue_Storage_Table::initialize_custom_sync_table();
230 +
231 + /**
232 + * Check if there was a problem when initializing the table.
233 + */
234 + if ( is_wp_error( $init_result ) ) {
235 + /**
236 + * Unable to initialize the table properly. Set the value to `false` as we can't enable it.
237 + */
238 + $value = false;
239 +
240 + /**
241 + * Send error to WPCOM, so we can track and take an appropriate action.
242 + */
243 + $data = array(
244 + 'timestamp' => microtime( true ),
245 + 'error_code' => $init_result->get_error_code(),
246 + 'response_body' => $init_result->get_error_message(),
247 + );
248 +
249 + $sender = Sender::get_instance();
250 + $sender->send_action( 'jetpack_sync_storage_error_custom_init', $data );
251 +
252 + } elseif ( ! Queue_Storage_Table::migrate_from_options_table_to_custom_table() ) {
253 + /**
254 + * If the migration fails, do a reverse migration and set the value to `false` as we can't
255 + * safely enable the table.
256 + */
257 + Queue_Storage_Table::migrate_from_custom_table_to_options_table();
258 +
259 + // Set $value to `false` as we couldn't do the migration, and we can't continue enabling the table.
260 + $value = false;
261 +
262 + /**
263 + * Send error to WPCOM, so we can track and take an appropriate action.
264 + */
265 + $data = array(
266 + 'timestamp' => microtime( true ),
267 + // TODO: Maybe add more details here for the migration, i.e. how many items where in the queue?
268 + );
269 +
270 + $sender = Sender::get_instance();
271 + $sender->send_action( 'jetpack_sync_storage_error_custom_migrate', $data );
272 + }
273 + } elseif ( $old_value && ! $value ) {
274 + if ( ! get_transient( Queue_Storage_Table::CUSTOM_QUEUE_TABLE_DISABLE_WPDB_ERROR_NOT_EXIST_FLAG ) ) {
275 + /**
276 + * The custom table has been disabled, migrate what we can from the custom table to the options table unless
277 + * the custom table doesn't exist in the DB.
278 + */
279 + Queue_Storage_Table::migrate_from_custom_table_to_options_table();
280 + }
281 + }
282 + }
283 +
284 + /**
285 + * Regular option update and handling
286 + */
287 + $updated = false;
288 + if ( self::is_network_setting( $setting ) ) {
289 + if ( is_multisite() && is_main_site() ) {
290 + $updated = update_site_option( self::SETTINGS_OPTION_PREFIX . $setting, $value );
291 + }
292 + } else {
293 + $updated = update_option( self::SETTINGS_OPTION_PREFIX . $setting, $value, true );
294 + }
295 +
296 + // If we set the disabled option to true, clear the queues.
297 + if ( ( 'disable' === $setting || 'network_disable' === $setting ) && (bool) $value ) {
298 + $listener = Listener::get_instance();
299 + $listener->get_sync_queue()->reset();
300 + $listener->get_full_sync_queue()->reset();
301 + }
302 +
303 + // Do not enable Dedicated Sync if we cannot spawn a Dedicated Sync request.
304 + if ( 'dedicated_sync_enabled' === $setting && $updated && (bool) $value ) {
305 + if ( ! Dedicated_Sender::can_spawn_dedicated_sync_request() ) {
306 + update_option( self::SETTINGS_OPTION_PREFIX . $setting, 0, true );
307 + $listener = Listener::get_instance();
308 + // Remove the last two actions from the queue since we failed to enable Dedicated Sync.
309 + // Those would be `updated_option` with `jetpack_sync_settings_dedicated_sync_enabled` set to 1 and then 0 again.
310 + $queue = $listener->get_sync_queue();
311 + $items = $queue->peek_newest( 2 );
312 + $key = 'jetpack_sync_settings_dedicated_sync_enabled';
313 +
314 + if (
315 + isset( $items[0][1][0] )
316 + && isset( $items[1][1][0] )
317 + && $items[0][1][0] === $key
318 + && $items[1][1][0] === $key
319 + ) {
320 + $queue->pop_newest( 2 );
321 + }
322 + }
323 + }
324 + }
325 + }
326 +
327 + /**
328 + * Whether the specified setting is a network setting.
329 + *
330 + * @access public
331 + * @static
332 + *
333 + * @param string $setting Setting name.
334 + * @return boolean Whether the setting is a network setting.
335 + */
336 + public static function is_network_setting( $setting ) {
337 + return str_starts_with( $setting, 'network_' );
338 + }
339 +
340 + /**
341 + * Returns escaped SQL for blacklisted post types.
342 + * Can be injected directly into a WHERE clause.
343 + *
344 + * @access public
345 + * @static
346 + *
347 + * @return string SQL WHERE clause.
348 + */
349 + public static function get_blacklisted_post_types_sql() {
350 + return 'post_type NOT IN (\'' . implode( '\', \'', array_map( 'esc_sql', static::get_setting( 'post_types_blacklist' ) ) ) . '\')';
351 + }
352 +
353 + /**
354 + * Returns escaped values for disallowed post types.
355 + *
356 + * @access public
357 + * @static
358 + *
359 + * @return array Post type filter values
360 + */
361 + public static function get_disallowed_post_types_structured() {
362 + return array(
363 + 'post_type' => array(
364 + 'operator' => 'NOT IN',
365 + 'values' => array_map( 'esc_sql', static::get_setting( 'post_types_blacklist' ) ),
366 + ),
367 + );
368 + }
369 +
370 + /**
371 + * Returns escaped SQL for blacklisted taxonomies.
372 + * Can be injected directly into a WHERE clause.
373 + *
374 + * @access public
375 + * @static
376 + *
377 + * @return string SQL WHERE clause.
378 + */
379 + public static function get_blacklisted_taxonomies_sql() {
380 + return "taxonomy NOT IN ('" . implode( "', '", array_map( 'esc_sql', static::get_setting( 'taxonomies_blacklist' ) ) ) . "')";
381 + }
382 +
383 + /**
384 + * Returns escaped SQL for whitelisted taxonomies.
385 + * Can be injected directly into a WHERE clause.
386 + *
387 + * @access public
388 + * @static
389 + *
390 + * @return string SQL WHERE clause.
391 + */
392 + public static function get_whitelisted_taxonomies_sql() {
393 + global $wp_taxonomies;
394 +
395 + $allowed_taxonomies = array_keys( $wp_taxonomies );
396 + $allowed_taxonomies = array_diff( $allowed_taxonomies, static::get_setting( 'taxonomies_blacklist' ) );
397 +
398 + return "taxonomy IN ('" . implode( "', '", array_map( 'esc_sql', $allowed_taxonomies ) ) . "')";
399 + }
400 +
401 + /**
402 + * Returns escaped SQL for blacklisted post meta.
403 + * Can be injected directly into a WHERE clause.
404 + *
405 + * @access public
406 + * @static
407 + *
408 + * @return string SQL WHERE clause.
409 + */
410 + public static function get_whitelisted_post_meta_sql() {
411 + return 'meta_key IN (\'' . implode( '\', \'', array_map( 'esc_sql', static::get_setting( 'post_meta_whitelist' ) ) ) . '\')';
412 + }
413 +
414 + /**
415 + * Returns escaped SQL for allowed post meta keys.
416 + *
417 + * @access public
418 + * @static
419 + *
420 + * @return array Meta keys filter values
421 + */
422 + public static function get_allowed_post_meta_structured() {
423 + return array(
424 + 'meta_key' => array(
425 + 'operator' => 'IN',
426 + 'values' => array_map( 'esc_sql', static::get_setting( 'post_meta_whitelist' ) ),
427 + ),
428 + );
429 + }
430 +
431 + /**
432 + * Returns structured SQL clause for blacklisted taxonomies.
433 + *
434 + * @access public
435 + * @static
436 + *
437 + * @return array taxonomies filter values
438 + */
439 + public static function get_blacklisted_taxonomies_structured() {
440 + return array(
441 + 'taxonomy' => array(
442 + 'operator' => 'NOT IN',
443 + 'values' => array_map( 'esc_sql', static::get_setting( 'taxonomies_blacklist' ) ),
444 + ),
445 + );
446 + }
447 +
448 + /**
449 + * Returns structured SQL clause for allowed taxonomies.
450 + *
451 + * @access public
452 + * @static
453 + *
454 + * @return array taxonomies filter values
455 + */
456 + public static function get_allowed_taxonomies_structured() {
457 + global $wp_taxonomies;
458 +
459 + $allowed_taxonomies = array_keys( $wp_taxonomies );
460 + $allowed_taxonomies = array_diff( $allowed_taxonomies, static::get_setting( 'taxonomies_blacklist' ) );
461 + return array(
462 + 'taxonomy' => array(
463 + 'operator' => 'IN',
464 + 'values' => array_map( 'esc_sql', $allowed_taxonomies ),
465 + ),
466 + );
467 + }
468 +
469 + /**
470 + * Returns escaped SQL for blacklisted comment meta.
471 + * Can be injected directly into a WHERE clause.
472 + *
473 + * @access public
474 + * @static
475 + *
476 + * @return string SQL WHERE clause.
477 + */
478 + public static function get_whitelisted_comment_meta_sql() {
479 + return 'meta_key IN (\'' . implode( '\', \'', array_map( 'esc_sql', static::get_setting( 'comment_meta_whitelist' ) ) ) . '\')';
480 + }
481 +
482 + /**
483 + * Returns SQL-escaped values for allowed post meta keys.
484 + *
485 + * @access public
486 + * @static
487 + *
488 + * @return array Meta keys filter values
489 + */
490 + public static function get_allowed_comment_meta_structured() {
491 + return array(
492 + 'meta_key' => array(
493 + 'operator' => 'IN',
494 + 'values' => array_map( 'esc_sql', static::get_setting( 'comment_meta_whitelist' ) ),
495 + ),
496 + );
497 + }
498 +
499 + /**
500 + * Returns SQL-escaped values for allowed order_item meta keys.
501 + *
502 + * @access public
503 + * @static
504 + *
505 + * @return array Meta keys filter values
506 + */
507 + public static function get_allowed_order_itemmeta_structured() {
508 + // Make sure that we only try to add the properties when the class exists.
509 + if ( ! class_exists( '\Automattic\Jetpack\Sync\Modules\WooCommerce' ) ) {
510 + return array();
511 + }
512 +
513 + $values = \Automattic\Jetpack\Sync\Modules\WooCommerce::$order_item_meta_whitelist;
514 +
515 + return array(
516 + 'meta_key' => array(
517 + 'operator' => 'IN',
518 + 'values' => array_map( 'esc_sql', $values ),
519 + ),
520 + );
521 + }
522 +
523 + /**
524 + * Returns structured filter values for allowed comment types.
525 + *
526 + * @access public
527 + * @static
528 + *
529 + * @return array Comment type filter values.
530 + */
531 + public static function get_allowed_comment_types_structured() {
532 + return array(
533 + 'comment_type' => array(
534 + 'operator' => 'IN',
535 + 'values' => array_map( 'esc_sql', Defaults::get_comment_types_whitelist() ),
536 + ),
537 + );
538 + }
539 +
540 + /**
541 + * Returns escaped SQL for comments, excluding any spam comments.
542 + * Can be injected directly into a WHERE clause.
543 + *
544 + * @access public
545 + * @static
546 + *
547 + * @return string SQL WHERE clause.
548 + */
549 + public static function get_comments_filter_sql() {
550 + return "comment_approved <> 'spam'";
551 + }
552 +
553 + /**
554 + * Delete any settings options and clean up the current settings state.
555 + *
556 + * @access public
557 + * @static
558 + */
559 + public static function reset_data() {
560 + $valid_settings = self::$valid_settings;
561 + foreach ( $valid_settings as $option => $value ) {
562 + delete_option( self::SETTINGS_OPTION_PREFIX . $option );
563 + }
564 + self::set_importing( null );
565 + self::set_doing_cron( null );
566 + self::set_is_syncing( null );
567 + self::set_is_sending( null );
568 + }
569 +
570 + /**
571 + * Set the importing state.
572 + *
573 + * @access public
574 + * @static
575 + *
576 + * @param boolean $is_importing Whether WordPress is currently importing.
577 + */
578 + public static function set_importing( $is_importing ) {
579 + // Set to NULL to revert to WP_IMPORTING, the standard behavior.
580 + self::$is_importing = $is_importing;
581 + }
582 +
583 + /**
584 + * Whether WordPress is currently importing.
585 + *
586 + * @access public
587 + * @static
588 + *
589 + * @return boolean Whether WordPress is currently importing.
590 + */
591 + public static function is_importing() {
592 + if ( self::$is_importing !== null ) {
593 + return self::$is_importing;
594 + }
595 +
596 + return defined( 'WP_IMPORTING' ) && WP_IMPORTING;
597 + }
598 +
599 + /**
600 + * Whether sync is enabled.
601 + *
602 + * @access public
603 + * @static
604 + *
605 + * @return boolean Whether sync is enabled.
606 + */
607 + public static function is_sync_enabled() {
608 + return ! ( static::get_setting( 'disable' ) || static::get_setting( 'network_disable' ) );
609 + }
610 +
611 + /**
612 + * Set the WP cron state.
613 + *
614 + * @access public
615 + * @static
616 + *
617 + * @param boolean $is_doing_cron Whether WordPress is currently doing WP cron.
618 + */
619 + public static function set_doing_cron( $is_doing_cron ) {
620 + // Set to NULL to revert to WP_IMPORTING, the standard behavior.
621 + self::$is_doing_cron = $is_doing_cron;
622 + }
623 +
624 + /**
625 + * Whether WordPress is currently doing WP cron.
626 + *
627 + * @access public
628 + * @static
629 + *
630 + * @return boolean Whether WordPress is currently doing WP cron.
631 + */
632 + public static function is_doing_cron() {
633 + if ( self::$is_doing_cron !== null ) {
634 + return self::$is_doing_cron;
635 + }
636 +
637 + return defined( 'DOING_CRON' ) && DOING_CRON;
638 + }
639 +
640 + /**
641 + * Whether we are currently syncing.
642 + *
643 + * @access public
644 + * @static
645 + *
646 + * @return boolean Whether we are currently syncing.
647 + */
648 + public static function is_syncing() {
649 + return (bool) self::$is_syncing || Constants::is_true( 'REST_API_REQUEST' );
650 + }
651 +
652 + /**
653 + * Set the syncing state.
654 + *
655 + * @access public
656 + * @static
657 + *
658 + * @param boolean $is_syncing Whether we are currently syncing.
659 + */
660 + public static function set_is_syncing( $is_syncing ) {
661 + self::$is_syncing = $is_syncing;
662 + }
663 +
664 + /**
665 + * Whether we are currently sending sync items.
666 + *
667 + * @access public
668 + * @static
669 + *
670 + * @return boolean Whether we are currently sending sync items.
671 + */
672 + public static function is_sending() {
673 + return (bool) self::$is_sending;
674 + }
675 +
676 + /**
677 + * Set the sending state.
678 + *
679 + * @access public
680 + * @static
681 + *
682 + * @param boolean $is_sending Whether we are currently sending sync items.
683 + */
684 + public static function set_is_sending( $is_sending ) {
685 + self::$is_sending = $is_sending;
686 + }
687 +
688 + /**
689 + * Whether should send from the queue
690 + *
691 + * @access public
692 + * @static
693 + *
694 + * @param string $queue_id The queue identifier.
695 + *
696 + * @return boolean Whether sync is enabled.
697 + */
698 + public static function is_sender_enabled( $queue_id ) {
699 + return (bool) static::get_setting( $queue_id . '_sender_enabled' );
700 + }
701 +
702 + /**
703 + * Whether checksums are enabled.
704 + *
705 + * @access public
706 + * @static
707 + *
708 + * @return boolean Whether sync is enabled.
709 + */
710 + public static function is_checksum_enabled() {
711 + return ! (bool) static::get_setting( 'checksum_disable' );
712 + }
713 +
714 + /**
715 + * Whether dedicated Sync flow is enabled.
716 + *
717 + * @access public
718 + * @static
719 + *
720 + * @return boolean Whether dedicated Sync flow is enabled.
721 + */
722 + public static function is_dedicated_sync_enabled() {
723 + return (bool) static::get_setting( 'dedicated_sync_enabled' );
724 + }
725 +
726 + /**
727 + * Whether custom queue table is enabled.
728 + *
729 + * @access public
730 + * @static
731 + *
732 + * @return boolean Whether custom queue table is enabled.
733 + */
734 + public static function is_custom_queue_table_enabled() {
735 + return (bool) static::get_setting( 'custom_queue_table_enabled' );
736 + }
737 +
738 + /**
739 + * Whether wpcom rest api is enabled.
740 + *
741 + * @access public
742 + * @static
743 + *
744 + * @return boolean Whether wpcom rest api is enabled.
745 + */
746 + public static function is_wpcom_rest_api_enabled() {
747 + return (bool) static::get_setting( 'wpcom_rest_api_enabled' );
748 + }
749 +}