Completed
Push — add/changelog-63 ( 4097a0...4b6617 )
by
unknown
37:46 queued 26:38
created

detect_theme_deletion()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 26
rs 9.504
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_themes', $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( 'wp_ajax_edit-theme-plugin-file', array( $this, 'theme_edit_ajax' ), 0 );
19
		add_action( 'update_site_option_allowedthemes', array( $this, 'sync_network_allowed_themes_change' ), 10, 4 );
20
		add_action( 'jetpack_network_disabled_themes', $callable, 10, 2 );
21
		add_action( 'jetpack_network_enabled_themes', $callable, 10, 2 );
22
23
		// Sidebar updates.
24
		add_action( 'update_option_sidebars_widgets', array( $this, 'sync_sidebar_widgets_actions' ), 10, 2 );
25
26
		add_action( 'jetpack_widget_added', $callable, 10, 4 );
27
		add_action( 'jetpack_widget_removed', $callable, 10, 4 );
28
		add_action( 'jetpack_widget_moved_to_inactive', $callable, 10, 2 );
29
		add_action( 'jetpack_cleared_inactive_widgets', $callable );
30
		add_action( 'jetpack_widget_reordered', $callable, 10, 2 );
31
		add_filter( 'widget_update_callback', array( $this, 'sync_widget_edit' ), 10, 4 );
32
		add_action( 'jetpack_widget_edited', $callable );
33
	}
34
35
	public function sync_widget_edit( $instance, $new_instance, $old_instance, $widget_object ) {
36
		if ( empty( $old_instance ) ) {
37
			return $instance;
38
		}
39
40
		$widget = array(
41
			'name' => $widget_object->name,
42
			'id' => $widget_object->id,
43
			'title' => isset( $new_instance['title'] ) ? $new_instance['title'] : '',
44
		);
45
		/**
46
		 * Trigger action to alert $callable sync listener that a widget was edited
47
		 *
48
		 * @since 5.0.0
49
		 *
50
		 * @param string $widget_name , Name of edited widget
51
		 */
52
		do_action( 'jetpack_widget_edited', $widget );
53
54
		return $instance;
55
	}
56
57
	public function sync_network_allowed_themes_change( $option, $value, $old_value, $network_id ) {
58
		$all_enabled_theme_slugs = array_keys( $value );
59
60
		if ( count( $old_value ) > count( $value ) )  {
61
62
			//Suppress jetpack_network_disabled_themes sync action when theme is deleted
63
			$delete_theme_call = $this->get_delete_theme_call();
64
			if ( ! empty( $delete_theme_call ) ) {
65
				return;
66
			}
67
68
			$newly_disabled_theme_names = array_keys( array_diff_key( $old_value, $value ) );
69
			$newly_disabled_themes = $this->get_theme_details_for_slugs( $newly_disabled_theme_names );
70
			/**
71
			 * Trigger action to alert $callable sync listener that network themes were disabled
72
			 *
73
			 * @since 5.0.0
74
			 *
75
			 * @param mixed $newly_disabled_themes, Array of info about network disabled themes
76
			 * @param mixed $all_enabled_theme_slugs, Array of slugs of all enabled themes
77
			 */
78
			do_action( 'jetpack_network_disabled_themes', $newly_disabled_themes, $all_enabled_theme_slugs );
79
			return;
80
		}
81
82
		$newly_enabled_theme_names = array_keys( array_diff_key( $value, $old_value ) );
83
		$newly_enabled_themes = $this->get_theme_details_for_slugs( $newly_enabled_theme_names );
84
		/**
85
		 * Trigger action to alert $callable sync listener that network themes were enabled
86
		 *
87
		 * @since 5.0.0
88
		 *
89
		 * @param mixed $newly_enabled_themes , Array of info about network enabled themes
90
		 * @param mixed $all_enabled_theme_slugs, Array of slugs of all enabled themes
91
		 */
92
		do_action( 'jetpack_network_enabled_themes', $newly_enabled_themes, $all_enabled_theme_slugs );
93
	}
94
95
	private function get_theme_details_for_slugs( $theme_slugs ) {
96
		$theme_data = array();
97 View Code Duplication
		foreach ( $theme_slugs as $slug ) {
98
			$theme = wp_get_theme( $slug );
99
			$theme_data[ $slug ] = array(
100
				'name' => $theme->get( 'Name' ),
101
				'version' => $theme->get( 'Version' ),
102
				'uri' => $theme->get( 'ThemeURI' ),
103
				'slug' => $slug,
104
			);
105
		}
106
		return $theme_data;
107
	}
