This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
0 ignored issues
–
show
|
|||
2 | /** |
||
3 | * @package Freemius |
||
4 | * @copyright Copyright (c) 2015, Freemius, Inc. |
||
5 | * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 |
||
6 | * @since 1.0.4 |
||
7 | * |
||
8 | * @link https://github.com/easydigitaldownloads/EDD-License-handler/blob/master/EDD_SL_Plugin_Updater.php |
||
9 | */ |
||
10 | |||
11 | if ( ! defined( 'ABSPATH' ) ) { |
||
12 | exit; |
||
13 | } |
||
14 | |||
15 | class FS_Plugin_Updater { |
||
0 ignored issues
–
show
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.
You can fix this by adding a namespace to your class: namespace YourVendor;
class YourClass { }
When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries. ![]() |
|||
16 | |||
17 | /** |
||
18 | * @var Freemius |
||
19 | * @since 1.0.4 |
||
20 | */ |
||
21 | private $_fs; |
||
22 | /** |
||
23 | * @var FS_Logger |
||
24 | * @since 1.0.4 |
||
25 | */ |
||
26 | private $_logger; |
||
27 | /** |
||
28 | * @var object |
||
29 | * @since 1.1.8.1 |
||
30 | */ |
||
31 | private $_update_details; |
||
32 | /** |
||
33 | * @var array |
||
34 | * @since 2.1.2 |
||
35 | */ |
||
36 | private $_translation_updates; |
||
37 | |||
38 | private static $_upgrade_basename = null; |
||
39 | |||
40 | #-------------------------------------------------------------------------------- |
||
41 | #region Singleton |
||
42 | #-------------------------------------------------------------------------------- |
||
43 | |||
44 | /** |
||
45 | * @var FS_Plugin_Updater[] |
||
46 | * @since 2.0.0 |
||
47 | */ |
||
48 | private static $_INSTANCES = array(); |
||
49 | |||
50 | /** |
||
51 | * @param Freemius $freemius |
||
52 | * |
||
53 | * @return FS_Plugin_Updater |
||
54 | */ |
||
55 | static function instance( Freemius $freemius ) { |
||
0 ignored issues
–
show
|
|||
56 | $key = $freemius->get_id(); |
||
57 | |||
58 | if ( ! isset( self::$_INSTANCES[ $key ] ) ) { |
||
59 | self::$_INSTANCES[ $key ] = new self( $freemius ); |
||
60 | } |
||
61 | |||
62 | return self::$_INSTANCES[ $key ]; |
||
63 | } |
||
64 | |||
65 | #endregion |
||
66 | |||
67 | private function __construct( Freemius $freemius ) { |
||
68 | $this->_fs = $freemius; |
||
69 | |||
70 | $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $freemius->get_slug() . '_updater', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK ); |
||
71 | |||
72 | $this->filters(); |
||
73 | } |
||
74 | |||
75 | /** |
||
76 | * Initiate required filters. |
||
77 | * |
||
78 | * @author Vova Feldman (@svovaf) |
||
79 | * @since 1.0.4 |
||
80 | */ |
||
81 | private function filters() { |
||
82 | // Override request for plugin information |
||
83 | add_filter( 'plugins_api', array( &$this, 'plugins_api_filter' ), 10, 3 ); |
||
84 | |||
85 | $this->add_transient_filters(); |
||
86 | |||
87 | /** |
||
88 | * If user has the premium plugin's code but do NOT have an active license, |
||
89 | * encourage him to upgrade by showing that there's a new release, but instead |
||
90 | * of showing an update link, show upgrade link to the pricing page. |
||
91 | * |
||
92 | * @since 1.1.6 |
||
93 | * |
||
94 | */ |
||
95 | // WP 2.9+ |
||
96 | add_action( "after_plugin_row_{$this->_fs->get_plugin_basename()}", array( |
||
97 | &$this, |
||
98 | 'catch_plugin_update_row' |
||
99 | ), 9 ); |
||
100 | add_action( "after_plugin_row_{$this->_fs->get_plugin_basename()}", array( |
||
101 | &$this, |
||
102 | 'edit_and_echo_plugin_update_row' |
||
103 | ), 11, 2 ); |
||
104 | |||
105 | add_action( 'admin_head', array( &$this, 'catch_plugin_information_dialog_contents' ) ); |
||
106 | |||
107 | if ( ! WP_FS__IS_PRODUCTION_MODE ) { |
||
108 | add_filter( 'http_request_host_is_external', array( |
||
109 | $this, |
||
110 | 'http_request_host_is_external_filter' |
||
111 | ), 10, 3 ); |
||
112 | } |
||
113 | |||
114 | if ( $this->_fs->is_premium() ) { |
||
115 | if ( ! $this->is_correct_folder_name() ) { |
||
116 | add_filter( 'upgrader_post_install', array( &$this, '_maybe_update_folder_name' ), 10, 3 ); |
||
117 | } |
||
118 | |||
119 | add_filter( 'upgrader_pre_install', array( 'FS_Plugin_Updater', '_store_basename_for_source_adjustment' ), 1, 2 ); |
||
120 | add_filter( 'upgrader_source_selection', array( 'FS_Plugin_Updater', '_maybe_adjust_source_dir' ), 1, 3 ); |
||
121 | |||
122 | if ( ! $this->_fs->has_any_active_valid_license() ) { |
||
123 | add_filter( 'wp_prepare_themes_for_js', array( &$this, 'change_theme_update_info_html' ), 10, 1 ); |
||
124 | } |
||
125 | } |
||
126 | } |
||
127 | |||
128 | /** |
||
129 | * @author Leo Fajardo (@leorw) |
||
130 | * @since 2.1.4 |
||
131 | */ |
||
132 | function catch_plugin_information_dialog_contents() { |
||
0 ignored issues
–
show
|
|||
133 | if ( |
||
134 | 'plugin-information' !== fs_request_get( 'tab', false ) || |
||
135 | $this->_fs->get_slug() !== fs_request_get( 'plugin', false ) |
||
136 | ) { |
||
137 | return; |
||
138 | } |
||
139 | |||
140 | add_action( 'admin_footer', array( &$this, 'edit_and_echo_plugin_information_dialog_contents' ), 0, 1 ); |
||
141 | |||
142 | ob_start(); |
||
143 | } |
||
144 | |||
145 | /** |
||
146 | * @author Leo Fajardo (@leorw) |
||
147 | * @since 2.1.4 |
||
148 | * |
||
149 | * @param string $hook_suffix |
||
150 | */ |
||
151 | function edit_and_echo_plugin_information_dialog_contents( $hook_suffix ) { |
||
0 ignored issues
–
show
|
|||
152 | if ( |
||
153 | 'plugin-information' !== fs_request_get( 'tab', false ) || |
||
154 | $this->_fs->get_slug() !== fs_request_get( 'plugin', false ) |
||
155 | ) { |
||
156 | return; |
||
157 | } |
||
158 | |||
159 | $license = $this->_fs->_get_license(); |
||
160 | |||
161 | $subscription = ( is_object( $license ) && ! $license->is_lifetime() ) ? |
||
162 | $this->_fs->_get_subscription( $license->id ) : |
||
163 | null; |
||
164 | |||
165 | $contents = ob_get_clean(); |
||
166 | |||
167 | /** |
||
168 | * Replace the plugin information dialog's "Install Update Now" button's text and URL. If there's a license, |
||
169 | * the text will be "Renew license" and will link to the checkout page with the license's billing cycle |
||
170 | * and quota. If there's no license, the text will be "Buy license" and will link to the pricing page. |
||
171 | */ |
||
172 | $contents = preg_replace( |
||
173 | '/(.+\<a.+)(id="plugin_update_from_iframe")(.+href=")([^\s]+)(".+\>)(.+)(\<\/a.+)/is', |
||
174 | is_object( $license ) ? |
||
175 | sprintf( |
||
176 | '$1$3%s$5%s$7', |
||
177 | $this->_fs->checkout_url( |
||
178 | is_object( $subscription ) ? |
||
179 | ( 1 == $subscription->billing_cycle ? WP_FS__PERIOD_MONTHLY : WP_FS__PERIOD_ANNUALLY ) : |
||
180 | WP_FS__PERIOD_LIFETIME, |
||
181 | false, |
||
182 | array( 'licenses' => $license->quota ) |
||
183 | ), |
||
184 | fs_text_inline( 'Renew license', 'renew-license', $this->_fs->get_slug() ) |
||
185 | ) : |
||
186 | sprintf( |
||
187 | '$1$3%s$5%s$7', |
||
188 | $this->_fs->pricing_url(), |
||
189 | fs_text_inline( 'Buy license', 'buy-license', $this->_fs->get_slug() ) |
||
190 | ), |
||
191 | $contents |
||
192 | ); |
||
193 | |||
194 | echo $contents; |
||
195 | } |
||
196 | |||
197 | /** |
||
198 | * @author Vova Feldman (@svovaf) |
||
199 | * @since 2.0.0 |
||
200 | */ |
||
201 | private function add_transient_filters() { |
||
202 | add_filter( 'pre_set_site_transient_update_plugins', array( |
||
203 | &$this, |
||
204 | 'pre_set_site_transient_update_plugins_filter' |
||
205 | ) ); |
||
206 | |||
207 | add_filter( 'pre_set_site_transient_update_themes', array( |
||
208 | &$this, |
||
209 | 'pre_set_site_transient_update_plugins_filter' |
||
210 | ) ); |
||
211 | } |
||
212 | |||
213 | /** |
||
214 | * @author Vova Feldman (@svovaf) |
||
215 | * @since 2.0.0 |
||
216 | */ |
||
217 | private function remove_transient_filters() { |
||
218 | remove_filter( 'pre_set_site_transient_update_plugins', array( |
||
219 | &$this, |
||
220 | 'pre_set_site_transient_update_plugins_filter' |
||
221 | ) ); |
||
222 | |||
223 | remove_filter( 'pre_set_site_transient_update_themes', array( |
||
224 | &$this, |
||
225 | 'pre_set_site_transient_update_plugins_filter' |
||
226 | ) ); |
||
227 | } |
||
228 | |||
229 | /** |
||
230 | * Capture plugin update row by turning output buffering. |
||
231 | * |
||
232 | * @author Vova Feldman (@svovaf) |
||
233 | * @since 1.1.6 |
||
234 | */ |
||
235 | function catch_plugin_update_row() { |
||
0 ignored issues
–
show
|
|||
236 | ob_start(); |
||
237 | } |
||
238 | |||
239 | /** |
||
240 | * Overrides default update message format with "renew your license" message. |
||
241 | * |
||
242 | * @author Vova Feldman (@svovaf) |
||
243 | * @since 1.1.6 |
||
244 | * |
||
245 | * @param string $file |
||
246 | * @param array $plugin_data |
||
247 | */ |
||
248 | function edit_and_echo_plugin_update_row( $file, $plugin_data ) { |
||
0 ignored issues
–
show
|
|||
249 | $plugin_update_row = ob_get_clean(); |
||
250 | |||
251 | $current = get_site_transient( 'update_plugins' ); |
||
252 | if ( ! isset( $current->response[ $file ] ) ) { |
||
253 | echo $plugin_update_row; |
||
254 | |||
255 | return; |
||
256 | } |
||
257 | |||
258 | $r = $current->response[ $file ]; |
||
259 | |||
260 | if ( ! $this->_fs->has_any_active_valid_license() ) { |
||
261 | /** |
||
262 | * Turn the "new version" text into a link that opens the plugin information dialog when clicked and |
||
263 | * make the "View version x details" text link to the checkout page instead of opening the plugin |
||
264 | * information dialog when clicked. |
||
265 | * |
||
266 | * Sample input: |
||
267 | * There is a new version of Awesome Plugin available. <a href="...>View version x.y.z details</a> or <a href="...>update now</a>. |
||
268 | * Output: |
||
269 | * There is a <a href="...>new version</a> of Awesome Plugin available. <a href="...>Buy a license now</a> to access version x.y.z security & feature updates, and support. |
||
270 | * |
||
271 | * @author Leo Fajardo (@leorw) |
||
272 | */ |
||
273 | $plugin_update_row = preg_replace( |
||
274 | '/(\<div.+>)(.+)(\<a.+href="([^\s]+)"([^\<]+)\>.+\<a.+)(\<\/div\>)/is', |
||
275 | ( |
||
276 | '$1' . |
||
277 | sprintf( |
||
278 | fs_text_inline( 'There is a %s of %s available.', 'new-version-available', $this->_fs->get_slug() ), |
||
279 | sprintf( |
||
280 | '<a href="$4"%s>%s</a>', |
||
281 | '$5', |
||
282 | fs_text_inline( 'new version', 'new-version', $this->_fs->get_slug() ) |
||
283 | ), |
||
284 | $this->_fs->get_plugin_title() |
||
285 | ) . |
||
286 | ' ' . |
||
287 | $this->_fs->version_upgrade_checkout_link( $r->new_version ) . |
||
288 | '$6' |
||
289 | ), |
||
290 | $plugin_update_row |
||
291 | ); |
||
292 | } |
||
293 | |||
294 | if ( |
||
295 | $this->_fs->is_plugin() && |
||
296 | isset( $r->upgrade_notice ) && |
||
297 | strlen( trim( $r->upgrade_notice ) ) > 0 |
||
298 | ) { |
||
299 | $slug = $this->_fs->get_slug(); |
||
300 | |||
301 | $upgrade_notice_html = sprintf( |
||
302 | '<p class="notice fs-upgrade-notice fs-slug-%1s fs-type-%2s" data-slug="%1s" data-type="%2s"><strong>%3s</strong> %4s</p>', |
||
303 | $slug, |
||
304 | $this->_fs->get_module_type(), |
||
305 | fs_text_inline( 'Important Upgrade Notice:', 'upgrade_notice', $slug ), |
||
306 | esc_html( $r->upgrade_notice ) |
||
307 | ); |
||
308 | |||
309 | $plugin_update_row = str_replace( '</div>', '</div>' . $upgrade_notice_html, $plugin_update_row ); |
||
310 | } |
||
311 | |||
312 | echo $plugin_update_row; |
||
313 | } |
||
314 | |||
315 | /** |
||
316 | * @author Leo Fajardo (@leorw) |
||
317 | * @since 2.0.2 |
||
318 | * |
||
319 | * @param array $prepared_themes |
||
320 | * |
||
321 | * @return array |
||
322 | */ |
||
323 | function change_theme_update_info_html( $prepared_themes ) { |
||
0 ignored issues
–
show
|
|||
324 | $theme_basename = $this->_fs->get_plugin_basename(); |
||
325 | |||
326 | if ( ! isset( $prepared_themes[ $theme_basename ] ) ) { |
||
327 | return $prepared_themes; |
||
328 | } |
||
329 | |||
330 | $themes_update = get_site_transient( 'update_themes' ); |
||
331 | if ( ! isset( $themes_update->response[ $theme_basename ] ) || |
||
332 | empty( $themes_update->response[ $theme_basename ]['package'] ) |
||
333 | ) { |
||
334 | return $prepared_themes; |
||
335 | } |
||
336 | |||
337 | $prepared_themes[ $theme_basename ]['update'] = preg_replace( |
||
338 | '/(\<p.+>)(.+)(\<a.+\<a.+)\.(.+\<\/p\>)/is', |
||
339 | '$1 $2 ' . $this->_fs->version_upgrade_checkout_link( $themes_update->response[ $theme_basename ]['new_version'] ) . |
||
340 | '$4', |
||
341 | $prepared_themes[ $theme_basename ]['update'] |
||
342 | ); |
||
343 | |||
344 | // Set to false to prevent the "Update now" link for the context theme from being shown on the "Themes" page. |
||
345 | $prepared_themes[ $theme_basename ]['hasPackage'] = false; |
||
346 | |||
347 | return $prepared_themes; |
||
348 | } |
||
349 | |||
350 | /** |
||
351 | * Since WP version 3.6, a new security feature was added that denies access to repository with a local ip. |
||
352 | * During development mode we want to be able updating plugin versions via our localhost repository. This |
||
353 | * filter white-list all domains including "api.freemius". |
||
354 | * |
||
355 | * @link http://www.emanueletessore.com/wordpress-download-failed-valid-url-provided/ |
||
356 | * |
||
357 | * @author Vova Feldman (@svovaf) |
||
358 | * @since 1.0.4 |
||
359 | * |
||
360 | * @param bool $allow |
||
361 | * @param string $host |
||
362 | * @param string $url |
||
363 | * |
||
364 | * @return bool |
||
365 | */ |
||
366 | function http_request_host_is_external_filter( $allow, $host, $url ) { |
||
0 ignored issues
–
show
|
|||
367 | return ( false !== strpos( $host, 'freemius' ) ) ? true : $allow; |
||
368 | } |
||
369 | |||
370 | /** |
||
371 | * Check for Updates at the defined API endpoint and modify the update array. |
||
372 | * |
||
373 | * This function dives into the update api just when WordPress creates its update array, |
||
374 | * then adds a custom API call and injects the custom plugin data retrieved from the API. |
||
375 | * It is reassembled from parts of the native WordPress plugin update code. |
||
376 | * See wp-includes/update.php line 121 for the original wp_update_plugins() function. |
||
377 | * |
||
378 | * @author Vova Feldman (@svovaf) |
||
379 | * @since 1.0.4 |
||
380 | * |
||
381 | * @uses FS_Api |
||
382 | * |
||
383 | * @param object $transient_data Update array build by WordPress. |
||
384 | * |
||
385 | * @return object Modified update array with custom plugin data. |
||
386 | */ |
||
387 | function pre_set_site_transient_update_plugins_filter( $transient_data ) { |
||
0 ignored issues
–
show
|
|||
388 | $this->_logger->entrance(); |
||
389 | |||
390 | /** |
||
391 | * "plugins" or "themes". |
||
392 | * |
||
393 | * @author Leo Fajardo (@leorw) |
||
394 | * @since 1.2.2 |
||
395 | */ |
||
396 | $module_type = $this->_fs->get_module_type() . 's'; |
||
397 | |||
398 | /** |
||
399 | * Ensure that we don't mix plugins update info with themes update info. |
||
400 | * |
||
401 | * @author Leo Fajardo (@leorw) |
||
402 | * @since 1.2.2 |
||
403 | */ |
||
404 | if ( "pre_set_site_transient_update_{$module_type}" !== current_filter() ) { |
||
405 | return $transient_data; |
||
406 | } |
||
407 | |||
408 | if ( empty( $transient_data ) || |
||
409 | defined( 'WP_FS__UNINSTALL_MODE' ) |
||
410 | ) { |
||
411 | return $transient_data; |
||
412 | } |
||
413 | |||
414 | if ( ! isset( $this->_update_details ) ) { |
||
415 | // Get plugin's newest update. |
||
416 | $new_version = $this->_fs->get_update( |
||
417 | false, |
||
418 | fs_request_get_bool( 'force-check' ), |
||
419 | WP_FS__TIME_24_HOURS_IN_SEC / 24, |
||
420 | $this->_fs->get_plugin_version() |
||
421 | ); |
||
422 | |||
423 | $this->_update_details = false; |
||
0 ignored issues
–
show
It seems like
false of type false is incompatible with the declared type object of property $_update_details .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||
424 | |||
425 | if ( is_object( $new_version ) ) { |
||
426 | $this->_logger->log( 'Found newer plugin version ' . $new_version->version ); |
||
427 | |||
428 | /** |
||
429 | * Cache plugin details locally since set_site_transient( 'update_plugins' ) |
||
430 | * called multiple times and the non wp.org plugins are filtered after the |
||
431 | * call to .org. |
||
432 | * |
||
433 | * @since 1.1.8.1 |
||
434 | */ |
||
435 | $this->_update_details = $this->get_update_details( $new_version ); |
||
436 | } |
||
437 | } |
||
438 | |||
439 | if ( is_object( $this->_update_details ) ) { |
||
440 | // Add plugin to transient data. |
||
441 | $transient_data->response[ $this->_fs->get_plugin_basename() ] = $this->_fs->is_plugin() ? |
||
442 | $this->_update_details : |
||
443 | (array) $this->_update_details; |
||
444 | } |
||
445 | |||
446 | $slug = $this->_fs->get_slug(); |
||
447 | |||
448 | if ( $this->_fs->is_org_repo_compliant() && $this->_fs->is_freemium() ) { |
||
449 | if ( ! isset( $this->_translation_updates ) ) { |
||
450 | $this->_translation_updates = array(); |
||
451 | |||
452 | if ( current_user_can( 'update_languages' ) ) { |
||
453 | $translation_updates = $this->fetch_wp_org_module_translation_updates( $module_type, $slug ); |
||
454 | if ( ! empty( $translation_updates ) ) { |
||
455 | $this->_translation_updates = $translation_updates; |
||
456 | } |
||
457 | } |
||
458 | } |
||
459 | |||
460 | if ( ! empty( $this->_translation_updates ) ) { |
||
461 | $all_translation_updates = ( isset( $transient_data->translations ) && is_array( $transient_data->translations ) ) ? |
||
462 | $transient_data->translations : |
||
463 | array(); |
||
464 | |||
465 | $current_plugin_translation_updates_map = array(); |
||
466 | foreach ( $all_translation_updates as $key => $translation_update ) { |
||
467 | if ( $module_type === ( $translation_update['type'] . 's' ) && $slug === $translation_update['slug'] ) { |
||
468 | $current_plugin_translation_updates_map[ $translation_update['language'] ] = $translation_update; |
||
469 | unset( $all_translation_updates[ $key ] ); |
||
470 | } |
||
471 | } |
||
472 | |||
473 | foreach ( $this->_translation_updates as $translation_update ) { |
||
474 | $lang = $translation_update['language']; |
||
475 | if ( ! isset( $current_plugin_translation_updates_map[ $lang ] ) || |
||
476 | version_compare( $translation_update['version'], $current_plugin_translation_updates_map[ $lang ]['version'], '>' ) |
||
477 | ) { |
||
478 | $current_plugin_translation_updates_map[ $lang ] = $translation_update; |
||
479 | } |
||
480 | } |
||
481 | |||
482 | $transient_data->translations = array_merge( $all_translation_updates, array_values( $current_plugin_translation_updates_map ) ); |
||
483 | } |
||
484 | } |
||
485 | |||
486 | return $transient_data; |
||
487 | } |
||
488 | |||
489 | /** |
||
490 | * Get module's required data for the updates mechanism. |
||
491 | * |
||
492 | * @author Vova Feldman (@svovaf) |
||
493 | * @since 2.0.0 |
||
494 | * |
||
495 | * @param \FS_Plugin_Tag $new_version |
||
496 | * |
||
497 | * @return object |
||
498 | */ |
||
499 | function get_update_details( FS_Plugin_Tag $new_version ) { |
||
0 ignored issues
–
show
|
|||
500 | $update = new stdClass(); |
||
501 | $update->slug = $this->_fs->get_slug(); |
||
502 | $update->new_version = $new_version->version; |
||
503 | $update->url = WP_FS__ADDRESS; |
||
504 | $update->package = $new_version->url; |
||
505 | $update->tested = $new_version->tested_up_to_version; |
||
506 | $update->requires = $new_version->requires_platform_version; |
||
507 | |||
508 | $icon = $this->_fs->get_local_icon_url(); |
||
509 | |||
510 | if ( ! empty( $icon ) ) { |
||
511 | $update->icons = array( |
||
512 | // '1x' => $icon, |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
54% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
513 | // '2x' => $icon, |
||
514 | 'default' => $icon, |
||
515 | ); |
||
516 | } |
||
517 | |||
518 | if ( $this->_fs->is_premium() ) { |
||
519 | $latest_tag = $this->_fs->_fetch_latest_version( $this->_fs->get_id(), false ); |
||
520 | |||
521 | if ( |
||
522 | isset( $latest_tag->readme ) && |
||
523 | isset( $latest_tag->readme->upgrade_notice ) && |
||
524 | ! empty( $latest_tag->readme->upgrade_notice ) |
||
525 | ) { |
||
526 | $update->upgrade_notice = $latest_tag->readme->upgrade_notice; |
||
527 | } |
||
528 | } |
||
529 | |||
530 | $update->{$this->_fs->get_module_type()} = $this->_fs->get_plugin_basename(); |
||
531 | |||
532 | return $update; |
||
533 | } |
||
534 | |||
535 | /** |
||
536 | * Update the updates transient with the module's update information. |
||
537 | * |
||
538 | * This method is required for multisite environment. |
||
539 | * If a module is site activated (not network) and not on the main site, |
||
540 | * the module will NOT be executed on the network level, therefore, the |
||
541 | * custom updates logic will not be executed as well, so unless we force |
||
542 | * the injection of the update into the updates transient, premium updates |
||
543 | * will not work. |
||
544 | * |
||
545 | * @author Vova Feldman (@svovaf) |
||
546 | * @since 2.0.0 |
||
547 | * |
||
548 | * @param \FS_Plugin_Tag $new_version |
||
549 | */ |
||
550 | function set_update_data( FS_Plugin_Tag $new_version ) { |
||
0 ignored issues
–
show
|
|||
551 | $this->_logger->entrance(); |
||
552 | |||
553 | $transient_key = "update_{$this->_fs->get_module_type()}s"; |
||
554 | |||
555 | $transient_data = get_site_transient( $transient_key ); |
||
556 | |||
557 | $transient_data = is_object( $transient_data ) ? |
||
558 | $transient_data : |
||
559 | new stdClass(); |
||
560 | |||
561 | // Alias. |
||
562 | $basename = $this->_fs->get_plugin_basename(); |
||
563 | $is_plugin = $this->_fs->is_plugin(); |
||
564 | |||
565 | if ( ! isset( $transient_data->response ) || |
||
566 | ! is_array( $transient_data->response ) |
||
567 | ) { |
||
568 | $transient_data->response = array(); |
||
569 | } else if ( ! empty( $transient_data->response[ $basename ] ) ) { |
||
570 | $version = $is_plugin ? |
||
571 | ( ! empty( $transient_data->response[ $basename ]->new_version ) ? |
||
572 | $transient_data->response[ $basename ]->new_version : |
||
573 | null |
||
574 | ) : ( ! empty( $transient_data->response[ $basename ]['new_version'] ) ? |
||
575 | $transient_data->response[ $basename ]['new_version'] : |
||
576 | null |
||
577 | ); |
||
578 | |||
579 | if ( $version == $new_version->version ) { |
||
580 | // The update data is already set. |
||
581 | return; |
||
582 | } |
||
583 | } |
||
584 | |||
585 | // Remove the added filters. |
||
586 | $this->remove_transient_filters(); |
||
587 | |||
588 | $this->_update_details = $this->get_update_details( $new_version ); |
||
589 | |||
590 | // Set update data in transient. |
||
591 | $transient_data->response[ $basename ] = $is_plugin ? |
||
592 | $this->_update_details : |
||
593 | (array) $this->_update_details; |
||
594 | |||
595 | if ( ! isset( $transient_data->checked ) || |
||
596 | ! is_array( $transient_data->checked ) |
||
597 | ) { |
||
598 | $transient_data->checked = array(); |
||
599 | } |
||
600 | |||
601 | // Flag the module as if it was already checked. |
||
602 | $transient_data->checked[ $basename ] = $this->_fs->get_plugin_version(); |
||
603 | $transient_data->last_checked = time(); |
||
604 | |||
605 | set_site_transient( $transient_key, $transient_data ); |
||
606 | |||
607 | $this->add_transient_filters(); |
||
608 | } |
||
609 | |||
610 | /** |
||
611 | * @author Leo Fajardo (@leorw) |
||
612 | * @since 2.0.2 |
||
613 | */ |
||
614 | function delete_update_data() { |
||
0 ignored issues
–
show
|
|||
615 | $this->_logger->entrance(); |
||
616 | |||
617 | $transient_key = "update_{$this->_fs->get_module_type()}s"; |
||
618 | |||
619 | $transient_data = get_site_transient( $transient_key ); |
||
620 | |||
621 | // Alias |
||
622 | $basename = $this->_fs->get_plugin_basename(); |
||
623 | |||
624 | if ( ! is_object( $transient_data ) || |
||
625 | ! isset( $transient_data->response ) || |
||
626 | ! is_array( $transient_data->response ) || |
||
627 | empty( $transient_data->response[ $basename ] ) |
||
628 | ) { |
||
629 | return; |
||
630 | } |
||
631 | |||
632 | unset( $transient_data->response[ $basename ] ); |
||
633 | |||
634 | // Remove the added filters. |
||
635 | $this->remove_transient_filters(); |
||
636 | |||
637 | set_site_transient( $transient_key, $transient_data ); |
||
638 | |||
639 | $this->add_transient_filters(); |
||
640 | } |
||
641 | |||
642 | /** |
||
643 | * Try to fetch plugin's info from .org repository. |
||
644 | * |
||
645 | * @author Vova Feldman (@svovaf) |
||
646 | * @since 1.0.5 |
||
647 | * |
||
648 | * @param string $action |
||
649 | * @param object $args |
||
650 | * |
||
651 | * @return bool|mixed |
||
652 | */ |
||
653 | static function _fetch_plugin_info_from_repository( $action, $args ) { |
||
0 ignored issues
–
show
|
|||
654 | $url = $http_url = 'http://api.wordpress.org/plugins/info/1.0/'; |
||
0 ignored issues
–
show
$http_url 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 ![]() |
|||
655 | if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) { |
||
0 ignored issues
–
show
$ssl 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 ![]() |
|||
656 | $url = set_url_scheme( $url, 'https' ); |
||
657 | } |
||
658 | |||
659 | $args = array( |
||
660 | 'timeout' => 15, |
||
661 | 'body' => array( |
||
662 | 'action' => $action, |
||
663 | 'request' => serialize( $args ) |
||
664 | ) |
||
665 | ); |
||
666 | |||
667 | $request = wp_remote_post( $url, $args ); |
||
668 | |||
669 | if ( is_wp_error( $request ) ) { |
||
670 | return false; |
||
671 | } |
||
672 | |||
673 | $res = maybe_unserialize( wp_remote_retrieve_body( $request ) ); |
||
674 | |||
675 | if ( ! is_object( $res ) && ! is_array( $res ) ) { |
||
676 | return false; |
||
677 | } |
||
678 | |||
679 | return $res; |
||
680 | } |
||
681 | |||
682 | /** |
||
683 | * Fetches module translation updates from wordpress.org. |
||
684 | * |
||
685 | * @author Leo Fajardo (@leorw) |
||
686 | * @since 2.1.2 |
||
687 | * |
||
688 | * @param string $module_type |
||
689 | * @param string $slug |
||
690 | * |
||
691 | * @return array|null |
||
692 | */ |
||
693 | private function fetch_wp_org_module_translation_updates( $module_type, $slug ) { |
||
694 | $plugin_data = $this->_fs->get_plugin_data(); |
||
695 | |||
696 | $locales = array_values( get_available_languages() ); |
||
697 | $locales = apply_filters( "{$module_type}_update_check_locales", $locales ); |
||
698 | $locales = array_unique( $locales ); |
||
699 | |||
700 | $plugin_basename = $this->_fs->get_plugin_basename(); |
||
701 | if ( 'themes' === $module_type ) { |
||
702 | $plugin_basename = $slug; |
||
703 | } |
||
704 | |||
705 | global $wp_version; |
||
0 ignored issues
–
show
Compatibility
Best Practice
introduced
by
Use of
global functionality is not recommended; it makes your code harder to test, and less reusable.
Instead of relying on 1. Pass all data via parametersfunction myFunction($a, $b) {
// Do something
}
2. Create a class that maintains your stateclass MyClass {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
public function myFunction() {
// Do something
}
}
![]() |
|||
706 | |||
707 | $request_args = array( |
||
708 | 'timeout' => 15, |
||
709 | 'body' => array( |
||
710 | "{$module_type}" => json_encode( |
||
711 | array( |
||
712 | "{$module_type}" => array( |
||
713 | $plugin_basename => array( |
||
714 | 'Name' => trim( str_replace( $this->_fs->get_plugin()->premium_suffix, '', $plugin_data['Name'] ) ), |
||
715 | 'Author' => $plugin_data['Author'], |
||
716 | ) |
||
717 | ) |
||
718 | ) |
||
719 | ), |
||
720 | 'translations' => json_encode( $this->get_installed_translations( $module_type, $slug ) ), |
||
721 | 'locale' => json_encode( $locales ) |
||
722 | ), |
||
723 | 'user-agent' => ( 'WordPress/' . $wp_version . '; ' . home_url( '/' ) ) |
||
724 | ); |
||
725 | |||
726 | $url = "http://api.wordpress.org/{$module_type}/update-check/1.1/"; |
||
727 | if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) { |
||
0 ignored issues
–
show
$ssl 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 ![]() |
|||
728 | $url = set_url_scheme( $url, 'https' ); |
||
729 | } |
||
730 | |||
731 | $raw_response = Freemius::safe_remote_post( |
||
732 | $url, |
||
733 | $request_args, |
||
734 | WP_FS__TIME_24_HOURS_IN_SEC, |
||
735 | WP_FS__TIME_12_HOURS_IN_SEC, |
||
736 | false |
||
737 | ); |
||
738 | |||
739 | if ( is_wp_error( $raw_response ) ) { |
||
740 | return null; |
||
741 | } |
||
742 | |||
743 | $response = json_decode( wp_remote_retrieve_body( $raw_response ), true ); |
||
744 | |||
745 | if ( ! is_array( $response ) ) { |
||
746 | return null; |
||
747 | } |
||
748 | |||
749 | if ( ! isset( $response['translations'] ) || empty( $response['translations'] ) ) { |
||
750 | return null; |
||
751 | } |
||
752 | |||
753 | return $response['translations']; |
||
754 | } |
||
755 | |||
756 | /** |
||
757 | * @author Leo Fajardo (@leorw) |
||
758 | * @since 2.1.2 |
||
759 | * |
||
760 | * @param string $module_type |
||
761 | * @param string $slug |
||
762 | * |
||
763 | * @return array |
||
764 | */ |
||
765 | private function get_installed_translations( $module_type, $slug ) { |
||
766 | if ( function_exists( 'wp_get_installed_translations' ) ) { |
||
767 | return wp_get_installed_translations( $module_type ); |
||
768 | } |
||
769 | |||
770 | $dir = "/{$module_type}"; |
||
771 | |||
772 | if ( ! is_dir( WP_LANG_DIR . $dir ) ) |
||
773 | return array(); |
||
774 | |||
775 | $files = scandir( WP_LANG_DIR . $dir ); |
||
776 | if ( ! $files ) |
||
0 ignored issues
–
show
The expression
$files of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
777 | return array(); |
||
778 | |||
779 | $language_data = array(); |
||
780 | |||
781 | foreach ( $files as $file ) { |
||
782 | if ( 0 !== strpos( $file, $slug ) ) { |
||
783 | continue; |
||
784 | } |
||
785 | |||
786 | if ( '.' === $file[0] || is_dir( WP_LANG_DIR . "{$dir}/{$file}" ) ) { |
||
787 | continue; |
||
788 | } |
||
789 | |||
790 | if ( substr( $file, -3 ) !== '.po' ) { |
||
791 | continue; |
||
792 | } |
||
793 | |||
794 | if ( ! preg_match( '/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z0-9]+)?).po/', $file, $match ) ) { |
||
795 | continue; |
||
796 | } |
||
797 | |||
798 | if ( ! in_array( substr( $file, 0, -3 ) . '.mo', $files ) ) { |
||
799 | continue; |
||
800 | } |
||
801 | |||
802 | list( , $textdomain, $language ) = $match; |
||
803 | |||
804 | if ( '' === $textdomain ) { |
||
805 | $textdomain = 'default'; |
||
806 | } |
||
807 | |||
808 | $language_data[ $textdomain ][ $language ] = wp_get_pomo_file_data( WP_LANG_DIR . "{$dir}/{$file}" ); |
||
809 | } |
||
810 | |||
811 | return $language_data; |
||
812 | } |
||
813 | |||
814 | /** |
||
815 | * Updates information on the "View version x.x details" page with custom data. |
||
816 | * |
||
817 | * @author Vova Feldman (@svovaf) |
||
818 | * @since 1.0.4 |
||
819 | * |
||
820 | * @uses FS_Api |
||
821 | * |
||
822 | * @param object $data |
||
823 | * @param string $action |
||
824 | * @param mixed $args |
||
825 | * |
||
826 | * @return object |
||
827 | */ |
||
828 | function plugins_api_filter( $data, $action = '', $args = null ) { |
||
0 ignored issues
–
show
|
|||
829 | $this->_logger->entrance(); |
||
830 | |||
831 | if ( ( 'plugin_information' !== $action ) || |
||
832 | ! isset( $args->slug ) |
||
833 | ) { |
||
834 | return $data; |
||
835 | } |
||
836 | |||
837 | $addon = false; |
||
838 | $is_addon = false; |
||
839 | |||
840 | if ( $this->_fs->get_slug() !== $args->slug ) { |
||
841 | $addon = $this->_fs->get_addon_by_slug( $args->slug ); |
||
842 | |||
843 | if ( ! is_object( $addon ) ) { |
||
844 | return $data; |
||
845 | } |
||
846 | |||
847 | $is_addon = true; |
||
848 | } |
||
849 | |||
850 | $plugin_in_repo = false; |
||
851 | if ( ! $is_addon ) { |
||
852 | // Try to fetch info from .org repository. |
||
853 | $data = self::_fetch_plugin_info_from_repository( $action, $args ); |
||
854 | |||
855 | $plugin_in_repo = ( false !== $data ); |
||
856 | } |
||
857 | |||
858 | if ( ! $plugin_in_repo ) { |
||
859 | $data = $args; |
||
860 | |||
861 | // Fetch as much as possible info from local files. |
||
862 | $plugin_local_data = $this->_fs->get_plugin_data(); |
||
863 | $data->name = $plugin_local_data['Name']; |
||
864 | $data->author = $plugin_local_data['Author']; |
||
865 | $data->sections = array( |
||
866 | 'description' => 'Upgrade ' . $plugin_local_data['Name'] . ' to latest.', |
||
867 | ); |
||
868 | |||
869 | // @todo Store extra plugin info on Freemius or parse readme.txt markup. |
||
870 | /*$info = $this->_fs->get_api_site_scope()->call('/information.json'); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
59% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
871 | |||
872 | if ( !isset($info->error) ) { |
||
873 | $data = $info; |
||
874 | }*/ |
||
875 | } |
||
876 | |||
877 | $plugin_version = $this->_fs->get_plugin_version(); |
||
878 | |||
879 | // Get plugin's newest update. |
||
880 | $new_version = $this->get_latest_download_details( $is_addon ? $addon->id : false, $plugin_version ); |
||
881 | |||
882 | if ( ! is_object( $new_version ) || empty( $new_version->version ) ) { |
||
883 | $data->version = $plugin_version; |
||
884 | } else { |
||
885 | if ( $is_addon ) { |
||
886 | $data->name = $addon->title . ' ' . $this->_fs->get_text_inline( 'Add-On', 'addon' ); |
||
887 | $data->slug = $addon->slug; |
||
888 | $data->url = WP_FS__ADDRESS; |
||
889 | $data->package = $new_version->url; |
||
890 | } |
||
891 | |||
892 | if ( ! $plugin_in_repo ) { |
||
893 | $data->last_updated = ! is_null( $new_version->updated ) ? $new_version->updated : $new_version->created; |
||
894 | $data->requires = $new_version->requires_platform_version; |
||
895 | $data->tested = $new_version->tested_up_to_version; |
||
896 | } |
||
897 | |||
898 | $data->version = $new_version->version; |
||
899 | $data->download_link = $new_version->url; |
||
900 | |||
901 | if ( isset( $new_version->readme ) && is_object( $new_version->readme ) ) { |
||
902 | $new_version_readme_data = $new_version->readme; |
||
903 | if ( isset( $new_version_readme_data->sections ) ) { |
||
904 | $new_version_readme_data->sections = (array) $new_version_readme_data->sections; |
||
905 | } else { |
||
906 | $new_version_readme_data->sections = array(); |
||
907 | } |
||
908 | |||
909 | if ( isset( $data->sections ) ) { |
||
910 | if ( isset( $data->sections['screenshots'] ) ) { |
||
911 | $new_version_readme_data->sections['screenshots'] = $data->sections['screenshots']; |
||
912 | } |
||
913 | |||
914 | if ( isset( $data->sections['reviews'] ) ) { |
||
915 | $new_version_readme_data->sections['reviews'] = $data->sections['reviews']; |
||
916 | } |
||
917 | } |
||
918 | |||
919 | if ( isset( $new_version_readme_data->banners ) ) { |
||
920 | $new_version_readme_data->banners = (array) $new_version_readme_data->banners; |
||
921 | } else if ( isset( $data->banners ) ) { |
||
922 | $new_version_readme_data->banners = $data->banners; |
||
923 | } |
||
924 | |||
925 | $wp_org_sections = array( |
||
926 | 'author', |
||
927 | 'author_profile', |
||
928 | 'rating', |
||
929 | 'ratings', |
||
930 | 'num_ratings', |
||
931 | 'support_threads', |
||
932 | 'support_threads_resolved', |
||
933 | 'active_installs', |
||
934 | 'added', |
||
935 | 'homepage' |
||
936 | ); |
||
937 | |||
938 | foreach ( $wp_org_sections as $wp_org_section ) { |
||
939 | if ( isset( $data->{$wp_org_section} ) ) { |
||
940 | $new_version_readme_data->{$wp_org_section} = $data->{$wp_org_section}; |
||
941 | } |
||
942 | } |
||
943 | |||
944 | $data = $new_version_readme_data; |
||
945 | } |
||
946 | } |
||
947 | |||
948 | return $data; |
||
949 | } |
||
950 | |||
951 | /** |
||
952 | * @author Vova Feldman (@svovaf) |
||
953 | * @since 1.2.1.7 |
||
954 | * |
||
955 | * @param number|bool $addon_id |
||
956 | * @param bool|string $newer_than Since 2.2.1 |
||
957 | * @param bool|string $fetch_readme Since 2.2.1 |
||
958 | * |
||
959 | * @return object |
||
960 | */ |
||
961 | private function get_latest_download_details( $addon_id = false, $newer_than = false, $fetch_readme = true ) { |
||
962 | return $this->_fs->_fetch_latest_version( $addon_id, true, WP_FS__TIME_24_HOURS_IN_SEC, $newer_than, $fetch_readme ); |
||
963 | } |
||
964 | |||
965 | /** |
||
966 | * Checks if a given basename has a matching folder name |
||
967 | * with the current context plugin. |
||
968 | * |
||
969 | * @author Vova Feldman (@svovaf) |
||
970 | * @since 1.2.1.6 |
||
971 | * |
||
972 | * @return bool |
||
973 | */ |
||
974 | private function is_correct_folder_name() { |
||
975 | return ( $this->_fs->get_target_folder_name() == trim( dirname( $this->_fs->get_plugin_basename() ), '/\\' ) ); |
||
976 | } |
||
977 | |||
978 | /** |
||
979 | * This is a special after upgrade handler for migrating modules |
||
980 | * that didn't use the '-premium' suffix folder structure before |
||
981 | * the migration. |
||
982 | * |
||
983 | * @author Vova Feldman (@svovaf) |
||
984 | * @since 1.2.1.6 |
||
985 | * |
||
986 | * @param bool $response Install response. |
||
987 | * @param array $hook_extra Extra arguments passed to hooked filters. |
||
988 | * @param array $result Installation result data. |
||
989 | * |
||
990 | * @return bool |
||
991 | */ |
||
992 | function _maybe_update_folder_name( $response, $hook_extra, $result ) { |
||
0 ignored issues
–
show
|
|||
993 | $basename = $this->_fs->get_plugin_basename(); |
||
994 | |||
995 | if ( true !== $response || |
||
996 | empty( $hook_extra ) || |
||
997 | empty( $hook_extra['plugin'] ) || |
||
998 | $basename !== $hook_extra['plugin'] |
||
999 | ) { |
||
1000 | return $response; |
||
1001 | } |
||
1002 | |||
1003 | $active_plugins_basenames = get_option( 'active_plugins' ); |
||
1004 | |||
1005 | for ( $i = 0, $len = count( $active_plugins_basenames ); $i < $len; $i ++ ) { |
||
1006 | if ( $basename === $active_plugins_basenames[ $i ] ) { |
||
1007 | // Get filename including extension. |
||
1008 | $filename = basename( $basename ); |
||
1009 | |||
1010 | $new_basename = plugin_basename( |
||
1011 | trailingslashit( $this->_fs->is_premium() ? $this->_fs->get_premium_slug() : $this->_fs->get_slug() ) . |
||
1012 | $filename |
||
1013 | ); |
||
1014 | |||
1015 | // Verify that the expected correct path exists. |
||
1016 | if ( file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $new_basename ) ) ) { |
||
1017 | // Override active plugin name. |
||
1018 | $active_plugins_basenames[ $i ] = $new_basename; |
||
1019 | update_option( 'active_plugins', $active_plugins_basenames ); |
||
1020 | } |
||
1021 | |||
1022 | break; |
||
1023 | } |
||
1024 | } |
||
1025 | |||
1026 | return $response; |
||
1027 | } |
||
1028 | |||
1029 | #---------------------------------------------------------------------------------- |
||
1030 | #region Auto Activation |
||
1031 | #---------------------------------------------------------------------------------- |
||
1032 | |||
1033 | /** |
||
1034 | * Installs and active a plugin when explicitly requested that from a 3rd party service. |
||
1035 | * |
||
1036 | * This logic was inspired by the TGMPA GPL licensed library by Thomas Griffin. |
||
1037 | * |
||
1038 | * @link http://tgmpluginactivation.com/ |
||
1039 | * |
||
1040 | * @author Vova Feldman |
||
1041 | * @since 1.2.1.7 |
||
1042 | * |
||
1043 | * @link https://make.wordpress.org/plugins/2017/03/16/clarification-of-guideline-8-executable-code-and-installs/ |
||
1044 | * |
||
1045 | * @uses WP_Filesystem |
||
1046 | * @uses WP_Error |
||
1047 | * @uses WP_Upgrader |
||
1048 | * @uses Plugin_Upgrader |
||
1049 | * @uses Plugin_Installer_Skin |
||
1050 | * @uses Plugin_Upgrader_Skin |
||
1051 | * |
||
1052 | * @param number|bool $plugin_id |
||
1053 | * |
||
1054 | * @return array |
||
1055 | */ |
||
1056 | function install_and_activate_plugin( $plugin_id = false ) { |
||
0 ignored issues
–
show
|
|||
1057 | if ( ! empty( $plugin_id ) && ! FS_Plugin::is_valid_id( $plugin_id ) ) { |
||
1058 | // Invalid plugin ID. |
||
1059 | return array( |
||
1060 | 'message' => $this->_fs->get_text_inline( 'Invalid module ID.', 'auto-install-error-invalid-id' ), |
||
1061 | 'code' => 'invalid_module_id', |
||
1062 | ); |
||
1063 | } |
||
1064 | |||
1065 | $is_addon = false; |
||
1066 | if ( FS_Plugin::is_valid_id( $plugin_id ) && |
||
1067 | $plugin_id != $this->_fs->get_id() |
||
1068 | ) { |
||
1069 | $addon = $this->_fs->get_addon( $plugin_id ); |
||
1070 | |||
1071 | if ( ! is_object( $addon ) ) { |
||
1072 | // Invalid add-on ID. |
||
1073 | return array( |
||
1074 | 'message' => $this->_fs->get_text_inline( 'Invalid module ID.', 'auto-install-error-invalid-id' ), |
||
1075 | 'code' => 'invalid_module_id', |
||
1076 | ); |
||
1077 | } |
||
1078 | |||
1079 | $slug = $addon->slug; |
||
1080 | $premium_slug = $addon->premium_slug; |
||
1081 | $title = $addon->title . ' ' . $this->_fs->get_text_inline( 'Add-On', 'addon' ); |
||
1082 | |||
1083 | $is_addon = true; |
||
1084 | } else { |
||
1085 | $slug = $this->_fs->get_slug(); |
||
1086 | $premium_slug = $this->_fs->get_premium_slug(); |
||
1087 | $title = $this->_fs->get_plugin_title() . |
||
1088 | ( $this->_fs->is_addon() ? ' ' . $this->_fs->get_text_inline( 'Add-On', 'addon' ) : '' ); |
||
1089 | } |
||
1090 | |||
1091 | if ( $this->is_premium_plugin_active( $plugin_id ) ) { |
||
1092 | // Premium version already activated. |
||
1093 | return array( |
||
1094 | 'message' => $is_addon ? |
||
1095 | $this->_fs->get_text_inline( 'Premium add-on version already installed.', 'auto-install-error-premium-addon-activated' ) : |
||
1096 | $this->_fs->get_text_inline( 'Premium version already active.', 'auto-install-error-premium-activated' ), |
||
1097 | 'code' => 'premium_installed', |
||
1098 | ); |
||
1099 | } |
||
1100 | |||
1101 | $latest_version = $this->get_latest_download_details( $plugin_id, false, false ); |
||
1102 | $target_folder = $premium_slug; |
||
1103 | |||
1104 | // Prep variables for Plugin_Installer_Skin class. |
||
1105 | $extra = array(); |
||
1106 | $extra['slug'] = $target_folder; |
||
1107 | $source = $latest_version->url; |
||
1108 | $api = null; |
||
1109 | |||
1110 | $install_url = add_query_arg( |
||
1111 | array( |
||
1112 | 'action' => 'install-plugin', |
||
1113 | 'plugin' => urlencode( $slug ), |
||
1114 | ), |
||
1115 | 'update.php' |
||
1116 | ); |
||
1117 | |||
1118 | if ( ! class_exists( 'Plugin_Upgrader', false ) ) { |
||
1119 | // Include required resources for the installation. |
||
1120 | require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; |
||
1121 | } |
||
1122 | |||
1123 | $skin_args = array( |
||
1124 | 'type' => 'web', |
||
1125 | 'title' => sprintf( $this->_fs->get_text_inline( 'Installing plugin: %s', 'installing-plugin-x' ), $title ), |
||
1126 | 'url' => esc_url_raw( $install_url ), |
||
1127 | 'nonce' => 'install-plugin_' . $slug, |
||
1128 | 'plugin' => '', |
||
1129 | 'api' => $api, |
||
1130 | 'extra' => $extra, |
||
1131 | ); |
||
1132 | |||
1133 | // $skin = new Automatic_Upgrader_Skin( $skin_args ); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
42% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
1134 | // $skin = new Plugin_Installer_Skin( $skin_args ); |
||
1135 | $skin = new WP_Ajax_Upgrader_Skin( $skin_args ); |
||
1136 | |||
1137 | // Create a new instance of Plugin_Upgrader. |
||
1138 | $upgrader = new Plugin_Upgrader( $skin ); |
||
1139 | |||
1140 | // Perform the action and install the plugin from the $source urldecode(). |
||
1141 | add_filter( 'upgrader_source_selection', array( 'FS_Plugin_Updater', '_maybe_adjust_source_dir' ), 1, 3 ); |
||
1142 | |||
1143 | $install_result = $upgrader->install( $source ); |
||
1144 | |||
1145 | remove_filter( 'upgrader_source_selection', array( 'FS_Plugin_Updater', '_maybe_adjust_source_dir' ), 1 ); |
||
1146 | |||
1147 | if ( is_wp_error( $install_result ) ) { |
||
1148 | return array( |
||
1149 | 'message' => $install_result->get_error_message(), |
||
1150 | 'code' => $install_result->get_error_code(), |
||
1151 | ); |
||
1152 | } elseif ( is_wp_error( $skin->result ) ) { |
||
1153 | return array( |
||
1154 | 'message' => $skin->result->get_error_message(), |
||
1155 | 'code' => $skin->result->get_error_code(), |
||
1156 | ); |
||
1157 | } elseif ( $skin->get_errors()->get_error_code() ) { |
||
1158 | return array( |
||
1159 | 'message' => $skin->get_error_messages(), |
||
1160 | 'code' => 'unknown', |
||
1161 | ); |
||
1162 | } elseif ( is_null( $install_result ) ) { |
||
1163 | global $wp_filesystem; |
||
0 ignored issues
–
show
Compatibility
Best Practice
introduced
by
Use of
global functionality is not recommended; it makes your code harder to test, and less reusable.
Instead of relying on 1. Pass all data via parametersfunction myFunction($a, $b) {
// Do something
}
2. Create a class that maintains your stateclass MyClass {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
public function myFunction() {
// Do something
}
}
![]() |
|||
1164 | |||
1165 | $error_code = 'unable_to_connect_to_filesystem'; |
||
1166 | $error_message = $this->_fs->get_text_inline( 'Unable to connect to the filesystem. Please confirm your credentials.' ); |
||
1167 | |||
1168 | // Pass through the error from WP_Filesystem if one was raised. |
||
1169 | if ( $wp_filesystem instanceof WP_Filesystem_Base && |
||
0 ignored issues
–
show
The class
WP_Filesystem_Base 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 dependenciesPHP Analyzer uses your Are you sure this class is defined by one of your dependencies, or did you maybe
not list a dependency in either the 2. Missing use statementPHP does not complain about undefined classes in if ($x instanceof DoesNotExist) {
// Do something.
}
If you have not tested against this specific condition, such errors might go unnoticed. ![]() |
|||
1170 | is_wp_error( $wp_filesystem->errors ) && |
||
1171 | $wp_filesystem->errors->get_error_code() |
||
1172 | ) { |
||
1173 | $error_message = $wp_filesystem->errors->get_error_message(); |
||
1174 | } |
||
1175 | |||
1176 | return array( |
||
1177 | 'message' => $error_message, |
||
1178 | 'code' => $error_code, |
||
1179 | ); |
||
1180 | } |
||
1181 | |||
1182 | // Grab the full path to the main plugin's file. |
||
1183 | $plugin_activate = $upgrader->plugin_info(); |
||
1184 | |||
1185 | // Try to activate the plugin. |
||
1186 | $activation_result = $this->try_activate_plugin( $plugin_activate ); |
||
1187 | |||
1188 | if ( is_wp_error( $activation_result ) ) { |
||
1189 | return array( |
||
1190 | 'message' => $activation_result->get_error_message(), |
||
1191 | 'code' => $activation_result->get_error_code(), |
||
1192 | ); |
||
1193 | } |
||
1194 | |||
1195 | return $skin->get_upgrade_messages(); |
||
1196 | } |
||
1197 | |||
1198 | /** |
||
1199 | * Tries to activate a plugin. If fails, returns the error. |
||
1200 | * |
||
1201 | * @author Vova Feldman |
||
1202 | * @since 1.2.1.7 |
||
1203 | * |
||
1204 | * @param string $file_path Path within wp-plugins/ to main plugin file. |
||
1205 | * This determines the styling of the output messages. |
||
1206 | * |
||
1207 | * @return bool|WP_Error |
||
1208 | */ |
||
1209 | protected function try_activate_plugin( $file_path ) { |
||
1210 | $activate = activate_plugin( $file_path, '', $this->_fs->is_network_active() ); |
||
1211 | |||
1212 | return is_wp_error( $activate ) ? |
||
1213 | $activate : |
||
1214 | true; |
||
1215 | } |
||
1216 | |||
1217 | /** |
||
1218 | * Check if a premium module version is already active. |
||
1219 | * |
||
1220 | * @author Vova Feldman |
||
1221 | * @since 1.2.1.7 |
||
1222 | * |
||
1223 | * @param number|bool $plugin_id |
||
1224 | * |
||
1225 | * @return bool |
||
1226 | */ |
||
1227 | private function is_premium_plugin_active( $plugin_id = false ) { |
||
1228 | if ( $plugin_id != $this->_fs->get_id() ) { |
||
1229 | return $this->_fs->is_addon_activated( $plugin_id, true ); |
||
1230 | } |
||
1231 | |||
1232 | return is_plugin_active( $this->_fs->premium_plugin_basename() ); |
||
1233 | } |
||
1234 | |||
1235 | /** |
||
1236 | * Store the basename since it's not always available in the `_maybe_adjust_source_dir` method below. |
||
1237 | * |
||
1238 | * @author Leo Fajardo (@leorw) |
||
1239 | * @since 2.2.1 |
||
1240 | * |
||
1241 | * @param bool|WP_Error $response Response. |
||
1242 | * @param array $hook_extra Extra arguments passed to hooked filters. |
||
1243 | * |
||
1244 | * @return bool|WP_Error |
||
1245 | */ |
||
1246 | static function _store_basename_for_source_adjustment( $response, $hook_extra ) { |
||
0 ignored issues
–
show
|
|||
1247 | if ( isset( $hook_extra['plugin'] ) ) { |
||
1248 | self::$_upgrade_basename = $hook_extra['plugin']; |
||
1249 | } else if ( isset( $hook_extra['theme'] ) ) { |
||
1250 | self::$_upgrade_basename = $hook_extra['theme']; |
||
1251 | } else { |
||
1252 | self::$_upgrade_basename = null; |
||
1253 | } |
||
1254 | |||
1255 | return $response; |
||
1256 | } |
||
1257 | |||
1258 | /** |
||
1259 | * Adjust the plugin directory name if necessary. |
||
1260 | * Assumes plugin has a folder (not a single file plugin). |
||
1261 | * |
||
1262 | * The final destination directory of a plugin is based on the subdirectory name found in the |
||
1263 | * (un)zipped source. In some cases this subdirectory name is not the same as the expected |
||
1264 | * slug and the plugin will not be recognized as installed. This is fixed by adjusting |
||
1265 | * the temporary unzipped source subdirectory name to the expected plugin slug. |
||
1266 | * |
||
1267 | * @author Vova Feldman |
||
1268 | * @since 1.2.1.7 |
||
1269 | * @since 2.2.1 The method was converted to static since when the admin update bulk products via the Updates section, the logic applies the `upgrader_source_selection` filter for every product that is being updated. |
||
1270 | * |
||
1271 | * @param string $source Path to upgrade/zip-file-name.tmp/subdirectory/. |
||
1272 | * @param string $remote_source Path to upgrade/zip-file-name.tmp. |
||
1273 | * @param \WP_Upgrader $upgrader Instance of the upgrader which installs the plugin. |
||
1274 | * |
||
1275 | * @return string|WP_Error |
||
1276 | */ |
||
1277 | static function _maybe_adjust_source_dir( $source, $remote_source, $upgrader ) { |
||
0 ignored issues
–
show
|
|||
1278 | if ( ! is_object( $GLOBALS['wp_filesystem'] ) ) { |
||
1279 | return $source; |
||
1280 | } |
||
1281 | |||
1282 | $basename = self::$_upgrade_basename; |
||
1283 | $is_theme = false; |
||
1284 | |||
1285 | // Figure out what the slug is supposed to be. |
||
1286 | if ( isset( $upgrader->skin->options['extra'] ) ) { |
||
1287 | // Set by the auto-install logic. |
||
1288 | $desired_slug = $upgrader->skin->options['extra']['slug']; |
||
1289 | } else if ( ! empty( $basename ) ) { |
||
1290 | /** |
||
1291 | * If it doesn't end with ".php", it's a theme. |
||
1292 | * |
||
1293 | * @author Leo Fajardo (@leorw) |
||
1294 | * @since 2.2.1 |
||
1295 | */ |
||
1296 | $is_theme = ( ! fs_ends_with( $basename, '.php' ) ); |
||
1297 | |||
1298 | $desired_slug = ( ! $is_theme ) ? |
||
1299 | dirname( $basename ) : |
||
1300 | // Theme slug |
||
1301 | $basename; |
||
1302 | } else { |
||
1303 | // Can't figure out the desired slug, stop the execution. |
||
1304 | return $source; |
||
1305 | } |
||
1306 | |||
1307 | if ( is_multisite() ) { |
||
0 ignored issues
–
show
This
if statement is empty and can be removed.
This check looks for the bodies of These if (rand(1, 6) > 3) {
//print "Check failed";
} else {
print "Check succeeded";
}
could be turned into if (rand(1, 6) <= 3) {
print "Check succeeded";
}
This is much more concise to read. ![]() |
|||
1308 | /** |
||
1309 | * If we are running in a multisite environment and the product is not network activated, |
||
1310 | * the instance will not exist anyway. Therefore, try to update the source if necessary |
||
1311 | * regardless if the Freemius instance of the product exists or not. |
||
1312 | * |
||
1313 | * @author Vova Feldman |
||
1314 | */ |
||
1315 | } else if ( ! empty( $basename ) ) { |
||
1316 | $fs = Freemius::get_instance_by_file( |
||
1317 | $basename, |
||
1318 | $is_theme ? |
||
1319 | WP_FS__MODULE_TYPE_THEME : |
||
1320 | WP_FS__MODULE_TYPE_PLUGIN |
||
1321 | ); |
||
1322 | |||
1323 | if ( ! is_object( $fs ) ) { |
||
1324 | /** |
||
1325 | * If the Freemius instance does not exist on a non-multisite network environment, it means that: |
||
1326 | * 1. The product is not powered by Freemius; OR |
||
1327 | * 2. The product is not activated, therefore, we don't mind if after the update the folder name will change. |
||
1328 | * |
||
1329 | * @author Leo Fajardo (@leorw) |
||
1330 | * @since 2.2.1 |
||
1331 | */ |
||
1332 | return $source; |
||
1333 | } |
||
1334 | } |
||
1335 | |||
1336 | $subdir_name = untrailingslashit( str_replace( trailingslashit( $remote_source ), '', $source ) ); |
||
1337 | |||
1338 | if ( ! empty( $subdir_name ) && $subdir_name !== $desired_slug ) { |
||
1339 | $from_path = untrailingslashit( $source ); |
||
1340 | $to_path = trailingslashit( $remote_source ) . $desired_slug; |
||
1341 | |||
1342 | if ( true === $GLOBALS['wp_filesystem']->move( $from_path, $to_path ) ) { |
||
1343 | return trailingslashit( $to_path ); |
||
1344 | } |
||
1345 | |||
1346 | return new WP_Error( |
||
1347 | 'rename_failed', |
||
1348 | fs_text_inline( 'The remote plugin package does not contain a folder with the desired slug and renaming did not work.', 'module-package-rename-failure' ), |
||
1349 | array( |
||
1350 | 'found' => $subdir_name, |
||
1351 | 'expected' => $desired_slug |
||
1352 | ) |
||
1353 | ); |
||
1354 | } |
||
1355 | |||
1356 | return $source; |
||
1357 | } |
||
1358 | |||
1359 | #endregion |
||
1360 | } |
||
1361 |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.