Total Complexity | 53 |
Total Lines | 364 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Complex classes like MonsterInsights_Updater often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use MonsterInsights_Updater, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
17 | class MonsterInsights_Updater { |
||
18 | |||
19 | /** |
||
20 | * Plugin name. |
||
21 | * |
||
22 | * @since 6.0.0 |
||
23 | * |
||
24 | * @var bool|string |
||
25 | */ |
||
26 | public $plugin_name = false; |
||
27 | |||
28 | /** |
||
29 | * Plugin slug. |
||
30 | * |
||
31 | * @since 6.0.0 |
||
32 | * |
||
33 | * @var bool|string |
||
34 | */ |
||
35 | public $plugin_slug = false; |
||
36 | |||
37 | /** |
||
38 | * Plugin path. |
||
39 | * |
||
40 | * @since 6.0.0 |
||
41 | * |
||
42 | * @var bool|string |
||
43 | */ |
||
44 | public $plugin_path = false; |
||
45 | |||
46 | /** |
||
47 | * URL of the plugin. |
||
48 | * |
||
49 | * @since 6.0.0 |
||
50 | * |
||
51 | * @var bool|string |
||
52 | */ |
||
53 | public $plugin_url = false; |
||
54 | |||
55 | /** |
||
56 | * Remote URL for getting plugin updates. |
||
57 | * |
||
58 | * @since 6.0.0 |
||
59 | * |
||
60 | * @var bool|string |
||
61 | */ |
||
62 | public $remote_url = false; |
||
63 | |||
64 | /** |
||
65 | * Version number of the plugin. |
||
66 | * |
||
67 | * @since 6.0.0 |
||
68 | * |
||
69 | * @var bool|int |
||
70 | */ |
||
71 | public $version = false; |
||
72 | |||
73 | /** |
||
74 | * License key for the plugin. |
||
75 | * |
||
76 | * @since 6.0.0 |
||
77 | * |
||
78 | * @var bool|string |
||
79 | */ |
||
80 | public $key = false; |
||
81 | |||
82 | /** |
||
83 | * Holds the update data returned from the API. |
||
84 | * |
||
85 | * @since 6.0.0 |
||
86 | * |
||
87 | * @var bool|object |
||
88 | */ |
||
89 | public $update = false; |
||
90 | |||
91 | /** |
||
92 | * Holds the plugin info details for the update. |
||
93 | * |
||
94 | * @since 6.0.0 |
||
95 | * |
||
96 | * @var bool|object |
||
97 | */ |
||
98 | public $info = false; |
||
99 | |||
100 | /** |
||
101 | * Primary class constructor. |
||
102 | * |
||
103 | * @since 6.0.0 |
||
104 | * |
||
105 | * @param array $config Array of updater config args. |
||
106 | */ |
||
107 | public function __construct( array $config ) { |
||
108 | // Set class properties. |
||
109 | $accepted_args = array( |
||
110 | 'plugin_name', |
||
111 | 'plugin_slug', |
||
112 | 'plugin_path', |
||
113 | 'plugin_url', |
||
114 | 'remote_url', |
||
115 | 'version', |
||
116 | 'key' |
||
117 | ); |
||
118 | foreach ( $accepted_args as $arg ) { |
||
119 | $this->$arg = $config[$arg]; |
||
120 | } |
||
121 | |||
122 | // If the user cannot update plugins, stop processing here. |
||
123 | if ( ! current_user_can( 'update_plugins' ) && ( ! defined( 'DOING_CRON' ) || ! DOING_CRON ) ) { |
||
124 | return; |
||
125 | } |
||
126 | |||
127 | // If it's our site, then return so we don't redirect loop. |
||
128 | if ( strpos( site_url(), 'monsterinsights.com' ) !== false ) { |
||
129 | return; |
||
130 | } |
||
131 | |||
132 | // Load the updater hooks and filters. |
||
133 | add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'update_plugins_filter' ) ); |
||
134 | |||
135 | add_filter( 'http_request_args', array( $this, 'http_request_args' ), 10, 2 ); |
||
136 | add_filter( 'plugins_api', array( $this, 'plugins_api' ), 10, 3 ); |
||
137 | |||
138 | // ManageWP premium update filters |
||
139 | //add_filter( 'mwp_premium_update_notification', array( $this, 'premium_update_push' ) ); |
||
140 | //add_filter( 'mwp_premium_perform_update', array( $this, 'premium_update' ) ); |
||
141 | |||
142 | // Add additional info if the license is expired. |
||
143 | add_action( 'in_plugin_update_message-'. $this->plugin_path, array( $this, 'maybe_show_license_expired_message' ), 10, 2 ); |
||
144 | } |
||
145 | |||
146 | public function maybe_show_license_expired_message( $plugin_data, $response ) { |
||
147 | // If there's no download link but there is an update available there's an issue with the license. |
||
148 | if ( empty( $response->package ) ) { |
||
149 | $settings_url = is_network_admin() ? network_admin_url( 'admin.php?page=monsterinsights_network' ) : admin_url( 'admin.php?page=monsterinsights_settings' ); |
||
150 | // Translators: First one is a link to the settings page, second one is closing tag, third is a link to MonsterInsights.com |
||
151 | echo '<br />' . sprintf( __( 'In order to enable updates, you need to have a valid license key on the %1$ssettings page%2$s. If your license key is expired or you need a new key, then %3$sclick here to purchase MonsterInsights Pro%2$s.', 'google-analytics-for-wordpress' ), '<a href="' . esc_url( $settings_url ) . '">', '</a>', '<a href="' . monsterinsights_get_url( 'Plugin update', $this->plugin_name ) . '">' ); |
||
152 | } |
||
153 | } |
||
154 | |||
155 | /** |
||
156 | * Infuse plugin update details when WordPress runs its update checker. |
||
157 | * |
||
158 | * @since 6.0.0 |
||
159 | * |
||
160 | * @param object $value The WordPress update object. |
||
161 | * @return object $value Amended WordPress update object on success, default if object is empty. |
||
162 | */ |
||
163 | public function update_plugins_filter( $value ) { |
||
164 | |||
165 | // If no update object exists, return early. |
||
166 | if ( empty( $value ) ) { |
||
167 | return $value; |
||
168 | } |
||
169 | |||
170 | // Run update check by pinging the external API. If it fails, return the default update object. |
||
171 | if ( ! $this->update ) { |
||
172 | $this->update = $this->perform_remote_request( 'get-plugin-update', array( 'tgm-updater-plugin' => $this->plugin_slug ) ); |
||
|
|||
173 | if ( ! $this->update || ! empty( $this->update->error ) ) { |
||
174 | $this->update = false; |
||
175 | return $value; |
||
176 | } |
||
177 | } |
||
178 | |||
179 | // Infuse the update object with our data if the version from the remote API is newer. |
||
180 | if ( isset( $this->update->new_version ) && version_compare( $this->version, $this->update->new_version, '<' ) ) { |
||
181 | // The $plugin_update object contains new_version, package, slug and last_update keys. |
||
182 | //$this->update->full_slug = $this->plugin_slug; |
||
183 | //$this->update->name = $this->plugin_name; |
||
184 | $this->update->monsterinsights_plugin = true; |
||
185 | $this->update->old_version = $this->version; |
||
186 | $this->update->plugin = $this->plugin_path; |
||
187 | $value->response[$this->plugin_path] = $this->update; |
||
188 | } |
||
189 | |||
190 | // Return the update object. |
||
191 | return $value; |
||
192 | |||
193 | } |
||
194 | |||
195 | /** |
||
196 | * Disables SSL verification to prevent download package failures. |
||
197 | * |
||
198 | * @since 6.0.0 |
||
199 | * |
||
200 | * @param array $args Array of request args. |
||
201 | * @param string $url The URL to be pinged. |
||
202 | * @return array $args Amended array of request args. |
||
203 | */ |
||
204 | public function http_request_args( $args, $url ) { |
||
205 | |||
206 | // If this is an SSL request and we are performing an upgrade routine, disable SSL verification. |
||
207 | if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'tgm-updater-action=get-plugin-update' ) ) { |
||
208 | $args['sslverify'] = false; |
||
209 | } |
||
210 | |||
211 | return $args; |
||
212 | |||
213 | } |
||
214 | |||
215 | /** |
||
216 | * Filters the plugins_api function to get our own custom plugin information |
||
217 | * from our private repo. |
||
218 | * |
||
219 | * @since 6.0.0 |
||
220 | * |
||
221 | * @param object $api The original plugins_api object. |
||
222 | * @param string $action The action sent by plugins_api. |
||
223 | * @param array $args Additional args to send to plugins_api. |
||
224 | * @return object $api New stdClass with plugin information on success, default response on failure. |
||
225 | */ |
||
226 | public function plugins_api( $api, $action = '', $args = null ) { |
||
227 | |||
228 | $plugin = ( 'plugin_information' == $action ) && isset( $args->slug ) && ( $this->plugin_slug == $args->slug ); |
||
229 | |||
230 | // If our plugin matches the request, set our own plugin data, else return the default response. |
||
231 | if ( $plugin ) { |
||
232 | return $this->set_plugins_api( $api ); |
||
233 | } else { |
||
234 | return $api; |
||
235 | } |
||
236 | |||
237 | } |
||
238 | |||
239 | /** |
||
240 | * Pings a remote API to retrieve plugin information for WordPress to display. |
||
241 | * |
||
242 | * @since 6.0.0 |
||
243 | * |
||
244 | * @param object $default_api The default API object. |
||
245 | * @return object $api Return custom plugin information to plugins_api. |
||
246 | */ |
||
247 | public function set_plugins_api( $default_api ) { |
||
248 | |||
249 | // Perform the remote request to retrieve our plugin information. If it fails, return the default object. |
||
250 | if ( ! $this->info ) { |
||
251 | $this->info = $this->perform_remote_request( 'get-plugin-info', array( 'tgm-updater-plugin' => $this->plugin_slug ) ); |
||
252 | if ( ! $this->info || ! empty( $this->info->error ) ) { |
||
253 | $this->info = false; |
||
254 | return $default_api; |
||
255 | } |
||
256 | } |
||
257 | |||
258 | // Create a new stdClass object and populate it with our plugin information. |
||
259 | $api = new stdClass; |
||
260 | $api->name = isset( $this->info->name ) ? $this->info->name : ''; |
||
261 | $api->slug = isset( $this->info->slug ) ? $this->info->slug : ''; |
||
262 | $api->version = isset( $this->info->version ) ? $this->info->version : ''; |
||
263 | $api->author = isset( $this->info->author ) ? $this->info->author : ''; |
||
264 | $api->author_profile = isset( $this->info->author_profile ) ? $this->info->author_profile : ''; |
||
265 | $api->requires = isset( $this->info->requires ) ? $this->info->requires : ''; |
||
266 | $api->tested = isset( $this->info->tested ) ? $this->info->tested : ''; |
||
267 | $api->last_updated = isset( $this->info->last_updated ) ? $this->info->last_updated : ''; |
||
268 | $api->homepage = isset( $this->info->homepage ) ? $this->info->homepage : ''; |
||
269 | |||
270 | $changelog = isset( $this->info->changelog ) ? $this->info->changelog : ''; |
||
271 | $description = isset( $this->info->description ) ? $this->info->description : ''; |
||
272 | |||
273 | if ( ! empty( $changelog ) ) { |
||
274 | if ( ! empty( $description ) ) { |
||
275 | $api->sections['description'] = $description; |
||
276 | $api->sections['changelog'] = $changelog; |
||
277 | } else { |
||
278 | $api->sections['changelog'] = $changelog; |
||
279 | } |
||
280 | } else if ( ! empty( $description ) ) { |
||
281 | $api->sections['description'] = $description; |
||
282 | } else { |
||
283 | $api->sections = array(); |
||
284 | } |
||
285 | |||
286 | $api->download_link = isset( $this->info->download_link ) ? $this->info->download_link : ''; |
||
287 | |||
288 | // Return the new API object with our custom data. |
||
289 | return $api; |
||
290 | |||
291 | } |
||
292 | |||
293 | // Integration with ManageWP |
||
294 | public function premium_update_push( $premium_update ) { |
||
295 | if ( ! function_exists( 'get_plugin_data' ) ) { |
||
296 | include_once( ABSPATH . 'wp-admin/includes/plugin.php' ); |
||
297 | } |
||
298 | |||
299 | $update = $this->set_plugins_api( array() ); |
||
300 | if ( ! empty( $update ) && version_compare( MONSTERINSIGHTS_VERSION, $update->version, '<' ) ) { |
||
301 | $plugin_data = get_plugin_data( $update->slug ); |
||
302 | $plugin_data['type'] = 'plugin'; |
||
303 | $plugin_data['slug'] = $update->slug; |
||
304 | $plugin_data['new_version'] = $update->version; |
||
305 | $premium_update[] = $plugin_data; |
||
306 | } |
||
307 | return $premium_update; |
||
308 | } |
||
309 | |||
310 | // Integration with ManageWP |
||
311 | public function premium_update( $premium_update ) { |
||
325 | } |
||
326 | |||
327 | /** |
||
328 | * Queries the remote URL via wp_remote_post and returns a json decoded response. |
||
329 | * |
||
330 | * @since 6.0.0 |
||
331 | * |
||
332 | * @param string $action The name of the $_POST action var. |
||
333 | * @param array $body The content to retrieve from the remote URL. |
||
334 | * @param array $headers The headers to send to the remote URL. |
||
335 | * @param string $return_format The format for returning content from the remote URL. |
||
336 | * @return string|bool Json decoded response on success, false on failure. |
||
337 | */ |
||
338 | public function perform_remote_request( $action, $body = array(), $headers = array(), $return_format = 'json' ) { |
||
381 | |||
382 | } |
||
383 | } |
||
384 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.