108
109
	public function detect_theme_edit( $redirect_url ) {
110
		$url = wp_parse_url( admin_url( $redirect_url ) );
111
		$theme_editor_url = wp_parse_url( admin_url( 'theme-editor.php' ) );
112
113
		if ( $theme_editor_url['path'] !== $url['path'] ) {
114
			return $redirect_url;
115
		}
116
117
		$query_params = array();
118
		wp_parse_str( $url['query'], $query_params );
119
		if (
120
			! isset( $_POST['newcontent'] ) ||
121
			! isset( $query_params['file'] ) ||
122
			! isset( $query_params['theme'] ) ||
123
			! isset( $query_params['updated'] )
124
		) {
125
			return $redirect_url;
126
		}
127
		$theme = wp_get_theme( $query_params['theme'] );
128
		$theme_data = array(
129
			'name' => $theme->get('Name'),
130
			'version' => $theme->get('Version'),
131
			'uri' => $theme->get( 'ThemeURI' ),
132
		);
133
134
		/**
135
		 * Trigger action to alert $callable sync listener that a theme was edited
136
		 *
137
		 * @since 5.0.0
138
		 *
139
		 * @param string $query_params['theme'], Slug of edited theme
140
		 * @param string $theme_data, Information about edited them
141
		 */
142
		do_action( 'jetpack_edited_theme', $query_params['theme'], $theme_data );
143
144
		return $redirect_url;
145
	}
146
147
	public function theme_edit_ajax() {
148
		$args = wp_unslash( $_POST );
149
150
		if ( empty( $args['theme'] ) ) {
151
			return;
152
		}
153
154
		if ( empty( $args['file'] ) ) {
155
			return;
156
		}
157
		$file = $args['file'];
158
		if ( 0 !== validate_file( $file ) ) {
159
			return;
160
		}
161
162
		if ( ! isset( $args['newcontent'] ) ) {
163
			return;
164
		}
165
166
		if ( ! isset( $args['nonce'] ) ) {
167
			return;
168
		}
169
170
		$stylesheet = $args['theme'];
171
		if ( 0 !== validate_file( $stylesheet ) ) {
172
			return;
173
		}
174
175
		if ( ! current_user_can( 'edit_themes' ) ) {
176
			return;
177
		}
178
179
		$theme = wp_get_theme( $stylesheet );
180
		if ( ! $theme->exists() ) {
181
			return;
182
		}
183
184
		$real_file = $theme->get_stylesheet_directory() . '/' . $file;
185
		if ( ! wp_verify_nonce( $args['nonce'], 'edit-theme_' . $real_file . $stylesheet ) ) {
186
			return;
187
		}
188
189
		if ( $theme->errors() && 'theme_no_stylesheet' === $theme->errors()->get_error_code() ) {
190
			return;
191
		}
192
193
		$editable_extensions = wp_get_theme_file_editable_extensions( $theme );
194
195
		$allowed_files = array();
196
		foreach ( $editable_extensions as $type ) {
197
			switch ( $type ) {
198
				case 'php':
199
					$allowed_files = array_merge( $allowed_files, $theme->get_files( 'php', -1 ) );
200
					break;
201
				case 'css':
202
					$style_files = $theme->get_files( 'css', -1 );
203
					$allowed_files['style.css'] = $style_files['style.css'];
204
					$allowed_files = array_merge( $allowed_files, $style_files );
205
					break;
206
				default:
207
					$allowed_files = array_merge( $allowed_files, $theme->get_files( $type, -1 ) );
208
					break;
209
			}
210
		}
211
212
		if ( 0 !== validate_file( $real_file, $allowed_files ) ) {
213
			return;
214
		}
215
216
		// Ensure file is real.
217
		if ( ! is_file( $real_file ) ) {
218
			return;
219
		}
220
221
		// Ensure file extension is allowed.
222
		$extension = null;
0 ignored issues
show
Unused Code introduced by
$extension is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
223
		if ( preg_match( '/\.([^.]+)$/', $real_file, $matches ) ) {
224
			$extension = strtolower( $matches[1] );
225
			if ( ! in_array( $extension, $editable_extensions, true ) ) {
226
				return;
227
			}
228
		}
229
230
		if ( ! is_writeable( $real_file ) ) {
231
			return;
232
		}
233
234
		$file_pointer = fopen( $real_file, 'w+' );
235
		if ( false === $file_pointer ) {
236
			return;
237
		}
238
		fclose( $file_pointer );
239
240
		$theme_data = array(
241
			'name' => $theme->get('Name'),
242
			'version' => $theme->get('Version'),
243
			'uri' => $theme->get( 'ThemeURI' ),
244
		);
245
246
		/**
247
		 * This action is documented already in this file
248
		 */
249
		do_action( 'jetpack_edited_theme', $stylesheet, $theme_data );
250
251
	}
