← All changes
|
jetpack_vendor/automattic/jetpack-sync/src/modules/class-themes.php
+32
-27
12.4.2
→
16.3-beta
View file →
| @@ -6,8 +6,12 @@ | ||
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | namespace Automattic\Jetpack\Sync\Modules; |
| 9 | 9 | |
| 10 | +if ( ! defined( 'ABSPATH' ) ) { | |
| 11 | + exit( 0 ); | |
| 12 | +} | |
| 13 | + | |
| 10 | 14 | /** |
| 11 | 15 | * Class to handle sync for themes. |
| 12 | 16 | */ |
| 13 | 17 | class Themes extends Module { |
| @@ -62,10 +66,8 @@ | ||
| 62 | 66 | * Sync handler for a widget edit. |
| 63 | 67 | * |
| 64 | 68 | * @access public |
| 65 | 69 | * |
| 66 | - * @todo Implement nonce verification | |
| 67 | - * | |
| 68 | 70 | * @param array $instance The current widget instance's settings. |
| 69 | 71 | * @param array $new_instance Array of new widget settings. |
| 70 | 72 | * @param array $old_instance Array of old widget settings. |
| 71 | 73 | * @param \WP_Widget $widget_object The current widget instance. |
| @@ -76,9 +78,9 @@ | ||
| 76 | 78 | return $instance; |
| 77 | 79 | } |
| 78 | 80 | |
| 79 | 81 | // Don't trigger sync action if this is an ajax request, because Customizer makes them during preview before saving changes. |
| 80 | - // phpcs:disable WordPress.Security.NonceVerification.Missing | |
| 82 | + // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Not doing anything with or in response to the $_POST data. We're only using $_POST['customized'] to early return if this is an ajax request from Customizer. | |
| 81 | 83 | if ( defined( 'DOING_AJAX' ) && DOING_AJAX && isset( $_POST['customized'] ) ) { |
| 82 | 84 | return $instance; |
| 83 | 85 | } |
| 84 | 86 | |
| @@ -84,9 +86,9 @@ | ||
| 84 | 86 | |
| 85 | 87 | $widget = array( |
| 86 | 88 | 'name' => $widget_object->name, |
| 87 | 89 | 'id' => $widget_object->id, |
| 88 | - 'title' => isset( $new_instance['title'] ) ? $new_instance['title'] : '', | |
| 90 | + 'title' => $new_instance['title'] ?? '', | |
| 89 | 91 | ); |
| 90 | 92 | /** |
| 91 | 93 | * Trigger action to alert $callable sync listener that a widget was edited. |
| 92 | 94 | * |
| @@ -184,9 +186,9 @@ | ||
| 184 | 186 | public function detect_theme_edit( $redirect_url ) { |
| 185 | 187 | $url = wp_parse_url( admin_url( $redirect_url ) ); |
| 186 | 188 | $theme_editor_url = wp_parse_url( admin_url( 'theme-editor.php' ) ); |
| 187 | 189 | |
| 188 | - if ( $theme_editor_url['path'] !== $url['path'] ) { | |
| 190 | + if ( ! isset( $url['query'] ) || $theme_editor_url['path'] !== $url['path'] ) { | |
| 189 | 191 | return $redirect_url; |
| 190 | 192 | } |
| 191 | 193 | |
| 192 | 194 | $query_params = array(); |
| @@ -191,9 +193,9 @@ | ||
| 191 | 193 | |
| 192 | 194 | $query_params = array(); |
| 193 | 195 | wp_parse_str( $url['query'], $query_params ); |
| 194 | 196 | if ( |
| 195 | - ! isset( $_POST['newcontent'] ) || | |
| 197 | + ! isset( $_POST['newcontent'] ) || // phpcs:ignore WordPress.Security.NonceVerification.Missing -- 'wp_redirect' gets fired for a lot of things. We're only using $_POST['newcontent'] to limit action to redirects from theme edits, we're not doing anything with or in response to the post itself. | |
| 196 | 198 | ! isset( $query_params['file'] ) || |
| 197 | 199 | ! isset( $query_params['theme'] ) || |
| 198 | 200 | ! isset( $query_params['updated'] ) |
| 199 | 201 | ) { |
| @@ -225,31 +227,30 @@ | ||
| 225 | 227 | * |
| 226 | 228 | * @todo Refactor to use WP_Filesystem instead of fopen()/fclose(). |
| 227 | 229 | */ |
| 228 | 230 | public function theme_edit_ajax() { |
| 229 | - $args = wp_unslash( $_POST ); | |
| 230 | - | |
| 231 | - if ( empty( $args['theme'] ) ) { | |
| 231 | + // This validation is based on wp_edit_theme_plugin_file(). | |
| 232 | + if ( empty( $_POST['theme'] ) ) { | |
| 232 | 233 | return; |
| 233 | 234 | } |
| 234 | 235 | |
| 235 | - if ( empty( $args['file'] ) ) { | |
| 236 | + if ( empty( $_POST['file'] ) ) { | |
| 236 | 237 | return; |
| 237 | 238 | } |
| 238 | - $file = $args['file']; | |
| 239 | + $file = wp_unslash( $_POST['file'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Validated manually just after. | |
| 239 | 240 | if ( 0 !== validate_file( $file ) ) { |
| 240 | 241 | return; |
| 241 | 242 | } |
| 242 | 243 | |
| 243 | - if ( ! isset( $args['newcontent'] ) ) { | |
| 244 | + if ( ! isset( $_POST['newcontent'] ) ) { | |
| 244 | 245 | return; |
| 245 | 246 | } |
| 246 | 247 | |
| 247 | - if ( ! isset( $args['nonce'] ) ) { | |
| 248 | + if ( ! isset( $_POST['nonce'] ) ) { | |
| 248 | 249 | return; |
| 249 | 250 | } |
| 250 | 251 | |
| 251 | - $stylesheet = $args['theme']; | |
| 252 | + $stylesheet = wp_unslash( $_POST['theme'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Validated manually just after. | |
| 252 | 253 | if ( 0 !== validate_file( $stylesheet ) ) { |
| 253 | 254 | return; |
| 254 | 255 | } |
| 255 | 256 | |
| @@ -261,9 +262,9 @@ | ||
| 261 | 262 | if ( ! $theme->exists() ) { |
| 262 | 263 | return; |
| 263 | 264 | } |
| 264 | 265 | |
| 265 | - if ( ! wp_verify_nonce( $args['nonce'], 'edit-theme_' . $stylesheet . '_' . $file ) ) { | |
| 266 | + if ( ! wp_verify_nonce( $_POST['nonce'], 'edit-theme_' . $stylesheet . '_' . $file ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- WP core doesn't pre-sanitize nonces either. | |
| 266 | 267 | return; |
| 267 | 268 | } |
| 268 | 269 | |
| 269 | 270 | if ( $theme->errors() && 'theme_no_stylesheet' === $theme->errors()->get_error_code() ) { |
| @@ -382,8 +383,9 @@ | ||
| 382 | 383 | return; |
| 383 | 384 | } |
| 384 | 385 | |
| 385 | 386 | if ( 'install' === $details['action'] ) { |
| 387 | + // @phan-suppress-next-line PhanUndeclaredMethod -- Checked above. See also https://github.com/phan/phan/issues/1204. | |
| 386 | 388 | $theme = $upgrader->theme_info(); |
| 387 | 389 | if ( ! $theme instanceof \WP_Theme ) { |
| 388 | 390 | return; |
| 389 | 391 | } |
| @@ -510,19 +512,25 @@ | ||
| 510 | 512 | * |
| 511 | 513 | * @access public |
| 512 | 514 | * |
| 513 | 515 | * @param array $config Full sync configuration for this sync module. |
| 516 | + * @param array $status This module Full Sync status. | |
| 514 | 517 | * @param int $send_until The timestamp until the current request can send. |
| 515 | - * @param array $state This module Full Sync status. | |
| 518 | + * @param int $started The timestamp when the full sync started. | |
| 516 | 519 | * |
| 517 | 520 | * @return array This module Full Sync status. |
| 518 | 521 | */ |
| 519 | - public function send_full_sync_actions( $config, $send_until, $state ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable | |
| 522 | + public function send_full_sync_actions( $config, $status, $send_until, $started ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable | |
| 520 | 523 | // we call this instead of do_action when sending immediately. |
| 521 | - $this->send_action( 'jetpack_full_sync_theme_data', array( true ) ); | |
| 524 | + $result = $this->send_action( 'jetpack_full_sync_theme_data', array( true ) ); | |
| 522 | 525 | |
| 523 | - // The number of actions enqueued, and next module state (true == done). | |
| 524 | - return array( 'finished' => true ); | |
| 526 | + if ( is_wp_error( $result ) ) { | |
| 527 | + $status['error'] = true; | |
| 528 | + return $status; | |
| 529 | + } | |
| 530 | + $status['finished'] = true; | |
| 531 | + $status['sent'] = $status['total']; | |
| 532 | + return $status; | |
| 525 | 533 | } |
| 526 | 534 | |
| 527 | 535 | /** |
| 528 | 536 | * Retrieve an estimated number of actions that will be enqueued. |
| @@ -529,9 +537,9 @@ | ||
| 529 | 537 | * |
| 530 | 538 | * @access public |
| 531 | 539 | * |
| 532 | 540 | * @param array $config Full sync configuration for this sync module. |
| 533 | - * @return array Number of items yet to be enqueued. | |
| 541 | + * @return int Number of items yet to be enqueued. | |
| 534 | 542 | */ |
| 535 | 543 | public function estimate_full_sync_actions( $config ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable |
| 536 | 544 | return 1; |
| 537 | 545 | } |
| @@ -736,22 +744,20 @@ | ||
| 736 | 744 | } |
| 737 | 745 | |
| 738 | 746 | $moved_to_inactive_ids = array(); |
| 739 | 747 | $moved_to_sidebar = array(); |
| 748 | + $new_inactive_widgets = $new_value['wp_inactive_widgets'] ?? array(); | |
| 740 | 749 | |
| 741 | 750 | foreach ( $new_value as $sidebar => $new_widgets ) { |
| 742 | 751 | if ( in_array( $sidebar, array( 'array_version', 'wp_inactive_widgets' ), true ) ) { |
| 743 | 752 | continue; |
| 744 | 753 | } |
| 745 | - $old_widgets = isset( $old_value[ $sidebar ] ) | |
| 746 | - ? $old_value[ $sidebar ] | |
| 747 | - : array(); | |
| 754 | + $old_widgets = $old_value[ $sidebar ] ?? array(); | |
| 748 | 755 | |
| 749 | 756 | if ( ! is_array( $new_widgets ) ) { |
| 750 | 757 | $new_widgets = array(); |
| 751 | 758 | } |
| 752 | - | |
| 753 | - $moved_to_inactive_recently = $this->sync_remove_widgets_from_sidebar( $new_widgets, $old_widgets, $sidebar, $new_value['wp_inactive_widgets'] ); | |
| 759 | + $moved_to_inactive_recently = $this->sync_remove_widgets_from_sidebar( $new_widgets, $old_widgets, $sidebar, $new_inactive_widgets ); | |
| 754 | 760 | $moved_to_inactive_ids = array_merge( $moved_to_inactive_ids, $moved_to_inactive_recently ); |
| 755 | 761 | |
| 756 | 762 | $moved_to_sidebar_recently = $this->sync_add_widgets_to_sidebar( $new_widgets, $old_widgets, $sidebar ); |
| 757 | 763 | $moved_to_sidebar = array_merge( $moved_to_sidebar, $moved_to_sidebar_recently ); |
| @@ -872,6 +878,5 @@ | ||
| 872 | 878 | } |
| 873 | 879 | |
| 874 | 880 | return array( $this->get_theme_info() ); |
| 875 | 881 | } |
| 876 | - | |
| 877 | 882 | } |