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/modules/class-themes.php +31 -26 13.4.5 → 16.3 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() ) {
@@ -511,19 +512,25 @@
511 512 *
512 513 * @access public
513 514 *
514 515 * @param array $config Full sync configuration for this sync module.
516 + * @param array $status This module Full Sync status.
515 517 * @param int $send_until The timestamp until the current request can send.
516 - * @param array $state This module Full Sync status.
518 + * @param int $started The timestamp when the full sync started.
517 519 *
518 520 * @return array This module Full Sync status.
519 521 */
520 - 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
521 523 // we call this instead of do_action when sending immediately.
522 - $this->send_action( 'jetpack_full_sync_theme_data', array( true ) );
524 + $result = $this->send_action( 'jetpack_full_sync_theme_data', array( true ) );
523 525
524 - // The number of actions enqueued, and next module state (true == done).
525 - 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;
526 533 }
527 534
528 535 /**
529 536 * Retrieve an estimated number of actions that will be enqueued.
@@ -530,9 +537,9 @@
530 537 *
531 538 * @access public
532 539 *
533 540 * @param array $config Full sync configuration for this sync module.
534 - * @return array Number of items yet to be enqueued.
541 + * @return int Number of items yet to be enqueued.
535 542 */
536 543 public function estimate_full_sync_actions( $config ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
537 544 return 1;
538 545 }
@@ -737,22 +744,20 @@
737 744 }
738 745
739 746 $moved_to_inactive_ids = array();
740 747 $moved_to_sidebar = array();
748 + $new_inactive_widgets = $new_value['wp_inactive_widgets'] ?? array();
741 749
742 750 foreach ( $new_value as $sidebar => $new_widgets ) {
743 751 if ( in_array( $sidebar, array( 'array_version', 'wp_inactive_widgets' ), true ) ) {
744 752 continue;
745 753 }
746 - $old_widgets = isset( $old_value[ $sidebar ] )
747 - ? $old_value[ $sidebar ]
748 - : array();
754 + $old_widgets = $old_value[ $sidebar ] ?? array();
749 755
750 756 if ( ! is_array( $new_widgets ) ) {
751 757 $new_widgets = array();
752 758 }
753 -
754 - $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 );
755 760 $moved_to_inactive_ids = array_merge( $moved_to_inactive_ids, $moved_to_inactive_recently );
756 761
757 762 $moved_to_sidebar_recently = $this->sync_add_widgets_to_sidebar( $new_widgets, $old_widgets, $sidebar );
758 763 $moved_to_sidebar = array_merge( $moved_to_sidebar, $moved_to_sidebar_recently );