PluginProbe
Buttonizer – Floating Menus, Sticky Buttons, & Popup Builder / 1.5
Buttonizer – Floating Menus, Sticky Buttons, & Popup Builder v1.5
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
buttonizer-multifunctional-button / freemius / includes / class-fs-plugin-updater.php

class-fs-plugin-updater.php in Buttonizer – Floating Menus, Sticky Buttons, & Popup Builder 1.5, at freemius/includes/class-fs-plugin-updater.php

859 lines 31.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
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 {
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 #--------------------------------------------------------------------------------
34 #region Singleton
35 #--------------------------------------------------------------------------------
36
37 /**
38 * @var FS_Plugin_Updater[]
39 * @since 2.0.0
40 */
41 private static $_INSTANCES = array();
42
43 /**
44 * @param Freemius $freemius
45 *
46 * @return FS_Plugin_Updater
47 */
48 static function instance( Freemius $freemius ) {
49 $key = $freemius->get_id();
50
51 if ( ! isset( self::$_INSTANCES[ $key ] ) ) {
52 self::$_INSTANCES[ $key ] = new self( $freemius );
53 }
54
55 return self::$_INSTANCES[ $key ];
56 }
57
58 #endregion
59
60 private function __construct( Freemius $freemius ) {
61 $this->_fs = $freemius;
62
63 $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $freemius->get_slug() . '_updater', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
64
65 $this->filters();
66 }
67
68 /**
69 * Initiate required filters.
70 *
71 * @author Vova Feldman (@svovaf)
72 * @since 1.0.4
73 */
74 private function filters() {
75 // Override request for plugin information
76 add_filter( 'plugins_api', array( &$this, 'plugins_api_filter' ), 10, 3 );
77
78 $this->add_transient_filters();
79
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 );
98 }
99
100 if ( ! WP_FS__IS_PRODUCTION_MODE ) {
101 add_filter( 'http_request_host_is_external', array(
102 $this,
103 'http_request_host_is_external_filter'
104 ), 10, 3 );
105 }
106
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 );
109 }
110 }
111
112 /**
113 * @author Vova Feldman (@svovaf)
114 * @since 2.0.0
115 */
116 private function add_transient_filters() {
117 add_filter( 'pre_set_site_transient_update_plugins', array(
118 &$this,
119 'pre_set_site_transient_update_plugins_filter'
120 ) );
121
122 add_filter( 'pre_set_site_transient_update_themes', array(
123 &$this,
124 'pre_set_site_transient_update_plugins_filter'
125 ) );
126 }
127
128 /**
129 * @author Vova Feldman (@svovaf)
130 * @since 2.0.0
131 */
132 private function remove_transient_filters() {
133 remove_filter( 'pre_set_site_transient_update_plugins', array(
134 &$this,
135 'pre_set_site_transient_update_plugins_filter'
136 ) );
137
138 remove_filter( 'pre_set_site_transient_update_themes', array(
139 &$this,
140 'pre_set_site_transient_update_plugins_filter'
141 ) );
142 }
143
144 /**
145 * Capture plugin update row by turning output buffering.
146 *
147 * @author Vova Feldman (@svovaf)
148 * @since 1.1.6
149 */
150 function catch_plugin_update_row() {
151 ob_start();
152 }
153
154 /**
155 * Overrides default update message format with "renew your license" message.
156 *
157 * @author Vova Feldman (@svovaf)
158 * @since 1.1.6
159 *
160 * @param string $file
161 * @param array $plugin_data
162 */
163 function edit_and_echo_plugin_update_row( $file, $plugin_data ) {
164 $plugin_update_row = ob_get_clean();
165
166 $current = get_site_transient( 'update_plugins' );
167 if ( ! isset( $current->response[ $file ] ) ) {
168 echo $plugin_update_row;
169
170 return;
171 }
172
173 $r = $current->response[ $file ];
174
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 ) .
181 '$4',
182 $plugin_update_row
183 );
184
185 echo $plugin_update_row;
186 }
187
188 /**
189 * Since WP version 3.6, a new security feature was added that denies access to repository with a local ip.
190 * During development mode we want to be able updating plugin versions via our localhost repository. This
191 * filter white-list all domains including "api.freemius".
192 *
193 * @link http://www.emanueletessore.com/wordpress-download-failed-valid-url-provided/
194 *
195 * @author Vova Feldman (@svovaf)
196 * @since 1.0.4
197 *
198 * @param bool $allow
199 * @param string $host
200 * @param string $url
201 *
202 * @return bool
203 */
204 function http_request_host_is_external_filter( $allow, $host, $url ) {
205 return ( false !== strpos( $host, 'freemius' ) ) ? true : $allow;
206 }
207
208 /**
209 * Check for Updates at the defined API endpoint and modify the update array.
210 *
211 * This function dives into the update api just when WordPress creates its update array,
212 * then adds a custom API call and injects the custom plugin data retrieved from the API.
213 * It is reassembled from parts of the native WordPress plugin update code.
214 * See wp-includes/update.php line 121 for the original wp_update_plugins() function.
215 *
216 * @author Vova Feldman (@svovaf)
217 * @since 1.0.4
218 *
219 * @uses FS_Api
220 *
221 * @param object $transient_data Update array build by WordPress.
222 *
223 * @return object Modified update array with custom plugin data.
224 */
225 function pre_set_site_transient_update_plugins_filter( $transient_data ) {
226 $this->_logger->entrance();
227
228 /**
229 * "plugins" or "themes".
230 *
231 * @author Leo Fajardo (@leorw)
232 * @since 1.2.2
233 */
234 $module_type = $this->_fs->get_module_type() . 's';
235
236 /**
237 * Ensure that we don't mix plugins update info with themes update info.
238 *
239 * @author Leo Fajardo (@leorw)
240 * @since 1.2.2
241 */
242 if ( "pre_set_site_transient_update_{$module_type}" !== current_filter() ) {
243 return $transient_data;
244 }
245
246 if ( empty( $transient_data ) ||
247 defined( 'WP_FS__UNINSTALL_MODE' )
248 ) {
249 return $transient_data;
250 }
251
252 if ( ! isset( $this->_update_details ) ) {
253 // Get plugin's newest update.
254 $new_version = $this->_fs->get_update(
255 false,
256 fs_request_get_bool( 'force-check' ),
257 WP_FS__TIME_24_HOURS_IN_SEC / 24
258 );
259
260 $this->_update_details = false;
261
262 if ( is_object( $new_version ) ) {
263 $this->_logger->log( 'Found newer plugin version ' . $new_version->version );
264
265 /**
266 * Cache plugin details locally since set_site_transient( 'update_plugins' )
267 * called multiple times and the non wp.org plugins are filtered after the
268 * call to .org.
269 *
270 * @since 1.1.8.1
271 */
272 $this->_update_details = $this->get_update_details( $new_version );
273 }
274 }
275
276 if ( is_object( $this->_update_details ) ) {
277 // Add plugin to transient data.
278 $transient_data->response[ $this->_fs->get_plugin_basename() ] = $this->_fs->is_plugin() ?
279 $this->_update_details :
280 (array) $this->_update_details;
281 }
282
283 return $transient_data;
284 }
285
286 /**
287 * Get module's required data for the updates mechanism.
288 *
289 * @author Vova Feldman (@svovaf)
290 * @since 2.0.0
291 *
292 * @param \FS_Plugin_Tag $new_version
293 *
294 * @return object
295 */
296 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;
304
305 $icon = $this->_fs->get_local_icon_url();
306
307 if ( ! empty( $icon ) ) {
308 $update->icons = array(
309 // '1x' => $icon,
310 // '2x' => $icon,
311 'default' => $icon,
312 );
313 }
314
315 $update->{$this->_fs->get_module_type()} = $this->_fs->get_plugin_basename();
316
317 return $update;
318 }
319
320 /**
321 * Update the updates transient with the module's update information.
322 *
323 * This method is required for multisite environment.
324 * If a module is site activated (not network) and not on the main site,
325 * the module will NOT be executed on the network level, therefore, the
326 * custom updates logic will not be executed as well, so unless we force
327 * the injection of the update into the updates transient, premium updates
328 * will not work.
329 *
330 * @author Vova Feldman (@svovaf)
331 * @since 2.0.0
332 *
333 * @param \FS_Plugin_Tag $new_version
334 */
335 function set_update_data( FS_Plugin_Tag $new_version ) {
336 $this->_logger->entrance();
337
338 $transient_key = "update_{$this->_fs->get_module_type()}s";
339
340 $transient_data = get_site_transient( $transient_key );
341
342 $transient_data = is_object( $transient_data ) ?
343 $transient_data :
344 new stdClass();
345
346 // Alias.
347 $basename = $this->_fs->get_plugin_basename();
348 $is_plugin = $this->_fs->is_plugin();
349
350 if ( ! isset( $transient_data->response ) ||
351 ! is_array( $transient_data->response )
352 ) {
353 $transient_data->response = array();
354 } else if ( ! empty( $transient_data->response[ $basename ] ) ) {
355 $version = $is_plugin ?
356 ( ! empty( $transient_data->response[ $basename ]->new_version ) ?
357 $transient_data->response[ $basename ]->new_version :
358 null
359 ) : ( ! empty( $transient_data->response[ $basename ]['new_version'] ) ?
360 $transient_data->response[ $basename ]['new_version'] :
361 null
362 );
363
364 if ( $version == $new_version->version ) {
365 // The update data is already set.
366 return;
367 }
368 }
369
370 // Remove the added filters.
371 $this->remove_transient_filters();
372
373 $this->_update_details = $this->get_update_details( $new_version );
374
375 // Set update data in transient.
376 $transient_data->response[ $basename ] = $is_plugin ?
377 $this->_update_details :
378 (array) $this->_update_details;
379
380 if ( ! isset( $transient_data->checked ) ||
381 ! is_array( $transient_data->checked )
382 ) {
383 $transient_data->checked = array();
384 }
385
386 // Flag the module as if it was already checked.
387 $transient_data->checked[ $basename ] = $this->_fs->get_plugin_version();
388 $transient_data->last_checked = time();
389
390 set_site_transient( $transient_key, $transient_data );
391
392 $this->add_transient_filters();
393 }
394
395 /**
396 * Try to fetch plugin's info from .org repository.
397 *
398 * @author Vova Feldman (@svovaf)
399 * @since 1.0.5
400 *
401 * @param string $action
402 * @param object $args
403 *
404 * @return bool|mixed
405 */
406 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' ) ) ) {
409 $url = set_url_scheme( $url, 'https' );
410 }
411
412 $args = array(
413 'timeout' => 15,
414 'body' => array(
415 'action' => $action,
416 'request' => serialize( $args )
417 )
418 );
419
420 $request = wp_remote_post( $url, $args );
421
422 if ( is_wp_error( $request ) ) {
423 return false;
424 }
425
426 $res = maybe_unserialize( wp_remote_retrieve_body( $request ) );
427
428 if ( ! is_object( $res ) && ! is_array( $res ) ) {
429 return false;
430 }
431
432 return $res;
433 }
434
435 /**
436 * Updates information on the "View version x.x details" page with custom data.
437 *
438 * @author Vova Feldman (@svovaf)
439 * @since 1.0.4
440 *
441 * @uses FS_Api
442 *
443 * @param object $data
444 * @param string $action
445 * @param mixed $args
446 *
447 * @return object
448 */
449 function plugins_api_filter( $data, $action = '', $args = null ) {
450 $this->_logger->entrance();
451
452 if ( ( 'plugin_information' !== $action ) ||
453 ! isset( $args->slug )
454 ) {
455 return $data;
456 }
457
458 $addon = false;
459 $is_addon = false;
460
461 if ( $this->_fs->get_slug() !== $args->slug ) {
462 $addon = $this->_fs->get_addon_by_slug( $args->slug );
463
464 if ( ! is_object( $addon ) ) {
465 return $data;
466 }
467
468 $is_addon = true;
469 }
470
471 $plugin_in_repo = false;
472 if ( ! $is_addon ) {
473 // Try to fetch info from .org repository.
474 $data = self::_fetch_plugin_info_from_repository( $action, $args );
475
476 $plugin_in_repo = ( false !== $data );
477 }
478
479 if ( ! $plugin_in_repo ) {
480 $data = $args;
481
482 // Fetch as much as possible info from local files.
483 $plugin_local_data = $this->_fs->get_plugin_data();
484 $data->name = $plugin_local_data['Name'];
485 $data->author = $plugin_local_data['Author'];
486 $data->sections = array(
487 'description' => 'Upgrade ' . $plugin_local_data['Name'] . ' to latest.',
488 );
489
490 // @todo Store extra plugin info on Freemius or parse readme.txt markup.
491 /*$info = $this->_fs->get_api_site_scope()->call('/information.json');
492
493 if ( !isset($info->error) ) {
494 $data = $info;
495 }*/
496 }
497
498 // Get plugin's newest update.
499 $new_version = $this->get_latest_download_details( $is_addon ? $addon->id : false );
500
501 if ( ! is_object( $new_version ) || empty( $new_version->version ) ) {
502 $data->version = $this->_fs->get_plugin_version();
503 } else {
504 if ( $is_addon ) {
505 $data->name = $addon->title . ' ' . $this->_fs->get_text_inline( 'Add-On', 'addon' );
506 $data->slug = $addon->slug;
507 $data->url = WP_FS__ADDRESS;
508 $data->package = $new_version->url;
509 }
510
511 if ( ! $plugin_in_repo ) {
512 $data->last_updated = ! is_null( $new_version->updated ) ? $new_version->updated : $new_version->created;
513 $data->requires = $new_version->requires_platform_version;
514 $data->tested = $new_version->tested_up_to_version;
515 }
516
517 $data->version = $new_version->version;
518 $data->download_link = $new_version->url;
519 }
520
521 return $data;
522 }
523
524 /**
525 * @author Vova Feldman (@svovaf)
526 * @since 1.2.1.7
527 *
528 * @param number|bool $addon_id
529 *
530 * @return object
531 */
532 private function get_latest_download_details( $addon_id = false ) {
533 return $this->_fs->_fetch_latest_version( $addon_id );
534 }
535
536 /**
537 * Checks if a given basename has a matching folder name
538 * with the current context plugin.
539 *
540 * @author Vova Feldman (@svovaf)
541 * @since 1.2.1.6
542 *
543 * @param string $basename Current plugin's basename.
544 *
545 * @return bool
546 */
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 ), '/\\' ) );
553 }
554
555 /**
556 * This is a special after upgrade handler for migrating modules
557 * that didn't use the '-premium' suffix folder structure before
558 * the migration.
559 *
560 * @author Vova Feldman (@svovaf)
561 * @since 1.2.1.6
562 *
563 * @param bool $response Install response.
564 * @param array $hook_extra Extra arguments passed to hooked filters.
565 * @param array $result Installation result data.
566 *
567 * @return bool
568 */
569 function _maybe_update_folder_name( $response, $hook_extra, $result ) {
570 $basename = $this->_fs->get_plugin_basename();
571
572 if ( true !== $response ||
573 empty( $hook_extra ) ||
574 empty( $hook_extra['plugin'] ) ||
575 $basename !== $hook_extra['plugin']
576 ) {
577 return $response;
578 }
579
580 $active_plugins_basenames = get_option( 'active_plugins' );
581
582 for ( $i = 0, $len = count( $active_plugins_basenames ); $i < $len; $i ++ ) {
583 if ( $basename === $active_plugins_basenames[ $i ] ) {
584 // Get filename including extension.
585 $filename = basename( $basename );
586
587 $new_basename = plugin_basename(
588 trailingslashit( $this->_fs->get_slug() . ( $this->_fs->is_premium() ? '-premium' : '' ) ) .
589 $filename
590 );
591
592 // Verify that the expected correct path exists.
593 if ( file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $new_basename ) ) ) {
594 // Override active plugin name.
595 $active_plugins_basenames[ $i ] = $new_basename;
596 update_option( 'active_plugins', $active_plugins_basenames );
597 }
598
599 break;
600 }
601 }
602
603 return $response;
604 }
605
606 #----------------------------------------------------------------------------------
607 #region Auto Activation
608 #----------------------------------------------------------------------------------
609
610 /**
611 * Installs and active a plugin when explicitly requested that from a 3rd party service.
612 *
613 * This logic was inspired by the TGMPA GPL licensed library by Thomas Griffin.
614 *
615 * @link http://tgmpluginactivation.com/
616 *
617 * @author Vova Feldman
618 * @since 1.2.1.7
619 *
620 * @link https://make.wordpress.org/plugins/2017/03/16/clarification-of-guideline-8-executable-code-and-installs/
621 *
622 * @uses WP_Filesystem
623 * @uses WP_Error
624 * @uses WP_Upgrader
625 * @uses Plugin_Upgrader
626 * @uses Plugin_Installer_Skin
627 * @uses Plugin_Upgrader_Skin
628 *
629 * @param number|bool $plugin_id
630 *
631 * @return array
632 */
633 function install_and_activate_plugin( $plugin_id = false ) {
634 if ( ! empty( $plugin_id ) && ! FS_Plugin::is_valid_id( $plugin_id ) ) {
635 // Invalid plugin ID.
636 return array(
637 'message' => $this->_fs->get_text_inline( 'Invalid module ID.', 'auto-install-error-invalid-id' ),
638 'code' => 'invalid_module_id',
639 );
640 }
641
642 $is_addon = false;
643 if ( FS_Plugin::is_valid_id( $plugin_id ) &&
644 $plugin_id != $this->_fs->get_id()
645 ) {
646 $addon = $this->_fs->get_addon( $plugin_id );
647
648 if ( ! is_object( $addon ) ) {
649 // Invalid add-on ID.
650 return array(
651 'message' => $this->_fs->get_text_inline( 'Invalid module ID.', 'auto-install-error-invalid-id' ),
652 'code' => 'invalid_module_id',
653 );
654 }
655
656 $slug = $addon->slug;
657 $title = $addon->title . ' ' . $this->_fs->get_text_inline( 'Add-On', 'addon' );
658
659 $is_addon = true;
660 } 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' ) : '' );
664 }
665
666 if ( $this->is_premium_plugin_active( $plugin_id ) ) {
667 // Premium version already activated.
668 return array(
669 'message' => $is_addon ?
670 $this->_fs->get_text_inline( 'Premium add-on version already installed.', 'auto-install-error-premium-addon-activated' ) :
671 $this->_fs->get_text_inline( 'Premium version already active.', 'auto-install-error-premium-activated' ),
672 'code' => 'premium_installed',
673 );
674 }
675
676 $latest_version = $this->get_latest_download_details( $plugin_id );
677 $target_folder = "{$slug}-premium";
678
679 // Prep variables for Plugin_Installer_Skin class.
680 $extra = array();
681 $extra['slug'] = $target_folder;
682 $source = $latest_version->url;
683 $api = null;
684
685 $install_url = add_query_arg(
686 array(
687 'action' => 'install-plugin',
688 'plugin' => urlencode( $slug ),
689 ),
690 'update.php'
691 );
692
693 if ( ! class_exists( 'Plugin_Upgrader', false ) ) {
694 // Include required resources for the installation.
695 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
696 }
697
698 $skin_args = array(
699 'type' => 'web',
700 'title' => sprintf( $this->_fs->get_text_inline( 'Installing plugin: %s', 'installing-plugin-x' ), $title ),
701 'url' => esc_url_raw( $install_url ),
702 'nonce' => 'install-plugin_' . $slug,
703 'plugin' => '',
704 'api' => $api,
705 'extra' => $extra,
706 );
707
708 // $skin = new Automatic_Upgrader_Skin( $skin_args );
709 // $skin = new Plugin_Installer_Skin( $skin_args );
710 $skin = new WP_Ajax_Upgrader_Skin( $skin_args );
711
712 // Create a new instance of Plugin_Upgrader.
713 $upgrader = new Plugin_Upgrader( $skin );
714
715 // 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 );
717
718 $install_result = $upgrader->install( $source );
719
720 remove_filter( 'upgrader_source_selection', array( &$this, '_maybe_adjust_source_dir' ), 1 );
721
722 if ( is_wp_error( $install_result ) ) {
723 return array(
724 'message' => $install_result->get_error_message(),
725 'code' => $install_result->get_error_code(),
726 );
727 } elseif ( is_wp_error( $skin->result ) ) {
728 return array(
729 'message' => $skin->result->get_error_message(),
730 'code' => $skin->result->get_error_code(),
731 );
732 } elseif ( $skin->get_errors()->get_error_code() ) {
733 return array(
734 'message' => $skin->get_error_messages(),
735 'code' => 'unknown',
736 );
737 } elseif ( is_null( $install_result ) ) {
738 global $wp_filesystem;
739
740 $error_code = 'unable_to_connect_to_filesystem';
741 $error_message = $this->_fs->get_text_inline( 'Unable to connect to the filesystem. Please confirm your credentials.' );
742
743 // Pass through the error from WP_Filesystem if one was raised.
744 if ( $wp_filesystem instanceof WP_Filesystem_Base &&
745 is_wp_error( $wp_filesystem->errors ) &&
746 $wp_filesystem->errors->get_error_code()
747 ) {
748 $error_message = $wp_filesystem->errors->get_error_message();
749 }
750
751 return array(
752 'message' => $error_message,
753 'code' => $error_code,
754 );
755 }
756
757 // Grab the full path to the main plugin's file.
758 $plugin_activate = $upgrader->plugin_info();
759
760 // Try to activate the plugin.
761 $activation_result = $this->try_activate_plugin( $plugin_activate );
762
763 if ( is_wp_error( $activation_result ) ) {
764 return array(
765 'message' => $activation_result->get_error_message(),
766 'code' => $activation_result->get_error_code(),
767 );
768 }
769
770 return $skin->get_upgrade_messages();
771 }
772
773 /**
774 * Tries to activate a plugin. If fails, returns the error.
775 *
776 * @author Vova Feldman
777 * @since 1.2.1.7
778 *
779 * @param string $file_path Path within wp-plugins/ to main plugin file.
780 * This determines the styling of the output messages.
781 *
782 * @return bool|WP_Error
783 */
784 protected function try_activate_plugin( $file_path ) {
785 $activate = activate_plugin( $file_path, '', $this->_fs->is_network_active() );
786
787 return is_wp_error( $activate ) ?
788 $activate :
789 true;
790 }
791
792 /**
793 * Check if a premium module version is already active.
794 *
795 * @author Vova Feldman
796 * @since 1.2.1.7
797 *
798 * @param number|bool $plugin_id
799 *
800 * @return bool
801 */
802 private function is_premium_plugin_active( $plugin_id = false ) {
803 if ( $plugin_id != $this->_fs->get_id() ) {
804 return $this->_fs->is_addon_activated( $plugin_id, true );
805 }
806
807 return is_plugin_active( $this->_fs->premium_plugin_basename() );
808 }
809
810 /**
811 * Adjust the plugin directory name if necessary.
812 * Assumes plugin has a folder (not a single file plugin).
813 *
814 * The final destination directory of a plugin is based on the subdirectory name found in the
815 * (un)zipped source. In some cases this subdirectory name is not the same as the expected
816 * slug and the plugin will not be recognized as installed. This is fixed by adjusting
817 * the temporary unzipped source subdirectory name to the expected plugin slug.
818 *
819 * @author Vova Feldman
820 * @since 1.2.1.7
821 *
822 * @param string $source Path to upgrade/zip-file-name.tmp/subdirectory/.
823 * @param string $remote_source Path to upgrade/zip-file-name.tmp.
824 * @param \WP_Upgrader $upgrader Instance of the upgrader which installs the plugin.
825 *
826 * @return string|WP_Error
827 */
828 function _maybe_adjust_source_dir( $source, $remote_source, $upgrader ) {
829 if ( ! is_object( $GLOBALS['wp_filesystem'] ) ) {
830 return $source;
831 }
832
833 // Figure out what the slug is supposed to be.
834 $desired_slug = $upgrader->skin->options['extra']['slug'];
835
836 $subdir_name = untrailingslashit( str_replace( trailingslashit( $remote_source ), '', $source ) );
837
838 if ( ! empty( $subdir_name ) && $subdir_name !== $desired_slug ) {
839 $from_path = untrailingslashit( $source );
840 $to_path = trailingslashit( $remote_source ) . $desired_slug;
841
842 if ( true === $GLOBALS['wp_filesystem']->move( $from_path, $to_path ) ) {
843 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 }
853 }
854
855 return $source;
856 }
857
858 #endregion
859 }