252
253
	public function detect_theme_deletion() {
254
		$delete_theme_call = $this->get_delete_theme_call();
255
		if ( empty( $delete_theme_call ) ) {
256
			return;
257
		}
258
259
		$slug = $delete_theme_call['args'][0];
260
		$theme = wp_get_theme( $slug );
261
		$theme_data = array(
262
			'name' => $theme->get('Name'),
263
			'version' => $theme->get('Version'),
264
			'uri' => $theme->get( 'ThemeURI' ),
265
			'slug' => $slug,
266
		);
267
268
		/**
269
		 * Signals to the sync listener that a theme was deleted and a sync action
270
		 * reflecting the deletion and theme slug should be sent
271
		 *
272
		 * @since 5.0.0
273
		 *
274
		 * @param string $slug Theme slug
275
		 * @param array $theme_data Theme info Since 5.3
276
		 */
277
		do_action( 'jetpack_deleted_theme', $slug, $theme_data );
278
	}
279
280
	public function check_upgrader( $upgrader, $details ) {
281
		if ( ! isset( $details['type'] ) ||
282
		     'theme' !== $details['type'] ||
283
		     is_wp_error( $upgrader->skin->result ) ||
284
		     ! method_exists( $upgrader, 'theme_info' )
285
		) {
286
			return;
287
		}
288
289
		if ( 'install' === $details['action'] ) {
290
			$theme = $upgrader->theme_info();
291
			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...
292
				return;
293
			}
294
			$theme_info = array(
295
				'name' => $theme->get( 'Name' ),
296
				'version' => $theme->get( 'Version' ),
297
				'uri' => $theme->get( 'ThemeURI' ),
298
			);
299
300
			/**
301
			 * Signals to the sync listener that a theme was installed and a sync action
302
			 * reflecting the installation and the theme info should be sent
303
			 *
304
			 * @since 4.9.0
305
			 *
306
			 * @param string $theme->theme_root Text domain of the theme
307
			 * @param mixed $theme_info Array of abbreviated theme info
308
			 */
309
			do_action( 'jetpack_installed_theme', $theme->stylesheet, $theme_info );
310
		}
311
312
		if ( 'update' === $details['action'] ) {
313
			$themes = array();
314
315
			if ( empty( $details['themes'] ) && isset ( $details['theme'] ) ) {
316
				$details['themes'] = array( $details['theme'] );
317
			}
318
319 View Code Duplication
			foreach ( $details['themes'] as $theme_slug ) {
320
				$theme = wp_get_theme( $theme_slug );
321
322
				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...
323
					continue;
324
				}
325
326
				$themes[ $theme_slug ] = array(
327
					'name' => $theme->get( 'Name' ),
328
					'version' => $theme->get( 'Version' ),
329
					'uri' => $theme->get( 'ThemeURI' ),
330
					'stylesheet' => $theme->stylesheet,
331
				);
332
			}
333
334
			if ( empty( $themes ) ) {
335
				return;
336
			}
337
338
			/**
339
			 * Signals to the sync listener that one or more themes was updated and a sync action
340
			 * reflecting the update and the theme info should be sent
341
			 *
342
			 * @since 6.2.0
343
			 *
344
			 * @param mixed $themes Array of abbreviated theme info
345
			 */
346
			do_action( 'jetpack_updated_themes', $themes );
347
		}
348
349
	}
350
351
	public function init_full_sync_listeners( $callable ) {
352
		add_action( 'jetpack_full_sync_theme_data', $callable );
353
	}
354
355
	public function sync_theme_support() {
356
		/**
357
		 * Fires when the client needs to sync theme support info
358
		 * Only sends theme support attributes whitelisted in Jetpack_Sync_Defaults::$default_theme_support_whitelist
359
		 *
360
		 * @since 4.2.0
361
		 *
362
		 * @param object the theme support hash
363
		 */
364
		do_action( 'jetpack_sync_current_theme_support' , $this->get_theme_support_info() );
365
	}
366
367
	public function enqueue_full_sync_actions( $config, $max_items_to_enqueue, $state ) {
368
		/**
369
		 * Tells the client to sync all theme data to the server
370
		 *
371
		 * @since 4.2.0
372
		 *
373
		 * @param boolean Whether to expand theme data (should always be true)
374
		 */
375
		do_action( 'jetpack_full_sync_theme_data', true );
376
377
		// The number of actions enqueued, and next module state (true == done)
378
		return array( 1, true );
379
	}
