Completed
Push — update/sync-users-enqueue-orde... ( 33db83...19456a )
by
unknown
12:33 queued 03:27
created

Jetpack_Sync_Module_Themes::get_widget_name()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
class Jetpack_Sync_Module_Themes extends Jetpack_Sync_Module {
4
	function name() {
5
		return 'themes';
6
	}
7
8
	public function init_listeners( $callable ) {
9
		add_action( 'switch_theme', array( $this, 'sync_theme_support' ) );
10
		add_action( 'jetpack_sync_current_theme_support', $callable );
11
		add_action( 'upgrader_process_complete', array( $this, 'check_upgrader'), 10, 2 );
12
		add_action( 'jetpack_installed_theme', $callable, 10, 2 );
13
		add_action( 'jetpack_updated_theme', $callable, 10, 2 );
14
		add_action( 'delete_site_transient_update_themes', array( $this, 'detect_theme_deletion') );
15
		add_action( 'jetpack_deleted_theme', $callable, 10, 2 );
16
		add_filter( 'wp_redirect', array( $this, 'detect_theme_edit' ) );
17
		add_action( 'jetpack_edited_theme', $callable, 10, 2 );
18
		add_action( 'update_site_option_allowedthemes', array( $this, 'sync_network_allowed_themes_change' ), 10, 4 );
19
		add_action( 'jetpack_network_disabled_themes', $callable, 10, 2 );
20
		add_action( 'jetpack_network_enabled_themes', $callable, 10, 2 );
21
22
		// Sidebar updates.
23
		add_action( 'update_option_sidebars_widgets', array( $this, 'sync_sidebar_widgets_actions' ), 10, 2 );
24
25
		add_action( 'jetpack_widget_added', $callable, 10, 4 );
26
		add_action( 'jetpack_widget_removed', $callable, 10, 4 );
27
		add_action( 'jetpack_widget_moved_to_inactive', $callable, 10, 2 );
28
		add_action( 'jetpack_cleared_inactive_widgets', $callable );
29
		add_action( 'jetpack_widget_reordered', $callable, 10, 2 );
30
		add_filter( 'widget_update_callback', array( $this, 'sync_widget_edit' ), 10, 4 );
31
		add_action( 'jetpack_widget_edited', $callable );
32
	}
33
34
	public function sync_widget_edit( $instance, $new_instance, $old_instance, $widget_object ) {
35
		if ( empty( $old_instance ) ) {
36
			return $instance;
37
		}
38
39
		$widget = array(
40
			'name' => $widget_object->name,
41
			'id' => $widget_object->id,
42
		);
43
		/**
44
		 * Trigger action to alert $callable sync listener that a widget was edited
45
		 *
46
		 * @since 5.0.0
47
		 *
48
		 * @param string $widget_name , Name of edited widget
49
		 */
50
		do_action( 'jetpack_widget_edited', $widget );
51
52
		return $instance;
53
	}
54
55
	public function sync_network_allowed_themes_change( $option, $value, $old_value, $network_id ) {
56
		$all_enabled_theme_slugs = array_keys( $value );
57
58
		if ( count( $old_value ) > count( $value ) )  {
59
60
			//Suppress jetpack_network_disabled_themes sync action when theme is deleted
61
			$delete_theme_call = $this->get_delete_theme_call();
62
			if ( ! empty( $delete_theme_call ) ) {
63
				return;
64
			}
65
66
			$newly_disabled_theme_names = array_keys( array_diff_key( $old_value, $value ) );
67
			$newly_disabled_themes = $this->get_theme_details_for_slugs( $newly_disabled_theme_names );
68
			/**
69
			 * Trigger action to alert $callable sync listener that network themes were disabled
70
			 *
71
			 * @since 5.0.0
72
			 *
73
			 * @param mixed $newly_disabled_themes, Array of info about network disabled themes
74
			 * @param mixed $all_enabled_theme_slugs, Array of slugs of all enabled themes
75
			 */
76
			do_action( 'jetpack_network_disabled_themes', $newly_disabled_themes, $all_enabled_theme_slugs );
77
			return;
78
		}
79
80
		$newly_enabled_theme_names = array_keys( array_diff_key( $value, $old_value ) );
81
		$newly_enabled_themes = $this->get_theme_details_for_slugs( $newly_enabled_theme_names );
82
		/**
83
		 * Trigger action to alert $callable sync listener that network themes were enabled
84
		 *
85
		 * @since 5.0.0
86
		 *
87
		 * @param mixed $newly_enabled_themes , Array of info about network enabled themes
88
		 * @param mixed $all_enabled_theme_slugs, Array of slugs of all enabled themes
89
		 */
90
		do_action( 'jetpack_network_enabled_themes', $newly_enabled_themes, $all_enabled_theme_slugs );
91
	}
92
93
	private function get_theme_details_for_slugs( $theme_slugs ) {
94
		$theme_data = array();
95
		foreach ( $theme_slugs as $slug ) {
96
			$theme = wp_get_theme( $slug );
97
			$theme_data[ $slug ] = array(
98
				'name' => $theme->get( 'Name' ),
99
				'version' => $theme->get( 'Version' ),
100
				'uri' => $theme->get( 'ThemeURI' ),
101
				'slug' => $slug,
102
			);
103
		}
104
		return $theme_data;
105
	}
106
107
	public function detect_theme_edit( $redirect_url ) {
108
		$url = wp_parse_url( admin_url( $redirect_url ) );
109
		$theme_editor_url = wp_parse_url( admin_url( 'theme-editor.php' ) );
110
111
		if ( $theme_editor_url['path'] !== $url['path'] ) {
112
			return $redirect_url;
113
		}
114
115
		$query_params = array();
116
		wp_parse_str( $url['query'], $query_params );
117
		if (
118
			! isset( $_POST['newcontent'] ) ||
119
			! isset( $query_params['file'] ) ||
120
			! isset( $query_params['theme'] ) ||
121
			! isset( $query_params['updated'] )
122
		) {
123
			return $redirect_url;
124
		}
125
		$theme = wp_get_theme( $query_params['theme'] );
126
		$theme_data = array(
127
			'name' => $theme->get('Name'),
128
			'version' => $theme->get('Version'),
129
			'uri' => $theme->get( 'ThemeURI' ),
130
		);
131
132
		/**
133
		 * Trigger action to alert $callable sync listener that a theme was edited
134
		 *
135
		 * @since 5.0.0
136
		 *
137
		 * @param string $query_params['theme'], Slug of edited theme
138
		 * @param string $theme_data, Information about edited them
139
		 */
140
		do_action( 'jetpack_edited_theme', $query_params['theme'], $theme_data );
141
142
		return $redirect_url;
143
	}
144
145
	public function detect_theme_deletion() {
146
		$delete_theme_call = $this->get_delete_theme_call();
147
		if ( empty( $delete_theme_call ) ) {
148
			return;
149
		}
150
151
		$slug = $delete_theme_call['args'][0];
152
		$theme = wp_get_theme( $slug );
153
		$theme_data = array(
154
			'name' => $theme->get('Name'),
155
			'version' => $theme->get('Version'),
156
			'uri' => $theme->get( 'ThemeURI' ),
157
			'slug' => $slug,
158
		);
159
160
		/**
161
		 * Signals to the sync listener that a theme was deleted and a sync action
162
		 * reflecting the deletion and theme slug should be sent
163
		 *
164
		 * @since 5.0.0
165
		 *
166
		 * @param string $slug Theme slug
167
		 * @param array $theme_data Theme info Since 5.3
168
		 */
169
		do_action( 'jetpack_deleted_theme', $slug, $theme_data );
170
	}
171
172
	public function check_upgrader( $upgrader, $details) {
173 View Code Duplication
		if ( ! isset( $details['type'] ) ||
174
		     'theme' !== $details['type'] ||
175
		     is_wp_error( $upgrader->skin->result ) ||
176
		     ! method_exists( $upgrader, 'theme_info' )
177
		) {
178
			return;
179
		}
180
181
		$theme = $upgrader->theme_info();
182
		if ( ! $theme instanceof WP_Theme ) {
0 ignored issues
show
Bug introduced by
The class WP_Theme does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
183
			return;
184
		}
185
		$theme_info = array(
186
			'name' => $theme->get( 'Name' ),
187
			'version' => $theme->get( 'Version' ),
188
			'uri' => $theme->get( 'ThemeURI' ),
189
		);
190
191
		if ( 'install' === $details['action'] ) {
192
			/**
193
			 * Signals to the sync listener that a theme was installed and a sync action
194
			 * reflecting the installation and the theme info should be sent
195
			 *
196
			 * @since 4.9.0
197
			 *
198
			 * @param string $theme->theme_root Text domain of the theme
199
			 * @param mixed $theme_info Array of abbreviated theme info
200
			 */
201
			do_action( 'jetpack_installed_theme', $theme->stylesheet, $theme_info );
202
		}
203
204
		if ( 'update' === $details['action'] ) {
205
			/**
206
			 * Signals to the sync listener that a theme was updated and a sync action
207
			 * reflecting the update and the theme info should be sent
208
			 *
209
			 * @since 4.9.0
210
			 *
211
			 * @param string $theme->theme_root Text domain of the theme
212
			 * @param mixed $theme_info Array of abbreviated theme info
213
			 */
214
			do_action( 'jetpack_updated_theme', $theme->stylesheet, $theme_info );
215
		}
216
	}
217
218
	public function init_full_sync_listeners( $callable ) {
219
		add_action( 'jetpack_full_sync_theme_data', $callable );
220
	}
221
222
	public function sync_theme_support() {
223
		/**
224
		 * Fires when the client needs to sync theme support info
225
		 * Only sends theme support attributes whitelisted in Jetpack_Sync_Defaults::$default_theme_support_whitelist
226
		 *
227
		 * @since 4.2.0
228
		 *
229
		 * @param object the theme support hash
230
		 */
231
		do_action( 'jetpack_sync_current_theme_support' , $this->get_theme_support_info() );
232
	}
233
234
	public function enqueue_full_sync_actions( $config, $max_items_to_enqueue, $state ) {
235
		/**
236
		 * Tells the client to sync all theme data to the server
237
		 *
238
		 * @since 4.2.0
239
		 *
240
		 * @param boolean Whether to expand theme data (should always be true)
241
		 */
242
		do_action( 'jetpack_full_sync_theme_data', true );
243
244
		// The number of actions enqueued, and next module state (true == done)
245
		return array( 1, true );
246
	}
247
248
	public function estimate_full_sync_actions( $config ) {
249
		return 1;
250
	}
251
252
	public function init_before_send() {
253
		add_filter( 'jetpack_sync_before_send_jetpack_full_sync_theme_data', array( $this, 'expand_theme_data' ) );
254
	}
255
256
	function get_full_sync_actions() {
257
		return array( 'jetpack_full_sync_theme_data' );
258
	}
259
260
	function expand_theme_data() {
261
		return array( $this->get_theme_support_info() );
262
	}
263
264
	function get_widget_name( $widget_id ) {
265
		global $wp_registered_widgets;
266
		return ( isset( $wp_registered_widgets[ $widget_id ] ) ? $wp_registered_widgets[ $widget_id ]['name'] : null );
267
	}
268
269
	function get_sidebar_name( $sidebar_id ) {
270
		global $wp_registered_sidebars;
271
		return ( isset( $wp_registered_sidebars[ $sidebar_id ] ) ? $wp_registered_sidebars[ $sidebar_id ]['name'] : null );
272
	}
273
274
	function sync_add_widgets_to_sidebar( $new_widgets, $old_widgets, $sidebar ) {
275
		$added_widgets = array_diff( $new_widgets, $old_widgets );
276
		if ( empty( $added_widgets ) ) {
277
			return array();
278
		}
279
		$moved_to_sidebar = array();
280
		$sidebar_name = $this->get_sidebar_name( $sidebar );
281
282
		//Don't sync jetpack_widget_added if theme was switched
283
		if ( $this->is_theme_switch() ) {
284
			return array();
285
		}
286
287
		foreach ( $added_widgets as $added_widget ) {
288
			$moved_to_sidebar[] = $added_widget;
289
			$added_widget_name = $this->get_widget_name( $added_widget );
290
			/**
291
			 * Helps Sync log that a widget got added
292
			 *
293
			 * @since 4.9.0
294
			 *
295
			 * @param string $sidebar, Sidebar id got changed
296
			 * @param string $added_widget, Widget id got added
297
			 * @param string $sidebar_name, Sidebar id got changed Since 5.0.0
298
			 * @param string $added_widget_name, Widget id got added Since 5.0.0
299
			 *
300
			 */
301
			do_action( 'jetpack_widget_added', $sidebar, $added_widget,  $sidebar_name, $added_widget_name );
302
		}
303
		return $moved_to_sidebar;
304
	}
305
306
	function sync_remove_widgets_from_sidebar( $new_widgets, $old_widgets, $sidebar, $inactive_widgets  ) {
307
		$removed_widgets = array_diff( $old_widgets, $new_widgets );
308
309
		if ( empty( $removed_widgets ) ) {
310
			return array();
311
		}
312
313
		$moved_to_inactive = array();
314
		$sidebar_name = $this->get_sidebar_name( $sidebar );
315
316
		foreach( $removed_widgets as $removed_widget ) {
317
			// Lets check if we didn't move the widget to in_active_widgets
318
			if ( isset( $inactive_widgets ) && ! in_array( $removed_widget, $inactive_widgets ) ) {
319
				$removed_widget_name = $this->get_widget_name( $removed_widget );
320
				/**
321
				 * Helps Sync log that a widgte got removed
322
				 *
323
				 * @since 4.9.0
324
				 *
325
				 * @param string $sidebar, Sidebar id got changed
326
				 * @param string $removed_widget, Widget id got removed
327
				 * @param string $sidebar_name, Name of the sidebar that changed  Since 5.0.0
328
				 * @param string $removed_widget_name, Name of the widget that got removed Since 5.0.0
329
				 */
330
				do_action( 'jetpack_widget_removed', $sidebar, $removed_widget, $sidebar_name, $removed_widget_name );
331
			} else {
332
				$moved_to_inactive[] = $removed_widget;
333
			}
334
		}
335
		return $moved_to_inactive;
336
337
	}
338
339
	function sync_widgets_reordered( $new_widgets, $old_widgets, $sidebar ) {
340
		$added_widgets = array_diff( $new_widgets, $old_widgets );
341
		if ( ! empty( $added_widgets ) ) {
342
			return;
343
		}
344
		$removed_widgets = array_diff( $old_widgets, $new_widgets );
345
		if ( ! empty( $removed_widgets ) ) {
346
			return;
347
		}
348
349
		if ( serialize( $old_widgets ) !== serialize( $new_widgets ) ) {
350
			$sidebar_name = $this->get_sidebar_name( $sidebar );
351
			/**
352
			 * Helps Sync log that a sidebar id got reordered
353
			 *
354
			 * @since 4.9.0
355
			 *
356
			 * @param string $sidebar, Sidebar id got changed
357
			 * @param string $sidebar_name, Name of the sidebar that changed  Since 5.0.0
358
			 */
359
			do_action( 'jetpack_widget_reordered', $sidebar, $sidebar_name );
360
		}
361
362
	}
363
364
	function sync_sidebar_widgets_actions( $old_value, $new_value ) {
365
		// Don't really know how to deal with different array_values yet.
366
		if (
367
			( isset( $old_value['array_version'] ) && $old_value['array_version'] !== 3 ) ||
368
			( isset( $new_value['array_version'] ) && $new_value['array_version'] !== 3 )
369
		) {
370
			return;
371
		}
372
373
		$moved_to_inactive_ids = array();
374
		$moved_to_sidebar = array();
375
376
		foreach ( $new_value as $sidebar => $new_widgets ) {
377
			if ( in_array( $sidebar, array( 'array_version', 'wp_inactive_widgets' ) ) ) {
378
				continue;
379
			}
380
			$old_widgets = isset( $old_value[ $sidebar ] )
381
				? $old_value[ $sidebar ]
382
				: array();
383
384
			if ( ! is_array( $new_widgets ) ) {
385
				$new_widgets = array();
386
			}
387
388
			$moved_to_inactive_recently = $this->sync_remove_widgets_from_sidebar( $new_widgets, $old_widgets, $sidebar, $new_value['wp_inactive_widgets'] );
389
			$moved_to_inactive_ids = array_merge( $moved_to_inactive_ids, $moved_to_inactive_recently );
390
391
			$moved_to_sidebar_recently = $this->sync_add_widgets_to_sidebar( $new_widgets, $old_widgets, $sidebar );
392
			$moved_to_sidebar = array_merge( $moved_to_sidebar, $moved_to_sidebar_recently );
393
394
			$this->sync_widgets_reordered( $new_widgets, $old_widgets, $sidebar );
395
396
		}
397
398
		//Don't sync either jetpack_widget_moved_to_inactive or jetpack_cleared_inactive_widgets if theme was switched
399
		if ( $this->is_theme_switch() ) {
400
			return;
401
		}
402
403
		// Treat inactive sidebar a bit differently
404
		if ( ! empty( $moved_to_inactive_ids ) ) {
405
			$moved_to_inactive_name = array_map( array( $this, 'get_widget_name' ), $moved_to_inactive_ids );
406
			/**
407
			 * Helps Sync log that a widgets IDs got moved to in active
408
			 *
409
			 * @since 4.9.0
410
			 *
411
			 * @param array $moved_to_inactive_ids, Array of widgets id that moved to inactive id got changed
412
			 * @param array $moved_to_inactive_names, Array of widgets names that moved to inactive id got changed Since 5.0.0
413
			 */
414
			do_action( 'jetpack_widget_moved_to_inactive', $moved_to_inactive_ids, $moved_to_inactive_name );
415
		} elseif ( empty( $moved_to_sidebar ) &&
416
		           empty( $new_value['wp_inactive_widgets']) &&
417
		           ! empty( $old_value['wp_inactive_widgets'] ) ) {
418
			/**
419
			 * Helps Sync log that a got cleared from inactive.
420
			 *
421
			 * @since 4.9.0
422
			 */
423
			do_action( 'jetpack_cleared_inactive_widgets' );
424
		}
425
	}
426
427
	private function get_theme_support_info() {
428
		global $_wp_theme_features;
429
430
		$theme_support = array();
431
432
		foreach ( Jetpack_Sync_Defaults::$default_theme_support_whitelist as $theme_feature ) {
0 ignored issues
show
Bug introduced by
The property default_theme_support_whitelist cannot be accessed from this context as it is declared private in class Jetpack_Sync_Defaults.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
433
			$has_support = current_theme_supports( $theme_feature );
434
			if ( $has_support ) {
435
				$theme_support[ $theme_feature ] = $_wp_theme_features[ $theme_feature ];
436
			}
437
		}
438
439
		$theme = wp_get_theme();
440
		$theme_support['name'] = $theme->get('Name');
441
		$theme_support['version'] =  $theme->get('Version');
442
		$theme_support['slug'] = $theme->get_stylesheet();
443
		$theme_support['uri'] = $theme->get('ThemeURI');
444
445
446
		return $theme_support;
447
	}
448
449
	private function get_delete_theme_call() {
450
		$backtrace = debug_backtrace();
451
		$delete_theme_call = null;
452
		foreach ( $backtrace as $call ) {
453
			if ( isset( $call['function'] ) && 'delete_theme' === $call['function'] ) {
454
				$delete_theme_call = $call;
455
				break;
456
			}
457
		}
458
		return $delete_theme_call;
459
	}
460
461
	private function is_theme_switch() {
462
		return did_action( 'after_switch_theme' );
463
	}
464
}