Passed
Push — main ( 44ea53...137754 )
by TARIQ
15:15 queued 02:39
created

UpgraderStatus::getThingBeingUpgradedBy()   C

Complexity

Conditions 16
Paths 22

Size

Total Lines 33
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 16
eloc 20
c 1
b 0
f 0
nc 22
nop 1
dl 0
loc 33
rs 5.5666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace YahnisElsts\PluginUpdateChecker\v5p0;
3
4
if ( !class_exists(UpgraderStatus::class, false) ):
5
6
	/**
7
	 * A utility class that helps figure out which plugin or theme WordPress is upgrading.
8
	 *
9
	 * It may seem strange to have a separate class just for that, but the task is surprisingly complicated.
10
	 * Core classes like Plugin_Upgrader don't expose the plugin file name during an in-progress update (AFAICT).
11
	 * This class uses a few workarounds and heuristics to get the file name.
12
	 */
13
	class UpgraderStatus {
14
		private $currentType = null; //"plugin" or "theme".
15
		private $currentId = null;   //Plugin basename or theme directory name.
16
17
		public function __construct() {
18
			//Keep track of which plugin/theme WordPress is currently upgrading.
19
			add_filter('upgrader_pre_install', array($this, 'setUpgradedThing'), 10, 2);
20
			add_filter('upgrader_package_options', array($this, 'setUpgradedPluginFromOptions'), 10, 1);
21
			add_filter('upgrader_post_install', array($this, 'clearUpgradedThing'), 10, 1);
22
			add_action('upgrader_process_complete', array($this, 'clearUpgradedThing'), 10, 1);
23
		}
24
25
		/**
26
		 * Is there and update being installed RIGHT NOW, for a specific plugin?
27
		 *
28
		 * Caution: This method is unreliable. WordPress doesn't make it easy to figure out what it is upgrading,
29
		 * and upgrader implementations are liable to change without notice.
30
		 *
31
		 * @param string $pluginFile The plugin to check.
32
		 * @param \WP_Upgrader|null $upgrader The upgrader that's performing the current update.
33
		 * @return bool True if the plugin identified by $pluginFile is being upgraded.
34
		 */
35
		public function isPluginBeingUpgraded($pluginFile, $upgrader = null) {
36
			return $this->isBeingUpgraded('plugin', $pluginFile, $upgrader);
37
		}
38
39
		/**
40
		 * Is there an update being installed for a specific theme?
41
		 *
42
		 * @param string $stylesheet Theme directory name.
43
		 * @param \WP_Upgrader|null $upgrader The upgrader that's performing the current update.
44
		 * @return bool
45
		 */
46
		public function isThemeBeingUpgraded($stylesheet, $upgrader = null) {
47
			return $this->isBeingUpgraded('theme', $stylesheet, $upgrader);
48
		}
49
50
		/**
51
		 * Check if a specific theme or plugin is being upgraded.
52
		 *
53
		 * @param string $type
54
		 * @param string $id
55
		 * @param \Plugin_Upgrader|\WP_Upgrader|null $upgrader
56
		 * @return bool
57
		 */
58
		protected function isBeingUpgraded($type, $id, $upgrader = null) {
59
			if ( isset($upgrader) ) {
60
				list($currentType, $currentId) = $this->getThingBeingUpgradedBy($upgrader);
61
				if ( $currentType !== null ) {
62
					$this->currentType = $currentType;
63
					$this->currentId = $currentId;
64
				}
65
			}
66
			return ($this->currentType === $type) && ($this->currentId === $id);
67
		}
68
69
		/**
70
		 * Figure out which theme or plugin is being upgraded by a WP_Upgrader instance.
71
		 *
72
		 * Returns an array with two items. The first item is the type of the thing that's being
73
		 * upgraded: "plugin" or "theme". The second item is either the plugin basename or
74
		 * the theme directory name. If we can't determine what the upgrader is doing, both items
75
		 * will be NULL.
76
		 *
77
		 * Examples:
78
		 *      ['plugin', 'plugin-dir-name/plugin.php']
79
		 *      ['theme', 'theme-dir-name']
80
		 *
81
		 * @param \Plugin_Upgrader|\WP_Upgrader $upgrader
82
		 * @return array
83
		 */
84
		private function getThingBeingUpgradedBy($upgrader) {
85
			if ( !isset($upgrader, $upgrader->skin) ) {
86
				return array(null, null);
87
			}
88
89
			//Figure out which plugin or theme is being upgraded.
90
			$pluginFile = null;
91
			$themeDirectoryName = null;
92
93
			$skin = $upgrader->skin;
94
			if ( isset($skin->theme_info) && ($skin->theme_info instanceof \WP_Theme) ) {
95
				$themeDirectoryName = $skin->theme_info->get_stylesheet();
96
			} elseif ( $skin instanceof \Plugin_Upgrader_Skin ) {
97
				if ( isset($skin->plugin) && is_string($skin->plugin) && ($skin->plugin !== '') ) {
98
					$pluginFile = $skin->plugin;
99
				}
100
			} elseif ( $skin instanceof \Theme_Upgrader_Skin ) {
101
				if ( isset($skin->theme) && is_string($skin->theme) && ($skin->theme !== '') ) {
102
					$themeDirectoryName = $skin->theme;
103
				}
104
			} elseif ( isset($skin->plugin_info) && is_array($skin->plugin_info) ) {
105
				//This case is tricky because Bulk_Plugin_Upgrader_Skin (etc) doesn't actually store the plugin
106
				//filename anywhere. Instead, it has the plugin headers in $plugin_info. So the best we can
107
				//do is compare those headers to the headers of installed plugins.
108
				$pluginFile = $this->identifyPluginByHeaders($skin->plugin_info);
109
			}
110
111
			if ( $pluginFile !== null ) {
112
				return array('plugin', $pluginFile);
113
			} elseif ( $themeDirectoryName !== null ) {
114
				return array('theme', $themeDirectoryName);
115
			}
116
			return array(null, null);
117
		}
118
119
		/**
120
		 * Identify an installed plugin based on its headers.
121
		 *
122
		 * @param array $searchHeaders The plugin file header to look for.
123
		 * @return string|null Plugin basename ("foo/bar.php"), or NULL if we can't identify the plugin.
124
		 */
125
		private function identifyPluginByHeaders($searchHeaders) {
126
			if ( !function_exists('get_plugins') ){
127
				require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
128
			}
129
130
			$installedPlugins = get_plugins();
131
			$matches = array();
132
			foreach($installedPlugins as $pluginBasename => $headers) {
133
				$diff1 = array_diff_assoc($headers, $searchHeaders);
134
				$diff2 = array_diff_assoc($searchHeaders, $headers);
135
				if ( empty($diff1) && empty($diff2) ) {
136
					$matches[] = $pluginBasename;
137
				}
138
			}
139
140
			//It's possible (though very unlikely) that there could be two plugins with identical
141
			//headers. In that case, we can't unambiguously identify the plugin that's being upgraded.
142
			if ( count($matches) !== 1 ) {
143
				return null;
144
			}
145
146
			return reset($matches);
147
		}
148
149
		/**
150
		 * @access private
151
		 *
152
		 * @param mixed $input
153
		 * @param array $hookExtra
154
		 * @return mixed Returns $input unaltered.
155
		 */
156
		public function setUpgradedThing($input, $hookExtra) {
157
			if ( !empty($hookExtra['plugin']) && is_string($hookExtra['plugin']) ) {
158
				$this->currentId = $hookExtra['plugin'];
159
				$this->currentType = 'plugin';
160
			} elseif ( !empty($hookExtra['theme']) && is_string($hookExtra['theme']) ) {
161
				$this->currentId = $hookExtra['theme'];
162
				$this->currentType = 'theme';
163
			} else {
164
				$this->currentType = null;
165
				$this->currentId = null;
166
			}
167
			return $input;
168
		}
169
170
		/**
171
		 * @access private
172
		 *
173
		 * @param array $options
174
		 * @return array
175
		 */
176
		public function setUpgradedPluginFromOptions($options) {
177
			if ( isset($options['hook_extra']['plugin']) && is_string($options['hook_extra']['plugin']) ) {
178
				$this->currentType = 'plugin';
179
				$this->currentId = $options['hook_extra']['plugin'];
180
			} else {
181
				$this->currentType = null;
182
				$this->currentId = null;
183
			}
184
			return $options;
185
		}
186
187
		/**
188
		 * @access private
189
		 *
190
		 * @param mixed $input
191
		 * @return mixed Returns $input unaltered.
192
		 */
193
		public function clearUpgradedThing($input = null) {
194
			$this->currentId = null;
195
			$this->currentType = null;
196
			return $input;
197
		}
198
	}
199
200
endif;
201