380
381
	public function estimate_full_sync_actions( $config ) {
382
		return 1;
383
	}
384
385
	public function init_before_send() {
386
		add_filter( 'jetpack_sync_before_send_jetpack_full_sync_theme_data', array( $this, 'expand_theme_data' ) );
387
	}
388
389
	function get_full_sync_actions() {
390
		return array( 'jetpack_full_sync_theme_data' );
391
	}
392
393
	function expand_theme_data() {
394
		return array( $this->get_theme_support_info() );
395
	}
396
397
	function get_widget_name( $widget_id ) {
398
		global $wp_registered_widgets;
399
		return ( isset( $wp_registered_widgets[ $widget_id ] ) ? $wp_registered_widgets[ $widget_id ]['name'] : null );
400
	}
401
402
	function get_sidebar_name( $sidebar_id ) {
403
		global $wp_registered_sidebars;
404
		return ( isset( $wp_registered_sidebars[ $sidebar_id ] ) ? $wp_registered_sidebars[ $sidebar_id ]['name'] : null );
405
	}
406
407
	function sync_add_widgets_to_sidebar( $new_widgets, $old_widgets, $sidebar ) {
408
		$added_widgets = array_diff( $new_widgets, $old_widgets );
409
		if ( empty( $added_widgets ) ) {
410
			return array();
411
		}
412
		$moved_to_sidebar = array();
413
		$sidebar_name = $this->get_sidebar_name( $sidebar );
414
415
		//Don't sync jetpack_widget_added if theme was switched
416
		if ( $this->is_theme_switch() ) {
417
			return array();
418
		}
419
420
		foreach ( $added_widgets as $added_widget ) {
421
			$moved_to_sidebar[] = $added_widget;
422
			$added_widget_name = $this->get_widget_name( $added_widget );
423
			/**
424
			 * Helps Sync log that a widget got added
425
			 *
426
			 * @since 4.9.0
427
			 *
428
			 * @param string $sidebar, Sidebar id got changed
429
			 * @param string $added_widget, Widget id got added
430
			 * @param string $sidebar_name, Sidebar id got changed Since 5.0.0
431
			 * @param string $added_widget_name, Widget id got added Since 5.0.0
432
			 *
433
			 */
434
			do_action( 'jetpack_widget_added', $sidebar, $added_widget,  $sidebar_name, $added_widget_name );
435
		}
436
		return $moved_to_sidebar;
437
	}
438
439
	function sync_remove_widgets_from_sidebar( $new_widgets, $old_widgets, $sidebar, $inactive_widgets  ) {
440
		$removed_widgets = array_diff( $old_widgets, $new_widgets );
441
442
		if ( empty( $removed_widgets ) ) {
443
			return array();
444
		}
445
446
		$moved_to_inactive = array();
447
		$sidebar_name = $this->get_sidebar_name( $sidebar );
448
449
		foreach( $removed_widgets as $removed_widget ) {
450
			// Lets check if we didn't move the widget to in_active_widgets
451
			if ( isset( $inactive_widgets ) && ! in_array( $removed_widget, $inactive_widgets ) ) {
452
				$removed_widget_name = $this->get_widget_name( $removed_widget );
453
				/**
454
				 * Helps Sync log that a widgte got removed
455
				 *
456
				 * @since 4.9.0
457
				 *
458
				 * @param string $sidebar, Sidebar id got changed
459
				 * @param string $removed_widget, Widget id got removed
460
				 * @param string $sidebar_name, Name of the sidebar that changed  Since 5.0.0
461
				 * @param string $removed_widget_name, Name of the widget that got removed Since 5.0.0
462
				 */
463
				do_action( 'jetpack_widget_removed', $sidebar, $removed_widget, $sidebar_name, $removed_widget_name );
464
			} else {
465
				$moved_to_inactive[] = $removed_widget;
466
			}
467
		}
468
		return $moved_to_inactive;
469
470
	}
471
472
	function sync_widgets_reordered( $new_widgets, $old_widgets, $sidebar ) {
473
		$added_widgets = array_diff( $new_widgets, $old_widgets );
474
		if ( ! empty( $added_widgets ) ) {
475
			return;
476
		}
477
		$removed_widgets = array_diff( $old_widgets, $new_widgets );
478
		if ( ! empty( $removed_widgets ) ) {
479
			return;
480
		}
481
482
		if ( serialize( $old_widgets ) !== serialize( $new_widgets ) ) {
483
			$sidebar_name = $this->get_sidebar_name( $sidebar );
484
			/**
485
			 * Helps Sync log that a sidebar id got reordered
486
			 *
487
			 * @since 4.9.0
488
			 *
489
			 * @param string $sidebar, Sidebar id got changed
490
			 * @param string $sidebar_name, Name of the sidebar that changed  Since 5.0.0
491
			 */
492
			do_action( 'jetpack_widget_reordered', $sidebar, $sidebar_name );
493
		}
494
495
	}
