PluginProbe
Buttonizer – Floating Menus, Sticky Buttons, & Popup Builder / 3.6.0
Buttonizer – Floating Menus, Sticky Buttons, & Popup Builder v3.6.0
3.6.0 3.5.0 trunk 1.0.10 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.6.1 1.0.7 1.0.8 1.0.9 1.1 1.1.1 1.2 1.3 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.5 1.5.1 All 110 releases
← All changes | freemius/includes/class-fs-plugin-updater.php +852 -91 1.4.53.6.0 View file →
@@ -28,9 +28,18 @@
28 28 * @var object
29 29 * @since 1.1.8.1
30 30 */
31 31 private $_update_details;
32 + /**
33 + * @var array
34 + * @since 2.1.2
35 + */
36 + private $_translation_updates;
32 37
38 + private static $_upgrade_basename = null;
39 +
40 + const UPDATES_CHECK_CACHE_EXPIRATION = ( WP_FS__TIME_24_HOURS_IN_SEC / 24 );
41 +
33 42 #--------------------------------------------------------------------------------
34 43 #region Singleton
35 44 #--------------------------------------------------------------------------------
36 45
@@ -76,26 +85,30 @@
76 85 add_filter( 'plugins_api', array( &$this, 'plugins_api_filter' ), 10, 3 );
77 86
78 87 $this->add_transient_filters();
79 88
80 - if ( ! $this->_fs->has_active_valid_license() ) {
81 - /**
82 - * If user has the premium plugin's code but do NOT have an active license,
83 - * encourage him to upgrade by showing that there's a new release, but instead
84 - * of showing an update link, show upgrade link to the pricing page.
85 - *
86 - * @since 1.1.6
87 - *
88 - */
89 - // WP 2.9+
90 - add_action( "after_plugin_row_{$this->_fs->get_plugin_basename()}", array(
91 - &$this,
92 - 'catch_plugin_update_row'
93 - ), 9 );
94 - add_action( "after_plugin_row_{$this->_fs->get_plugin_basename()}", array(
95 - &$this,
96 - 'edit_and_echo_plugin_update_row'
97 - ), 11, 2 );
89 + /**
90 + * If user has the premium plugin's code but do NOT have an active license,
91 + * encourage him to upgrade by showing that there's a new release, but instead
92 + * of showing an update link, show upgrade link to the pricing page.
93 + *
94 + * @since 1.1.6
95 + *
96 + */
97 + // WP 2.9+
98 + add_action( "after_plugin_row_{$this->_fs->get_plugin_basename()}", array(
99 + &$this,
100 + 'catch_plugin_update_row'
101 + ), 9 );
102 + add_action( "after_plugin_row_{$this->_fs->get_plugin_basename()}", array(
103 + &$this,
104 + 'edit_and_echo_plugin_update_row'
105 + ), 11, 2 );
106 +
107 + if ( ! $this->_fs->has_any_active_valid_license() ) {
108 + add_action( 'admin_head', array( &$this, 'catch_plugin_information_dialog_contents' ) );
109 + } else {
110 + add_action( 'admin_footer', array( &$this, '_add_fs_allow_updater_and_dialog_request_param' ) );
98 111 }
99 112
100 113 if ( ! WP_FS__IS_PRODUCTION_MODE ) {
101 114 add_filter( 'http_request_host_is_external', array(
@@ -103,18 +116,182 @@
103 116 'http_request_host_is_external_filter'
104 117 ), 10, 3 );
105 118 }
106 119
107 - if ( $this->_fs->is_premium() && $this->is_correct_folder_name() ) {
108 - add_filter( 'upgrader_post_install', array( &$this, '_maybe_update_folder_name' ), 10, 3 );
120 + if ( $this->_fs->is_premium() ) {
121 + if ( ! $this->is_correct_folder_name() ) {
122 + add_filter( 'upgrader_post_install', array( &$this, '_maybe_update_folder_name' ), 10, 3 );
123 + }
124 +
125 + add_filter( 'upgrader_pre_install', array( 'FS_Plugin_Updater', '_store_basename_for_source_adjustment' ), 1, 2 );
126 + add_filter( 'upgrader_source_selection', array( 'FS_Plugin_Updater', '_maybe_adjust_source_dir' ), 1, 3 );
127 +
128 + if ( ! $this->_fs->has_any_active_valid_license() ) {
129 + add_filter( 'wp_prepare_themes_for_js', array( &$this, 'change_theme_update_info_html' ), 10, 1 );
130 + }
109 131 }
110 132 }
111 133
112 134 /**
135 + * @author Leo Fajardo (@leorw)
136 + * @since 2.7.4
137 + */
138 + function _add_fs_allow_updater_and_dialog_request_param() {
139 + if ( ! $this->is_plugin_information_dialog_for_plugin() ) {
140 + return;
141 + }
142 + ?>
143 + <script type="text/javascript">
144 + if ( typeof jQuery !== 'undefined' ) {
145 + jQuery( document ).on( 'wp-plugin-updating', function( event, args ) {
146 + if ( typeof args === 'object' && args.slug && typeof args.slug === 'string' ) {
147 + if ( <?php echo json_encode( $this->_fs->get_slug() ) ?> === args.slug ) {
148 + args.fs_allow_updater_and_dialog = true;
149 + }
150 + }
151 + } );
152 + }
153 + </script>
154 + <?php
155 + }
156 +
157 + /**
158 + * @author Leo Fajardo (@leorw)
159 + * @since 2.7.4
160 + *
161 + * @return bool
162 + */
163 + private function is_plugin_information_dialog_for_plugin() {
164 + return (
165 + 'plugin-information' === fs_request_get( 'tab', false ) &&
166 + $this->_fs->get_slug() === fs_request_get_raw( 'plugin', false )
167 + );
168 + }
169 +
170 + /**
171 + * @author Leo Fajardo (@leorw)
172 + * @since 2.1.4
173 + */
174 + function catch_plugin_information_dialog_contents() {
175 + if ( ! $this->is_plugin_information_dialog_for_plugin() ) {
176 + return;
177 + }
178 +
179 + add_action( 'admin_footer', array( &$this, 'edit_and_echo_plugin_information_dialog_contents' ), 0, 1 );
180 +
181 + ob_start();
182 + }
183 +
184 + /**
185 + * @author Leo Fajardo (@leorw)
186 + * @since 2.1.4
187 + *
188 + * @param string $hook_suffix
189 + */
190 + function edit_and_echo_plugin_information_dialog_contents( $hook_suffix ) {
191 + if (
192 + 'plugin-information' !== fs_request_get( 'tab', false ) ||
193 + $this->_fs->get_slug() !== fs_request_get_raw( 'plugin', false )
194 + ) {
195 + return;
196 + }
197 +
198 + $license = $this->_fs->_get_license();
199 +
200 + $subscription = ( is_object( $license ) && ! $license->is_lifetime() ) ?
201 + $this->_fs->_get_subscription( $license->id ) :
202 + null;
203 +
204 + $contents = ob_get_clean();
205 +
206 + $install_or_update_button_id_attribute_pos = strpos( $contents, 'id="plugin_install_from_iframe"' );
207 +
208 + if ( false === $install_or_update_button_id_attribute_pos ) {
209 + $install_or_update_button_id_attribute_pos = strpos( $contents, 'id="plugin_update_from_iframe"' );
210 + }
211 +
212 + if ( false !== $install_or_update_button_id_attribute_pos ) {
213 + $install_or_update_button_start_pos = strrpos(
214 + substr( $contents, 0, $install_or_update_button_id_attribute_pos ),
215 + '<a'
216 + );
217 +
218 + $install_or_update_button_end_pos = ( strpos( $contents, '</a>', $install_or_update_button_id_attribute_pos ) + strlen( '</a>' ) );
219 +
220 + /**
221 + * The part of the contents without the update button.
222 + *
223 + * @author Leo Fajardo (@leorw)
224 + * @since 2.2.5
225 + */
226 + $modified_contents = substr( $contents, 0, $install_or_update_button_start_pos );
227 +
228 + $install_or_update_button = substr( $contents, $install_or_update_button_start_pos, ( $install_or_update_button_end_pos - $install_or_update_button_start_pos ) );
229 +
230 + /**
231 + * Replace the plugin information dialog's "Install Update Now" button's text and URL. If there's a license,
232 + * the text will be "Renew license" and will link to the checkout page with the license's billing cycle
233 + * and quota. If there's no license, the text will be "Buy license" and will link to the pricing page.
234 + */
235 + $install_or_update_button = preg_replace(
236 + '/(\<a.+)(id="plugin_(install|update)_from_iframe")(.+href=")([^\s]+)(".*\>)(.+)(\<\/a>)/is',
237 + is_object( $license ) ?
238 + sprintf(
239 + '$1$4%s$6%s$8',
240 + $this->_fs->checkout_url(
241 + is_object( $subscription ) ?
242 + ( 1 == $subscription->billing_cycle ? WP_FS__PERIOD_MONTHLY : WP_FS__PERIOD_ANNUALLY ) :
243 + WP_FS__PERIOD_LIFETIME,
244 + false,
245 + array( 'licenses' => $license->quota )
246 + ),
247 + fs_text_inline( 'Renew license', 'renew-license', $this->_fs->get_slug() )
248 + ) :
249 + sprintf(
250 + '$1$4%s$6%s$8',
251 + $this->_fs->pricing_url(),
252 + fs_text_inline( 'Buy license', 'buy-license', $this->_fs->get_slug() )
253 + ),
254 + $install_or_update_button
255 + );
256 +
257 + /**
258 + * Append the modified button.
259 + *
260 + * @author Leo Fajardo (@leorw)
261 + * @since 2.2.5
262 + */
263 + $modified_contents .= $install_or_update_button;
264 +
265 + /**
266 + * Append the remaining part of the contents after the update button.
267 + *
268 + * @author Leo Fajardo (@leorw)
269 + * @since 2.2.5
270 + */
271 + $modified_contents .= substr( $contents, $install_or_update_button_end_pos );
272 +
273 + $contents = $modified_contents;
274 + }
275 +
276 + echo $contents;
277 + }
278 +
279 + /**
113 280 * @author Vova Feldman (@svovaf)
114 281 * @since 2.0.0
115 282 */
116 283 private function add_transient_filters() {
284 + if (
285 + $this->_fs->is_premium() &&
286 + $this->_fs->is_registered() &&
287 + ! FS_Permission_Manager::instance( $this->_fs )->is_essentials_tracking_allowed()
288 + ) {
289 + $this->_logger->log( 'Opted out sites cannot receive automatic software updates.' );
290 +
291 + return;
292 + }
293 +
117 294 add_filter( 'pre_set_site_transient_update_plugins', array(
118 295 &$this,
119 296 'pre_set_site_transient_update_plugins_filter'
120 297 ) );
@@ -171,19 +348,133 @@
171 348 }
172 349
173 350 $r = $current->response[ $file ];
174 351
175 - $plugin_update_row = preg_replace(
176 - '/(\<div.+>)(.+)(\<a.+\<a.+)\<\/div\>/is',
177 - '$1 $2 ' . sprintf(
178 - $this->_fs->get_text_inline( '%sRenew your license now%s to access version %s features and support.', 'renew-license-now' ),
179 - '<a href="' . $this->_fs->pricing_url() . '">', '</a>',
180 - $r->new_version ) .
352 + $has_beta_update = $this->_fs->has_beta_update();
353 +
354 + if ( $this->_fs->has_any_active_valid_license() ) {
355 + if ( $has_beta_update ) {
356 + /**
357 + * Turn the "new version" text into "new Beta version".
358 + *
359 + * Sample input:
360 + * There is a new version of Awesome Plugin available. <a href="...>View version x.y.z details</a> or <a href="...>update now</a>.
361 + * Output:
362 + * There is a new Beta version of Awesome Plugin available. <a href="...>View version x.y.z details</a> or <a href="...>update now</a>.
363 + *
364 + * @author Leo Fajardo (@leorw)
365 + * @since 2.3.0
366 + */
367 + $plugin_update_row = preg_replace(
368 + '/(\<div.+>)(.+)(\<a.+href="([^\s]+)"([^\<]+)\>.+\<a.+)(\<\/div\>)/is',
369 + (
370 + '$1' .
371 + sprintf(
372 + fs_text_inline( 'There is a %s of %s available.', 'new-version-available', $this->_fs->get_slug() ),
373 + $has_beta_update ?
374 + fs_text_inline( 'new Beta version', 'new-beta-version', $this->_fs->get_slug() ) :
375 + fs_text_inline( 'new version', 'new-version', $this->_fs->get_slug() ),
376 + $this->_fs->get_plugin_title()
377 + ) .
378 + ' ' .
379 + '$3' .
380 + '$6'
381 + ),
382 + $plugin_update_row
383 + );
384 + }
385 + } else {
386 + /**
387 + * Turn the "new version" text into a link that opens the plugin information dialog when clicked and
388 + * make the "View version x details" text link to the checkout page instead of opening the plugin
389 + * information dialog when clicked.
390 + *
391 + * Sample input:
392 + * There is a new version of Awesome Plugin available. <a href="...>View version x.y.z details</a> or <a href="...>update now</a>.
393 + * Output:
394 + * 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.
395 + * OR
396 + * There is a <a href="...>new Beta version</a> of Awesome Plugin available. <a href="...>Buy a license now</a> to access version x.y.z security & feature updates, and support.
397 + *
398 + * @author Leo Fajardo (@leorw)
399 + */
400 + $plugin_update_row = preg_replace(
401 + '/(\<div.+>)(.+)(\<a.+href="([^\s]+)"([^\<]+)\>.+\<a.+)(\<\/div\>)/is',
402 + (
403 + '$1' .
404 + sprintf(
405 + fs_text_inline( 'There is a %s of %s available.', 'new-version-available', $this->_fs->get_slug() ),
406 + sprintf(
407 + '<a href="$4"%s>%s</a>',
408 + '$5',
409 + $has_beta_update ?
410 + fs_text_inline( 'new Beta version', 'new-beta-version', $this->_fs->get_slug() ) :
411 + fs_text_inline( 'new version', 'new-version', $this->_fs->get_slug() )
412 + ),
413 + $this->_fs->get_plugin_title()
414 + ) .
415 + ' ' .
416 + $this->_fs->version_upgrade_checkout_link( $r->new_version ) .
417 + '$6'
418 + ),
419 + $plugin_update_row
420 + );
421 + }
422 +
423 + if (
424 + $this->_fs->is_plugin() &&
425 + isset( $r->upgrade_notice ) &&
426 + strlen( trim( $r->upgrade_notice ) ) > 0
427 + ) {
428 + $slug = $this->_fs->get_slug();
429 +
430 + $upgrade_notice_html = sprintf(
431 + '<p class="notice fs-upgrade-notice fs-slug-%1$s fs-type-%2$s" data-slug="%1$s" data-type="%2$s"><strong>%3$s</strong> %4$s</p>',
432 + $slug,
433 + $this->_fs->get_module_type(),
434 + fs_text_inline( 'Important Upgrade Notice:', 'upgrade_notice', $slug ),
435 + esc_html( $r->upgrade_notice )
436 + );
437 +
438 + $plugin_update_row = str_replace( '</div>', '</div>' . $upgrade_notice_html, $plugin_update_row );
439 + }
440 +
441 + echo $plugin_update_row;
442 + }
443 +
444 + /**
445 + * @author Leo Fajardo (@leorw)
446 + * @since 2.0.2
447 + *
448 + * @param array $prepared_themes
449 + *
450 + * @return array
451 + */
452 + function change_theme_update_info_html( $prepared_themes ) {
453 + $theme_basename = $this->_fs->get_plugin_basename();
454 +
455 + if ( ! isset( $prepared_themes[ $theme_basename ] ) ) {
456 + return $prepared_themes;
457 + }
458 +
459 + $themes_update = get_site_transient( 'update_themes' );
460 + if ( ! isset( $themes_update->response[ $theme_basename ] ) ||
461 + empty( $themes_update->response[ $theme_basename ]['package'] )
462 + ) {
463 + return $prepared_themes;
464 + }
465 +
466 + $prepared_themes[ $theme_basename ]['update'] = preg_replace(
467 + '/(\<p.+>)(.+)(\<a.+\<a.+)\.(.+\<\/p\>)/is',
468 + '$1 $2 ' . $this->_fs->version_upgrade_checkout_link( $themes_update->response[ $theme_basename ]['new_version'] ) .
181 469 '$4',
182 - $plugin_update_row
470 + $prepared_themes[ $theme_basename ]['update']
183 471 );
184 472
185 - echo $plugin_update_row;
473 + // Set to false to prevent the "Update now" link for the context theme from being shown on the "Themes" page.
474 + $prepared_themes[ $theme_basename ]['hasPackage'] = false;
475 +
476 + return $prepared_themes;
186 477 }
187 478
188 479 /**
189 480 * Since WP version 3.6, a new security feature was added that denies access to repository with a local ip.
@@ -248,19 +539,26 @@
248 539 ) {
249 540 return $transient_data;
250 541 }
251 542
543 + global $wp_current_filter;
544 +
545 + if ( ! empty( $wp_current_filter ) && in_array( 'upgrader_process_complete', $wp_current_filter ) ) {
546 + return $transient_data;
547 + }
548 +
252 549 if ( ! isset( $this->_update_details ) ) {
253 550 // Get plugin's newest update.
254 551 $new_version = $this->_fs->get_update(
255 552 false,
256 553 fs_request_get_bool( 'force-check' ),
257 - WP_FS__TIME_24_HOURS_IN_SEC / 24
554 + FS_Plugin_Updater::UPDATES_CHECK_CACHE_EXPIRATION,
555 + $this->_fs->get_plugin_version()
258 556 );
259 557
260 558 $this->_update_details = false;
261 559
262 - if ( is_object( $new_version ) ) {
560 + if ( is_object( $new_version ) && $this->is_new_version_premium( $new_version ) ) {
263 561 $this->_logger->log( 'Found newer plugin version ' . $new_version->version );
264 562
265 563 /**
266 564 * Cache plugin details locally since set_site_transient( 'update_plugins' )
@@ -272,20 +570,113 @@
272 570 $this->_update_details = $this->get_update_details( $new_version );
273 571 }
274 572 }
275 573
574 + // Alias.
575 + $basename = $this->_fs->premium_plugin_basename();
576 +
276 577 if ( is_object( $this->_update_details ) ) {
578 + if ( isset( $transient_data->no_update ) ) {
579 + unset( $transient_data->no_update[ $basename ] );
580 + }
581 +
582 + if ( ! isset( $transient_data->response ) ) {
583 + $transient_data->response = array();
584 + }
585 +
277 586 // Add plugin to transient data.
278 - $transient_data->response[ $this->_fs->get_plugin_basename() ] = $this->_fs->is_plugin() ?
587 + $transient_data->response[ $basename ] = $this->_fs->is_plugin() ?
279 588 $this->_update_details :
280 589 (array) $this->_update_details;
590 + } else {
591 + if ( isset( $transient_data->response ) ) {
592 + /**
593 + * Ensure that there's no update data for the plugin to prevent upgrading the premium version to the latest free version.
594 + *
595 + * @author Leo Fajardo (@leorw)
596 + * @since 2.3.0
597 + */
598 + unset( $transient_data->response[ $basename ] );
599 + }
600 +
601 + if ( ! isset( $transient_data->no_update ) ) {
602 + $transient_data->no_update = array();
603 + }
604 +
605 + /**
606 + * Add product to no_update transient data to properly integrate with WP 5.5 auto-updates UI.
607 + *
608 + * @since 2.4.1
609 + * @link https://make.wordpress.org/core/2020/07/30/recommended-usage-of-the-updates-api-to-support-the-auto-updates-ui-for-plugins-and-themes-in-wordpress-5-5/
610 + */
611 + $transient_data->no_update[ $basename ] = $this->_fs->is_plugin() ?
612 + (object) array(
613 + 'id' => $basename,
614 + 'slug' => $this->_fs->get_slug(),
615 + 'plugin' => $basename,
616 + 'new_version' => $this->_fs->get_plugin_version(),
617 + 'url' => '',
618 + 'package' => '',
619 + 'icons' => array(),
620 + 'banners' => array(),
621 + 'banners_rtl' => array(),
622 + 'tested' => '',
623 + 'requires_php' => '',
624 + 'compatibility' => new stdClass(),
625 + ) :
626 + array(
627 + 'theme' => $basename,
628 + 'new_version' => $this->_fs->get_plugin_version(),
629 + 'url' => '',
630 + 'package' => '',
631 + 'requires' => '',
632 + 'requires_php' => '',
633 + );
281 634 }
282 635
636 + $slug = $this->_fs->get_slug();
637 +
638 + if ( $this->can_fetch_data_from_wp_org() ) {
639 + if ( ! isset( $this->_translation_updates ) ) {
640 + $this->_translation_updates = array();
641 +
642 + $translation_updates = $this->fetch_wp_org_module_translation_updates( $module_type, $slug );
643 + if ( ! empty( $translation_updates ) ) {
644 + $this->_translation_updates = $translation_updates;
645 + }
646 + }
647 +
648 + if ( ! empty( $this->_translation_updates ) ) {
649 + $all_translation_updates = ( isset( $transient_data->translations ) && is_array( $transient_data->translations ) ) ?
650 + $transient_data->translations :
651 + array();
652 +
653 + $current_plugin_translation_updates_map = array();
654 + foreach ( $all_translation_updates as $key => $translation_update ) {
655 + if ( $module_type === ( $translation_update['type'] . 's' ) && $slug === $translation_update['slug'] ) {
656 + $current_plugin_translation_updates_map[ $translation_update['language'] ] = $translation_update;
657 + unset( $all_translation_updates[ $key ] );
658 + }
659 + }
660 +
661 + foreach ( $this->_translation_updates as $translation_update ) {
662 + $lang = $translation_update['language'];
663 + if ( ! isset( $current_plugin_translation_updates_map[ $lang ] ) ||
664 + version_compare( $translation_update['version'], $current_plugin_translation_updates_map[ $lang ]['version'], '>' )
665 + ) {
666 + $current_plugin_translation_updates_map[ $lang ] = $translation_update;
667 + }
668 + }
669 +
670 + $transient_data->translations = array_merge( $all_translation_updates, array_values( $current_plugin_translation_updates_map ) );
671 + }
672 + }
673 +
283 674 return $transient_data;
284 675 }
285 676
286 677 /**
287 - * Get module's required data for the updates mechanism.
678 + * Get module's required data for the updates' mechanism.
288 679 *
289 680 * @author Vova Feldman (@svovaf)
290 681 * @since 2.0.0
291 682 *
@@ -293,15 +684,16 @@
293 684 *
294 685 * @return object
295 686 */
296 687 function get_update_details( FS_Plugin_Tag $new_version ) {
297 - $update = new stdClass();
298 - $update->slug = $this->_fs->get_slug();
299 - $update->new_version = $new_version->version;
300 - $update->url = WP_FS__ADDRESS;
301 - $update->package = $new_version->url;
302 - $update->tested = $new_version->tested_up_to_version;
303 - $update->requires = $new_version->requires_platform_version;
688 + $update = new stdClass();
689 + $update->slug = $this->_fs->get_slug();
690 + $update->new_version = $new_version->version;
691 + $update->url = WP_FS__ADDRESS;
692 + $update->package = $new_version->url;
693 + $update->tested = self::get_tested_wp_version( $new_version->tested_up_to_version );
694 + $update->requires = $new_version->requires_platform_version;
695 + $update->requires_php = $new_version->requires_programming_language_version;
304 696
305 697 $icon = $this->_fs->get_local_icon_url();
306 698
307 699 if ( ! empty( $icon ) ) {
@@ -311,8 +703,20 @@
311 703 'default' => $icon,
312 704 );
313 705 }
314 706
707 + if ( $this->_fs->is_premium() ) {
708 + $latest_tag = $this->_fs->_fetch_latest_version( $this->_fs->get_id(), false );
709 +
710 + if (
711 + isset( $latest_tag->readme ) &&
712 + isset( $latest_tag->readme->upgrade_notice ) &&
713 + ! empty( $latest_tag->readme->upgrade_notice )
714 + ) {
715 + $update->upgrade_notice = $latest_tag->readme->upgrade_notice;
716 + }
717 + }
718 +
315 719 $update->{$this->_fs->get_module_type()} = $this->_fs->get_plugin_basename();
316 720
317 721 return $update;
318 722 }
@@ -317,8 +721,22 @@
317 721 return $update;
318 722 }
319 723
320 724 /**
725 + * @author Leo Fajardo (@leorw)
726 + * @since 2.3.0
727 + *
728 + * @param FS_Plugin_Tag $new_version
729 + *
730 + * @return bool
731 + */
732 + private function is_new_version_premium( FS_Plugin_Tag $new_version ) {
733 + $params = fs_parse_url_params( $new_version->url );
734 +
735 + return ( isset( $params['is_premium'] ) && 'true' == $params['is_premium'] );
736 + }
737 +
738 + /**
321 739 * Update the updates transient with the module's update information.
322 740 *
323 741 * This method is required for multisite environment.
324 742 * If a module is site activated (not network) and not on the main site,
@@ -334,8 +752,12 @@
334 752 */
335 753 function set_update_data( FS_Plugin_Tag $new_version ) {
336 754 $this->_logger->entrance();
337 755
756 + if ( ! $this->is_new_version_premium( $new_version ) ) {
757 + return;
758 + }
759 +
338 760 $transient_key = "update_{$this->_fs->get_module_type()}s";
339 761
340 762 $transient_data = get_site_transient( $transient_key );
341 763
@@ -392,8 +814,40 @@
392 814 $this->add_transient_filters();
393 815 }
394 816
395 817 /**
818 + * @author Leo Fajardo (@leorw)
819 + * @since 2.0.2
820 + */
821 + function delete_update_data() {
822 + $this->_logger->entrance();
823 +
824 + $transient_key = "update_{$this->_fs->get_module_type()}s";
825 +
826 + $transient_data = get_site_transient( $transient_key );
827 +
828 + // Alias
829 + $basename = $this->_fs->get_plugin_basename();
830 +
831 + if ( ! is_object( $transient_data ) ||
832 + ! isset( $transient_data->response ) ||
833 + ! is_array( $transient_data->response ) ||
834 + empty( $transient_data->response[ $basename ] )
835 + ) {
836 + return;
837 + }
838 +
839 + unset( $transient_data->response[ $basename ] );
840 +
841 + // Remove the added filters.
842 + $this->remove_transient_filters();
843 +
844 + set_site_transient( $transient_key, $transient_data );
845 +
846 + $this->add_transient_filters();
847 + }
848 +
849 + /**
396 850 * Try to fetch plugin's info from .org repository.
397 851 *
398 852 * @author Vova Feldman (@svovaf)
399 853 * @since 1.0.5
@@ -403,37 +857,185 @@
403 857 *
404 858 * @return bool|mixed
405 859 */
406 860 static function _fetch_plugin_info_from_repository( $action, $args ) {
407 - $url = $http_url = 'http://api.wordpress.org/plugins/info/1.0/';
408 - if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) {
861 + $url = $http_url = 'http://api.wordpress.org/plugins/info/1.2/';
862 + $url = add_query_arg(
863 + array(
864 + 'action' => $action,
865 + 'request' => $args,
866 + ),
867 + $url
868 + );
869 +
870 + if ( wp_http_supports( array( 'ssl' ) ) ) {
409 871 $url = set_url_scheme( $url, 'https' );
410 872 }
411 873
412 - $args = array(
874 + // The new endpoint version serves only GET requests.
875 + $request = wp_remote_get( $url, array( 'timeout' => 15 ) );
876 +
877 + if ( is_wp_error( $request ) ) {
878 + return false;
879 + }
880 +
881 + $res = json_decode( wp_remote_retrieve_body( $request ), true );
882 +
883 + if ( is_array( $res ) ) {
884 + // Object casting is required in order to match the info/1.0 format. We are not decoding directly into an object as we need some fields to remain an array (e.g., $res->sections).
885 + $res = (object) $res;
886 + }
887 +
888 + if ( ! is_object( $res ) || isset( $res->error ) ) {
889 + return false;
890 + }
891 +
892 + return $res;
893 + }
894 +
895 + /**
896 + * Returns true if the product can fetch data from WordPress.org.
897 + *
898 + * @author Leo Fajardo (@leorw)
899 + * @since 2.7.4
900 + */
901 + private function can_fetch_data_from_wp_org() {
902 + return ( $this->_fs->is_org_repo_compliant() && $this->_fs->is_freemium() );
903 + }
904 +
905 + /**
906 + * Fetches module translation updates from wordpress.org.
907 + *
908 + * @author Leo Fajardo (@leorw)
909 + * @since 2.1.2
910 + *
911 + * @param string $module_type
912 + * @param string $slug
913 + *
914 + * @return array|null
915 + */
916 + private function fetch_wp_org_module_translation_updates( $module_type, $slug ) {
917 + $plugin_data = $this->_fs->get_plugin_data();
918 +
919 + $locales = array_values( get_available_languages() );
920 + $locales = apply_filters( "{$module_type}_update_check_locales", $locales );
921 + $locales = array_unique( $locales );
922 +
923 + $plugin_basename = $this->_fs->get_plugin_basename();
924 + if ( 'themes' === $module_type ) {
925 + $plugin_basename = $slug;
926 + }
927 +
928 + global $wp_version;
929 +
930 + $request_args = array(
413 931 'timeout' => 15,
414 932 'body' => array(
415 - 'action' => $action,
416 - 'request' => serialize( $args )
417 - )
933 + "{$module_type}" => json_encode(
934 + array(
935 + "{$module_type}" => array(
936 + $plugin_basename => array(
937 + 'Name' => trim( str_replace( $this->_fs->get_plugin()->premium_suffix, '', $plugin_data['Name'] ) ),
938 + 'Author' => $plugin_data['Author'],
939 + )
940 + )
941 + )
942 + ),
943 + 'translations' => json_encode( $this->get_installed_translations( $module_type, $slug ) ),
944 + 'locale' => json_encode( $locales )
945 + ),
946 + 'user-agent' => ( 'WordPress/' . $wp_version . '; ' . home_url( '/' ) )
418 947 );
419 948
420 - $request = wp_remote_post( $url, $args );
949 + $url = "http://api.wordpress.org/{$module_type}/update-check/1.1/";
950 + if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) {
951 + $url = set_url_scheme( $url, 'https' );
952 + }
421 953
422 - if ( is_wp_error( $request ) ) {
423 - return false;
954 + $raw_response = Freemius::safe_remote_post(
955 + $url,
956 + $request_args,
957 + WP_FS__TIME_24_HOURS_IN_SEC,
958 + WP_FS__TIME_12_HOURS_IN_SEC,
959 + false
960 + );
961 +
962 + if ( is_wp_error( $raw_response ) ) {
963 + return null;
424 964 }
425 965
426 - $res = maybe_unserialize( wp_remote_retrieve_body( $request ) );
966 + $response = json_decode( wp_remote_retrieve_body( $raw_response ), true );
427 967
428 - if ( ! is_object( $res ) && ! is_array( $res ) ) {
429 - return false;
968 + if ( ! is_array( $response ) ) {
969 + return null;
430 970 }
431 971
432 - return $res;
972 + if ( ! isset( $response['translations'] ) || empty( $response['translations'] ) ) {
973 + return null;
974 + }
975 +
976 + return $response['translations'];
433 977 }
434 978
435 979 /**
980 + * @author Leo Fajardo (@leorw)
981 + * @since 2.1.2
982 + *
983 + * @param string $module_type
984 + * @param string $slug
985 + *
986 + * @return array
987 + */
988 + private function get_installed_translations( $module_type, $slug ) {
989 + if ( function_exists( 'wp_get_installed_translations' ) ) {
990 + return wp_get_installed_translations( $module_type );
991 + }
992 +
993 + $dir = "/{$module_type}";
994 +
995 + if ( ! is_dir( WP_LANG_DIR . $dir ) )
996 + return array();
997 +
998 + $files = scandir( WP_LANG_DIR . $dir );
999 + if ( ! $files )
1000 + return array();
1001 +
1002 + $language_data = array();
1003 +
1004 + foreach ( $files as $file ) {
1005 + if ( 0 !== strpos( $file, $slug ) ) {
1006 + continue;
1007 + }
1008 +
1009 + if ( '.' === $file[0] || is_dir( WP_LANG_DIR . "{$dir}/{$file}" ) ) {
1010 + continue;
1011 + }
1012 +
1013 + if ( substr( $file, -3 ) !== '.po' ) {
1014 + continue;
1015 + }
1016 +
1017 + if ( ! preg_match( '/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z0-9]+)?).po/', $file, $match ) ) {
1018 + continue;
1019 + }
1020 +
1021 + if ( ! in_array( substr( $file, 0, -3 ) . '.mo', $files ) ) {
1022 + continue;
1023 + }
1024 +
1025 + list( , $textdomain, $language ) = $match;
1026 +
1027 + if ( '' === $textdomain ) {
1028 + $textdomain = 'default';
1029 + }
1030 +
1031 + $language_data[ $textdomain ][ $language ] = wp_get_pomo_file_data( WP_LANG_DIR . "{$dir}/{$file}" );
1032 + }
1033 +
1034 + return $language_data;
1035 + }
1036 +
1037 + /**
436 1038 * Updates information on the "View version x.x details" page with custom data.
437 1039 *
438 1040 * @author Vova Feldman (@svovaf)
439 1041 * @since 1.0.4
@@ -454,10 +1056,11 @@
454 1056 ) {
455 1057 return $data;
456 1058 }
457 1059
458 - $addon = false;
459 - $is_addon = false;
1060 + $addon = false;
1061 + $is_addon = false;
1062 + $addon_version = false;
460 1063
461 1064 if ( $this->_fs->get_slug() !== $args->slug ) {
462 1065 $addon = $this->_fs->get_addon_by_slug( $args->slug );
463 1066
@@ -464,13 +1067,27 @@
464 1067 if ( ! is_object( $addon ) ) {
465 1068 return $data;
466 1069 }
467 1070
1071 + if ( $this->_fs->is_addon_activated( $addon->id ) ) {
1072 + $addon_version = $this->_fs->get_addon_instance( $addon->id )->get_plugin_version();
1073 + } else if ( $this->_fs->is_addon_installed( $addon->id ) ) {
1074 + $addon_plugin_data = get_plugin_data(
1075 + ( WP_PLUGIN_DIR . '/' . $this->_fs->get_addon_basename( $addon->id ) ),
1076 + false,
1077 + false
1078 + );
1079 +
1080 + if ( ! empty( $addon_plugin_data ) ) {
1081 + $addon_version = $addon_plugin_data['Version'];
1082 + }
1083 + }
1084 +
468 1085 $is_addon = true;
469 1086 }
470 1087
471 1088 $plugin_in_repo = false;
472 - if ( ! $is_addon ) {
1089 + if ( ! $is_addon && $this->can_fetch_data_from_wp_org() ) {
473 1090 // Try to fetch info from .org repository.
474 1091 $data = self::_fetch_plugin_info_from_repository( $action, $args );
475 1092
476 1093 $plugin_in_repo = ( false !== $data );
@@ -494,13 +1111,17 @@
494 1111 $data = $info;
495 1112 }*/
496 1113 }
497 1114
1115 + $plugin_version = $is_addon ?
1116 + $addon_version :
1117 + $this->_fs->get_plugin_version();
1118 +
498 1119 // Get plugin's newest update.
499 - $new_version = $this->get_latest_download_details( $is_addon ? $addon->id : false );
1120 + $new_version = $this->get_latest_download_details( $is_addon ? $addon->id : false, $plugin_version );
500 1121
501 1122 if ( ! is_object( $new_version ) || empty( $new_version->version ) ) {
502 - $data->version = $this->_fs->get_plugin_version();
1123 + $data->version = $plugin_version;
503 1124 } else {
504 1125 if ( $is_addon ) {
505 1126 $data->name = $addon->title . ' ' . $this->_fs->get_text_inline( 'Add-On', 'addon' );
506 1127 $data->slug = $addon->slug;
@@ -510,28 +1131,96 @@
510 1131
511 1132 if ( ! $plugin_in_repo ) {
512 1133 $data->last_updated = ! is_null( $new_version->updated ) ? $new_version->updated : $new_version->created;
513 1134 $data->requires = $new_version->requires_platform_version;
1135 + $data->requires_php = $new_version->requires_programming_language_version;
514 1136 $data->tested = $new_version->tested_up_to_version;
515 1137 }
516 1138
517 1139 $data->version = $new_version->version;
518 1140 $data->download_link = $new_version->url;
1141 +
1142 + if ( isset( $new_version->readme ) && is_object( $new_version->readme ) ) {
1143 + $new_version_readme_data = $new_version->readme;
1144 + if ( isset( $new_version_readme_data->sections ) ) {
1145 + $new_version_readme_data->sections = (array) $new_version_readme_data->sections;
1146 + } else {
1147 + $new_version_readme_data->sections = array();
1148 + }
1149 +
1150 + if ( isset( $data->sections ) ) {
1151 + if ( isset( $data->sections['screenshots'] ) ) {
1152 + $new_version_readme_data->sections['screenshots'] = $data->sections['screenshots'];
1153 + }
1154 +
1155 + if ( isset( $data->sections['reviews'] ) ) {
1156 + $new_version_readme_data->sections['reviews'] = $data->sections['reviews'];
1157 + }
1158 + }
1159 +
1160 + if ( isset( $new_version_readme_data->banners ) ) {
1161 + $new_version_readme_data->banners = (array) $new_version_readme_data->banners;
1162 + } else if ( isset( $data->banners ) ) {
1163 + $new_version_readme_data->banners = $data->banners;
1164 + }
1165 +
1166 + $wp_org_sections = array(
1167 + 'author',
1168 + 'author_profile',
1169 + 'rating',
1170 + 'ratings',
1171 + 'num_ratings',
1172 + 'support_threads',
1173 + 'support_threads_resolved',
1174 + 'active_installs',
1175 + 'added',
1176 + 'homepage'
1177 + );
1178 +
1179 + foreach ( $wp_org_sections as $wp_org_section ) {
1180 + if ( isset( $data->{$wp_org_section} ) ) {
1181 + $new_version_readme_data->{$wp_org_section} = $data->{$wp_org_section};
1182 + }
1183 + }
1184 +
1185 + $data = $new_version_readme_data;
1186 + }
519 1187 }
520 1188
1189 + if ( ! empty( $data->tested ) ) {
1190 + $data->tested = self::get_tested_wp_version( $data->tested );
1191 + }
1192 +
521 1193 return $data;
522 1194 }
523 1195
524 1196 /**
1197 + * @since 2.5.3 If the current WordPress version is a patch of the tested version (e.g., 6.1.2 is a patch of 6.1), then override the tested version with the patch so developers won't need to release a new version just to bump the latest supported WP version.
1198 + *
1199 + * @param string|null $tested_up_to
1200 + *
1201 + * @return string|null
1202 + */
1203 + private static function get_tested_wp_version( $tested_up_to ) {
1204 + $current_wp_version = get_bloginfo( 'version' );
1205 +
1206 + return ( ! empty($tested_up_to) && fs_starts_with( $current_wp_version, $tested_up_to . '.' ) ) ?
1207 + $current_wp_version :
1208 + $tested_up_to;
1209 + }
1210 +
1211 + /**
525 1212 * @author Vova Feldman (@svovaf)
526 1213 * @since 1.2.1.7
527 1214 *
528 1215 * @param number|bool $addon_id
1216 + * @param bool|string $newer_than Since 2.2.1
1217 + * @param bool|string $fetch_readme Since 2.2.1
529 1218 *
530 1219 * @return object
531 1220 */
532 - private function get_latest_download_details( $addon_id = false ) {
533 - return $this->_fs->_fetch_latest_version( $addon_id );
1221 + private function get_latest_download_details( $addon_id = false, $newer_than = false, $fetch_readme = true ) {
1222 + return $this->_fs->_fetch_latest_version( $addon_id, true, FS_Plugin_Updater::UPDATES_CHECK_CACHE_EXPIRATION, $newer_than, $fetch_readme );
534 1223 }
535 1224
536 1225 /**
537 1226 * Checks if a given basename has a matching folder name
@@ -539,18 +1228,12 @@
539 1228 *
540 1229 * @author Vova Feldman (@svovaf)
541 1230 * @since 1.2.1.6
542 1231 *
543 - * @param string $basename Current plugin's basename.
544 - *
545 1232 * @return bool
546 1233 */
547 - private function is_correct_folder_name( $basename = '' ) {
548 - if ( empty( $basename ) ) {
549 - $basename = $this->_fs->get_plugin_basename();
550 - }
551 -
552 - return ( $this->_fs->get_target_folder_name() != trim( dirname( $basename ), '/\\' ) );
1234 + private function is_correct_folder_name() {
1235 + return ( $this->_fs->get_target_folder_name() == trim( dirname( $this->_fs->get_plugin_basename() ), '/\\' ) );
553 1236 }
554 1237
555 1238 /**
556 1239 * This is a special after upgrade handler for migrating modules
@@ -578,15 +1261,15 @@
578 1261 }
579 1262
580 1263 $active_plugins_basenames = get_option( 'active_plugins' );
581 1264
582 - for ( $i = 0, $len = count( $active_plugins_basenames ); $i < $len; $i ++ ) {
583 - if ( $basename === $active_plugins_basenames[ $i ] ) {
1265 + foreach ( $active_plugins_basenames as $key => $active_plugin_basename ) {
1266 + if ( $basename === $active_plugin_basename ) {
584 1267 // Get filename including extension.
585 1268 $filename = basename( $basename );
586 1269
587 1270 $new_basename = plugin_basename(
588 - trailingslashit( $this->_fs->get_slug() . ( $this->_fs->is_premium() ? '-premium' : '' ) ) .
1271 + trailingslashit( $this->_fs->is_premium() ? $this->_fs->get_premium_slug() : $this->_fs->get_slug() ) .
589 1272 $filename
590 1273 );
591 1274
592 1275 // Verify that the expected correct path exists.
@@ -591,9 +1274,9 @@
591 1274
592 1275 // Verify that the expected correct path exists.
593 1276 if ( file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $new_basename ) ) ) {
594 1277 // Override active plugin name.
595 - $active_plugins_basenames[ $i ] = $new_basename;
1278 + $active_plugins_basenames[ $key ] = $new_basename;
596 1279 update_option( 'active_plugins', $active_plugins_basenames );
597 1280 }
598 1281
599 1282 break;
@@ -652,16 +1335,18 @@
652 1335 'code' => 'invalid_module_id',
653 1336 );
654 1337 }
655 1338
656 - $slug = $addon->slug;
657 - $title = $addon->title . ' ' . $this->_fs->get_text_inline( 'Add-On', 'addon' );
1339 + $slug = $addon->slug;
1340 + $premium_slug = $addon->premium_slug;
1341 + $title = $addon->title . ' ' . $this->_fs->get_text_inline( 'Add-On', 'addon' );
658 1342
659 1343 $is_addon = true;
660 1344 } else {
661 - $slug = $this->_fs->get_slug();
662 - $title = $this->_fs->get_plugin_title() .
663 - ( $this->_fs->is_addon() ? ' ' . $this->_fs->get_text_inline( 'Add-On', 'addon' ) : '' );
1345 + $slug = $this->_fs->get_slug();
1346 + $premium_slug = $this->_fs->get_premium_slug();
1347 + $title = $this->_fs->get_plugin_title() .
1348 + ( $this->_fs->is_addon() ? ' ' . $this->_fs->get_text_inline( 'Add-On', 'addon' ) : '' );
664 1349 }
665 1350
666 1351 if ( $this->is_premium_plugin_active( $plugin_id ) ) {
667 1352 // Premium version already activated.
@@ -672,10 +1357,10 @@
672 1357 'code' => 'premium_installed',
673 1358 );
674 1359 }
675 1360
676 - $latest_version = $this->get_latest_download_details( $plugin_id );
677 - $target_folder = "{$slug}-premium";
1361 + $latest_version = $this->get_latest_download_details( $plugin_id, false, false );
1362 + $target_folder = $premium_slug;
678 1363
679 1364 // Prep variables for Plugin_Installer_Skin class.
680 1365 $extra = array();
681 1366 $extra['slug'] = $target_folder;
@@ -712,13 +1397,13 @@
712 1397 // Create a new instance of Plugin_Upgrader.
713 1398 $upgrader = new Plugin_Upgrader( $skin );
714 1399
715 1400 // Perform the action and install the plugin from the $source urldecode().
716 - add_filter( 'upgrader_source_selection', array( &$this, '_maybe_adjust_source_dir' ), 1, 3 );
1401 + add_filter( 'upgrader_source_selection', array( 'FS_Plugin_Updater', '_maybe_adjust_source_dir' ), 1, 3 );
717 1402
718 1403 $install_result = $upgrader->install( $source );
719 1404
720 - remove_filter( 'upgrader_source_selection', array( &$this, '_maybe_adjust_source_dir' ), 1 );
1405 + remove_filter( 'upgrader_source_selection', array( 'FS_Plugin_Updater', '_maybe_adjust_source_dir' ), 1 );
721 1406
722 1407 if ( is_wp_error( $install_result ) ) {
723 1408 return array(
724 1409 'message' => $install_result->get_error_message(),
@@ -807,8 +1492,31 @@
807 1492 return is_plugin_active( $this->_fs->premium_plugin_basename() );
808 1493 }
809 1494
810 1495 /**
1496 + * Store the basename since it's not always available in the `_maybe_adjust_source_dir` method below.
1497 + *
1498 + * @author Leo Fajardo (@leorw)
1499 + * @since 2.2.1
1500 + *
1501 + * @param bool|WP_Error $response Response.
1502 + * @param array $hook_extra Extra arguments passed to hooked filters.
1503 + *
1504 + * @return bool|WP_Error
1505 + */
1506 + static function _store_basename_for_source_adjustment( $response, $hook_extra ) {
1507 + if ( isset( $hook_extra['plugin'] ) ) {
1508 + self::$_upgrade_basename = $hook_extra['plugin'];
1509 + } else if ( isset( $hook_extra['theme'] ) ) {
1510 + self::$_upgrade_basename = $hook_extra['theme'];
1511 + } else {
1512 + self::$_upgrade_basename = null;
1513 + }
1514 +
1515 + return $response;
1516 + }
1517 +
1518 + /**
811 1519 * Adjust the plugin directory name if necessary.
812 1520 * Assumes plugin has a folder (not a single file plugin).
813 1521 *
814 1522 * The final destination directory of a plugin is based on the subdirectory name found in the
@@ -817,8 +1525,9 @@
817 1525 * the temporary unzipped source subdirectory name to the expected plugin slug.
818 1526 *
819 1527 * @author Vova Feldman
820 1528 * @since 1.2.1.7
1529 + * @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.
821 1530 *
822 1531 * @param string $source Path to upgrade/zip-file-name.tmp/subdirectory/.
823 1532 * @param string $remote_source Path to upgrade/zip-file-name.tmp.
824 1533 * @param \WP_Upgrader $upgrader Instance of the upgrader which installs the plugin.
@@ -824,16 +1533,67 @@
824 1533 * @param \WP_Upgrader $upgrader Instance of the upgrader which installs the plugin.
825 1534 *
826 1535 * @return string|WP_Error
827 1536 */
828 - function _maybe_adjust_source_dir( $source, $remote_source, $upgrader ) {
1537 + static function _maybe_adjust_source_dir( $source, $remote_source, $upgrader ) {
829 1538 if ( ! is_object( $GLOBALS['wp_filesystem'] ) ) {
830 1539 return $source;
831 1540 }
832 1541
1542 + $basename = self::$_upgrade_basename;
1543 + $is_theme = false;
1544 +
833 1545 // Figure out what the slug is supposed to be.
834 - $desired_slug = $upgrader->skin->options['extra']['slug'];
1546 + if ( isset( $upgrader->skin->options['extra'] ) ) {
1547 + // Set by the auto-install logic.
1548 + $desired_slug = $upgrader->skin->options['extra']['slug'];
1549 + } else if ( ! empty( $basename ) ) {
1550 + /**
1551 + * If it doesn't end with ".php", it's a theme.
1552 + *
1553 + * @author Leo Fajardo (@leorw)
1554 + * @since 2.2.1
1555 + */
1556 + $is_theme = ( ! fs_ends_with( $basename, '.php' ) );
835 1557
1558 + $desired_slug = ( ! $is_theme ) ?
1559 + dirname( $basename ) :
1560 + // Theme slug
1561 + $basename;
1562 + } else {
1563 + // Can't figure out the desired slug, stop the execution.
1564 + return $source;
1565 + }
1566 +
1567 + if ( is_multisite() ) {
1568 + /**
1569 + * If we are running in a multisite environment and the product is not network activated,
1570 + * the instance will not exist anyway. Therefore, try to update the source if necessary
1571 + * regardless if the Freemius instance of the product exists or not.
1572 + *
1573 + * @author Vova Feldman
1574 + */
1575 + } else if ( ! empty( $basename ) ) {
1576 + $fs = Freemius::get_instance_by_file(
1577 + $basename,
1578 + $is_theme ?
1579 + WP_FS__MODULE_TYPE_THEME :
1580 + WP_FS__MODULE_TYPE_PLUGIN
1581 + );
1582 +
1583 + if ( ! is_object( $fs ) ) {
1584 + /**
1585 + * If the Freemius instance does not exist on a non-multisite network environment, it means that:
1586 + * 1. The product is not powered by Freemius; OR
1587 + * 2. The product is not activated, therefore, we don't mind if after the update the folder name will change.
1588 + *
1589 + * @author Leo Fajardo (@leorw)
1590 + * @since 2.2.1
1591 + */
1592 + return $source;
1593 + }
1594 + }
1595 +
836 1596 $subdir_name = untrailingslashit( str_replace( trailingslashit( $remote_source ), '', $source ) );
837 1597
838 1598 if ( ! empty( $subdir_name ) && $subdir_name !== $desired_slug ) {
839 1599 $from_path = untrailingslashit( $source );
@@ -840,17 +1600,18 @@
840 1600 $to_path = trailingslashit( $remote_source ) . $desired_slug;
841 1601
842 1602 if ( true === $GLOBALS['wp_filesystem']->move( $from_path, $to_path ) ) {
843 1603 return trailingslashit( $to_path );
844 - } else {
845 - return new WP_Error(
846 - 'rename_failed',
847 - $this->_fs->get_text_inline( 'The remote plugin package does not contain a folder with the desired slug and renaming did not work.', 'module-package-rename-failure' ),
848 - array(
849 - 'found' => $subdir_name,
850 - 'expected' => $desired_slug
851 - ) );
852 1604 }
1605 +
1606 + return new WP_Error(
1607 + 'rename_failed',
1608 + 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' ),
1609 + array(
1610 + 'found' => $subdir_name,
1611 + 'expected' => $desired_slug
1612 + )
1613 + );
853 1614 }
854 1615
855 1616 return $source;
856 1617 }
@@ -855,5 +1616,5 @@
855 1616 return $source;
856 1617 }
857 1618
858 1619 #endregion
859 - }
1620 + }