496
497
	function sync_sidebar_widgets_actions( $old_value, $new_value ) {
498
		// Don't really know how to deal with different array_values yet.
499
		if (
500
			( isset( $old_value['array_version'] ) && $old_value['array_version'] !== 3 ) ||
501
			( isset( $new_value['array_version'] ) && $new_value['array_version'] !== 3 )
502
		) {
503
			return;
504
		}
505
506
		$moved_to_inactive_ids = array();
507
		$moved_to_sidebar = array();
508
509
		foreach ( $new_value as $sidebar => $new_widgets ) {
510
			if ( in_array( $sidebar, array( 'array_version', 'wp_inactive_widgets' ) ) ) {
511
				continue;
512
			}
513
			$old_widgets = isset( $old_value[ $sidebar ] )
514
				? $old_value[ $sidebar ]
515
				: array();
516
517
			if ( ! is_array( $new_widgets ) ) {
518
				$new_widgets = array();
519
			}
520
521
			$moved_to_inactive_recently = $this->sync_remove_widgets_from_sidebar( $new_widgets, $old_widgets, $sidebar, $new_value['wp_inactive_widgets'] );
522
			$moved_to_inactive_ids = array_merge( $moved_to_inactive_ids, $moved_to_inactive_recently );
523
524
			$moved_to_sidebar_recently = $this->sync_add_widgets_to_sidebar( $new_widgets, $old_widgets, $sidebar );
525
			$moved_to_sidebar = array_merge( $moved_to_sidebar, $moved_to_sidebar_recently );
526
527
			$this->sync_widgets_reordered( $new_widgets, $old_widgets, $sidebar );
528
529
		}
530
531
		//Don't sync either jetpack_widget_moved_to_inactive or jetpack_cleared_inactive_widgets if theme was switched
532
		if ( $this->is_theme_switch() ) {
533
			return;
534
		}
535
536
		// Treat inactive sidebar a bit differently
537
		if ( ! empty( $moved_to_inactive_ids ) ) {
538
			$moved_to_inactive_name = array_map( array( $this, 'get_widget_name' ), $moved_to_inactive_ids );
539
			/**
540
			 * Helps Sync log that a widgets IDs got moved to in active
541
			 *
542
			 * @since 4.9.0
543
			 *
544
			 * @param array $moved_to_inactive_ids, Array of widgets id that moved to inactive id got changed
545
			 * @param array $moved_to_inactive_names, Array of widgets names that moved to inactive id got changed Since 5.0.0
546
			 */
547
			do_action( 'jetpack_widget_moved_to_inactive', $moved_to_inactive_ids, $moved_to_inactive_name );
548
		} elseif ( empty( $moved_to_sidebar ) &&
549
		           empty( $new_value['wp_inactive_widgets']) &&
550
		           ! empty( $old_value['wp_inactive_widgets'] ) ) {
551
			/**
552
			 * Helps Sync log that a got cleared from inactive.
553
			 *
554
			 * @since 4.9.0
555
			 */
556
			do_action( 'jetpack_cleared_inactive_widgets' );
557
		}
558
	}
559
560
	private function get_theme_support_info() {
561
		global $_wp_theme_features;
562
563
		$theme_support = array();
564
565
		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...
566
			$has_support = current_theme_supports( $theme_feature );
567
			if ( $has_support ) {
568
				$theme_support[ $theme_feature ] = $_wp_theme_features[ $theme_feature ];
569
			}
570
		}
571
572
		$theme = wp_get_theme();
573
		$theme_support['name'] = $theme->get('Name');
574
		$theme_support['version'] =  $theme->get('Version');
575
		$theme_support['slug'] = $theme->get_stylesheet();
576
		$theme_support['uri'] = $theme->get('ThemeURI');
577
578
579
		return $theme_support;
580
	}
581
582
	private function get_delete_theme_call() {
583
		$backtrace = debug_backtrace();
584
		$delete_theme_call = null;
585
		foreach ( $backtrace as $call ) {
586
			if ( isset( $call['function'] ) && 'delete_theme' === $call['function'] ) {
587
				$delete_theme_call = $call;
588
				break;
589
			}
590
		}
591
		return $delete_theme_call;
592
	}
593
594
	private function is_theme_switch() {
595
		return did_action( 'after_switch_theme' );
596
	}
597
}
598