594 lines
17 KiB
PHP
594 lines
17 KiB
PHP
<?php
|
||
/**
|
||
* Plugin Installer class - responsible for installing other plugins.
|
||
*
|
||
* @package ocdi
|
||
*/
|
||
|
||
namespace OCDI;
|
||
|
||
class PluginInstaller {
|
||
|
||
/**
|
||
* Holds all registered plugins.
|
||
*
|
||
* @var array
|
||
*/
|
||
private $plugins;
|
||
|
||
/**
|
||
* Initialize everything needed for the plugin installer class to function properly.
|
||
*/
|
||
public function init() {
|
||
$this->set_plugins();
|
||
|
||
add_action( 'ocdi/plugin_intaller_before_plugin_activation', array( $this, 'before_plugin_activation' ) );
|
||
add_action( 'ocdi/plugin_intaller_after_plugin_activation', array( $this, 'after_plugin_activation' ) );
|
||
|
||
add_action( 'wp_ajax_ocdi_install_plugin', array( $this, 'install_plugin_callback' ) );
|
||
}
|
||
|
||
/**
|
||
* Prevent the auto redirects for our recommended plugins.
|
||
* This code is run before plugin is activated.
|
||
*
|
||
* @param string $slug The plugin slug.
|
||
*/
|
||
public function before_plugin_activation( $slug ) {
|
||
// Disable the WPForms redirect after plugin activation.
|
||
if ( $slug === 'wpforms-lite' ) {
|
||
update_option( 'wpforms_activation_redirect', true );
|
||
}
|
||
|
||
// Disable the AIOSEO redirect after plugin activation.
|
||
if ( $slug === 'all-in-one-seo-pack' ) {
|
||
update_option( 'aioseo_activation_redirect', true );
|
||
}
|
||
|
||
// Disable the WP Mail SMTP redirect after plugin activation.
|
||
if ( $slug === 'wp-mail-smtp' ) {
|
||
update_option( 'wp_mail_smtp_activation_prevent_redirect', true );
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Prevent the auto redirects for our recommended plugins.
|
||
* This code is run after plugin is activated.
|
||
*
|
||
* @param string $slug The plugin slug.
|
||
*/
|
||
public function after_plugin_activation( $slug ) {
|
||
// Disable the RafflePress redirect after plugin activation.
|
||
if ( $slug === 'rafflepress' ) {
|
||
delete_transient('_rafflepress_welcome_screen_activation_redirect');
|
||
}
|
||
|
||
// Disable the MonsterInsights redirect after plugin activation.
|
||
if ( $slug === 'google-analytics-for-wordpress' ) {
|
||
delete_transient('_monsterinsights_activation_redirect');
|
||
}
|
||
|
||
// Disable the SeedProd redirect after the plugin activation.
|
||
if ( $slug === 'coming-soon' ) {
|
||
delete_transient( '_seedprod_welcome_screen_activation_redirect' );
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Get all partner plugins data.
|
||
*
|
||
* @return array[]
|
||
*/
|
||
public function get_partner_plugins() {
|
||
return array(
|
||
array(
|
||
'name' => esc_html__( 'WPForms', 'one-click-demo-import' ),
|
||
'description' => esc_html__( 'Join 4,000,000+ professionals who build smarter forms and surveys with WPForms.', 'one-click-demo-import' ),
|
||
'slug' => 'wpforms-lite',
|
||
'required' => false,
|
||
'preselected' => true,
|
||
),
|
||
array(
|
||
'name' => esc_html__( 'All in One SEO', 'one-click-demo-import' ),
|
||
'description' => esc_html__( 'Use All in One SEO Pack to optimize your WordPress site for SEO.', 'one-click-demo-import' ),
|
||
'slug' => 'all-in-one-seo-pack',
|
||
'required' => false,
|
||
'preselected' => true,
|
||
),
|
||
array(
|
||
'name' => esc_html__( 'MonsterInsights', 'one-click-demo-import' ),
|
||
'description' => esc_html__( 'The #1 Google Analytics Plugin for WordPress that’s easy and powerful.', 'one-click-demo-import' ),
|
||
'slug' => 'google-analytics-for-wordpress',
|
||
'required' => false,
|
||
'preselected' => true,
|
||
),
|
||
array(
|
||
'name' => esc_html__( 'Custom Landing Pages by SeedProd', 'one-click-demo-import' ),
|
||
'description' => esc_html__( 'Work on your site in private while visitors see a "Coming Soon" or "Maintenance Mode" page.', 'one-click-demo-import' ),
|
||
'slug' => 'coming-soon',
|
||
'required' => false,
|
||
),
|
||
array(
|
||
'name' => esc_html__( 'Smash Balloon Social Photo Feed', 'one-click-demo-import' ),
|
||
'description' => esc_html__( 'Display beautifully clean, customizable, and responsive Instagram feeds.', 'one-click-demo-import' ),
|
||
'slug' => 'instagram-feed',
|
||
'required' => false,
|
||
),
|
||
array(
|
||
'name' => esc_html__( 'WP Mail SMTP', 'one-click-demo-import' ),
|
||
'description' => esc_html__( 'Make email delivery easy for WordPress. Connect with SMTP, Gmail, Outlook, Mailgun, and more.', 'one-click-demo-import' ),
|
||
'slug' => 'wp-mail-smtp',
|
||
'required' => false,
|
||
),
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Set all registered plugins.
|
||
* With our recommended plugins being set as defaults.
|
||
*/
|
||
public function set_plugins() {
|
||
$all_plugins = array_merge( $this->get_partner_plugins(), Helpers::apply_filters( 'ocdi/register_plugins', array() ) );
|
||
|
||
$this->plugins = $this->filter_plugins( $all_plugins );
|
||
}
|
||
|
||
/**
|
||
* Get all theme registered plugins.
|
||
* With our 3 top recommended plugins being set as defaults.
|
||
*/
|
||
public function get_theme_plugins() {
|
||
$default_plugins = $this->get_top_partner_plugins();
|
||
|
||
$theme_plugins = array_merge( $default_plugins, Helpers::apply_filters( 'ocdi/register_plugins', array() ) );
|
||
|
||
return $this->filter_plugins( $theme_plugins );
|
||
}
|
||
|
||
/**
|
||
* Get the top 3 partner plugins if they are not already activated.
|
||
*
|
||
* @return array
|
||
*/
|
||
private function get_top_partner_plugins() {
|
||
$installed_plugins = $this->get_plugins();
|
||
$contact_form = [
|
||
'wpforms-lite/wpforms.php',
|
||
'wpforms/wpforms.php',
|
||
'formidable/formidable.php',
|
||
'formidable/formidable-pro.php',
|
||
'gravityforms/gravityforms.php',
|
||
'ninja-forms/ninja-forms.php',
|
||
];
|
||
$seo = [
|
||
'all-in-one-seo-pack/all_in_one_seo_pack.php',
|
||
'all-in-one-seo-pack-pro/all_in_one_seo_pack.php',
|
||
'wordpress-seo/wp-seo.php',
|
||
'wordpress-seo-premium/wp-seo-premium.php',
|
||
'seo-by-rank-math/rank-math.php',
|
||
'seo-by-rank-math-pro/rank-math-pro.php',
|
||
];
|
||
$google_analytics = [
|
||
'google-analytics-for-wordpress/googleanalytics.php',
|
||
'exactmetrics-premium/exactmetrics-premium.php',
|
||
'google-analytics-dashboard-for-wp/gadwp.php',
|
||
];
|
||
|
||
$plugins = array_slice( $this->get_partner_plugins(), 0, 3 );
|
||
|
||
$plugins = array_map( function ( $plugin ) {
|
||
unset( $plugin['preselected'] );
|
||
|
||
return $plugin;
|
||
} , $plugins );
|
||
|
||
return array_filter(
|
||
$plugins,
|
||
function ( $plugin ) use ( $installed_plugins, $contact_form, $seo, $google_analytics ) {
|
||
if ( empty( $plugin['slug'] ) || empty( $plugin['name'] ) ) {
|
||
return false;
|
||
}
|
||
|
||
if ( 'wpforms-lite' === $plugin['slug'] ) {
|
||
foreach ( $installed_plugins as $basename => $plugin_info ) {
|
||
if ( in_array( $basename, $contact_form, true ) ) {
|
||
return false;
|
||
}
|
||
}
|
||
} elseif ( 'all-in-one-seo-pack' === $plugin['slug'] ) {
|
||
foreach ( $installed_plugins as $basename => $plugin_info ) {
|
||
if ( in_array( $basename, $seo, true ) ) {
|
||
return false;
|
||
}
|
||
}
|
||
} elseif ( 'google-analytics-for-wordpress' === $plugin['slug'] ) {
|
||
foreach ( $installed_plugins as $basename => $plugin_info ) {
|
||
if ( in_array( $basename, $google_analytics, true ) ) {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
);
|
||
}
|
||
|
||
/**
|
||
* AJAX callback for installing a plugin.
|
||
* Has to contain the `slug` POST parameter.
|
||
*/
|
||
public function install_plugin_callback() {
|
||
check_ajax_referer( 'ocdi-ajax-verification', 'security' );
|
||
|
||
// Check if user has the WP capability to install plugins.
|
||
if ( ! current_user_can( 'install_plugins' ) ) {
|
||
wp_send_json_error( esc_html__( 'Could not install the plugin. You don\'t have permission to install plugins.', 'one-click-demo-import' ) );
|
||
}
|
||
|
||
$slug = ! empty( $_POST['slug'] ) ? sanitize_key( wp_unslash( $_POST['slug'] ) ) : '';
|
||
|
||
if ( empty( $slug ) ) {
|
||
wp_send_json_error( esc_html__( 'Could not install the plugin. Plugin slug is missing.', 'one-click-demo-import' ) );
|
||
}
|
||
|
||
// Check if the plugin is already installed and activated.
|
||
if ( $this->is_plugin_active( $slug ) ) {
|
||
wp_send_json_success( esc_html__( 'Plugin is already installed and activated!', 'one-click-demo-import' ) );
|
||
}
|
||
|
||
// Activate the plugin if the plugin is already installed.
|
||
if ( $this->is_plugin_installed( $slug ) ) {
|
||
$activated = $this->activate_plugin( $this->get_plugin_basename_from_slug( $slug ), $slug );
|
||
|
||
if ( ! is_wp_error( $activated ) ) {
|
||
wp_send_json_success( esc_html__( 'Plugin was already installed! We activated it for you.', 'one-click-demo-import' ) );
|
||
} else {
|
||
wp_send_json_error( $activated->get_error_message() );
|
||
}
|
||
}
|
||
|
||
// Check for file system permissions.
|
||
if ( ! $this->filesystem_permissions_allowed() ) {
|
||
wp_send_json_error( esc_html__( 'Could not install the plugin. Don\'t have file permission.', 'one-click-demo-import' ) );
|
||
}
|
||
|
||
// Do not allow WordPress to search/download translations, as this will break JS output.
|
||
remove_action( 'upgrader_process_complete', [ 'Language_Pack_Upgrader', 'async_upgrade' ], 20 );
|
||
|
||
// Prep variables for Plugin_Installer_Skin class.
|
||
$extra = array();
|
||
$extra['slug'] = $slug; // Needed for potentially renaming of directory name.
|
||
$source = $this->get_download_url( $slug );
|
||
$api = empty( $this->get_plugin_data( $slug )['source'] ) ? $this->get_plugins_api( $slug ) : null;
|
||
$api = ( false !== $api ) ? $api : null;
|
||
|
||
if ( ! empty( $api ) && is_wp_error( $api ) ) {
|
||
wp_send_json_error( $api->get_error_message() );
|
||
}
|
||
|
||
if ( ! class_exists( '\Plugin_Upgrader', false ) ) {
|
||
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
||
}
|
||
|
||
$skin_args = array(
|
||
'type' => 'web',
|
||
'plugin' => '',
|
||
'api' => $api,
|
||
'extra' => $extra,
|
||
);
|
||
|
||
$upgrader = new \Plugin_Upgrader( new PluginInstallerSkin( $skin_args ) );
|
||
|
||
$upgrader->install( $source );
|
||
|
||
// Flush the cache and return the newly installed plugin basename.
|
||
wp_cache_flush();
|
||
|
||
if ( $upgrader->plugin_info() ) {
|
||
$activated = $this->activate_plugin( $upgrader->plugin_info(), $slug );
|
||
|
||
if ( ! is_wp_error( $activated ) ) {
|
||
wp_send_json_success(
|
||
esc_html__( 'Plugin installed and activated succesfully.', 'one-click-demo-import' )
|
||
);
|
||
} else {
|
||
wp_send_json_success( $activated->get_error_message() );
|
||
}
|
||
}
|
||
|
||
wp_send_json_error( esc_html__( 'Could not install the plugin. WP Plugin installer could not retrieve plugin information.', 'one-click-demo-import' ) );
|
||
}
|
||
|
||
/**
|
||
* Direct plugin install, without AJAX responses.
|
||
*
|
||
* @param string $slug The registered plugin slug to install.
|
||
*
|
||
* @return bool
|
||
*/
|
||
public function install_plugin( $slug ) {
|
||
if ( empty( $slug ) ) {
|
||
return false;
|
||
}
|
||
|
||
// Check if user has the WP capability to install plugins.
|
||
if ( ! current_user_can( 'install_plugins' ) ) {
|
||
return false;
|
||
}
|
||
|
||
// Check if the plugin is already installed and activated.
|
||
if ( $this->is_plugin_active( $slug ) ) {
|
||
return true;
|
||
}
|
||
|
||
// Activate the plugin if the plugin is already installed.
|
||
if ( $this->is_plugin_installed( $slug ) ) {
|
||
$activated = $this->activate_plugin( $this->get_plugin_basename_from_slug( $slug ), $slug );
|
||
|
||
return ! is_wp_error( $activated );
|
||
}
|
||
|
||
// Check for file system permissions.
|
||
if ( ! $this->filesystem_permissions_allowed() ) {
|
||
return false;
|
||
}
|
||
|
||
// Do not allow WordPress to search/download translations, as this will break JS output.
|
||
remove_action( 'upgrader_process_complete', [ 'Language_Pack_Upgrader', 'async_upgrade' ], 20 );
|
||
|
||
// Prep variables for Plugin_Installer_Skin class.
|
||
$extra = array();
|
||
$extra['slug'] = $slug; // Needed for potentially renaming of directory name.
|
||
$source = $this->get_download_url( $slug );
|
||
$api = empty( $this->get_plugin_data( $slug )['source'] ) ? $this->get_plugins_api( $slug ) : null;
|
||
$api = ( false !== $api ) ? $api : null;
|
||
|
||
if ( ! empty( $api ) && is_wp_error( $api ) ) {
|
||
return false;
|
||
}
|
||
|
||
if ( ! class_exists( '\Plugin_Upgrader', false ) ) {
|
||
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
||
}
|
||
|
||
$skin_args = array(
|
||
'type' => 'web',
|
||
'plugin' => '',
|
||
'api' => $api,
|
||
'extra' => $extra,
|
||
);
|
||
|
||
$upgrader = new \Plugin_Upgrader( new PluginInstallerSkinSilent( $skin_args ) );
|
||
|
||
$upgrader->install( $source );
|
||
|
||
// Flush the cache and return the newly installed plugin basename.
|
||
wp_cache_flush();
|
||
|
||
if ( $upgrader->plugin_info() ) {
|
||
$activated = $this->activate_plugin( $upgrader->plugin_info(), $slug );
|
||
|
||
if ( ! is_wp_error( $activated ) ) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Activate the plugin with the before and after hooks.
|
||
*
|
||
* @param string $plugin_filename The plugin's basename(example: wpforms/wpforms.php).
|
||
* @param string $slug The plugin's slug.
|
||
*
|
||
* @return null|WP_Error Null on success, WP_Error on invalid file.
|
||
*/
|
||
private function activate_plugin( $plugin_filename, $slug ) {
|
||
Helpers::do_action( 'ocdi/plugin_intaller_before_plugin_activation', $slug );
|
||
|
||
$activated = activate_plugin( $plugin_filename );
|
||
|
||
Helpers::do_action( 'ocdi/plugin_intaller_after_plugin_activation', $slug );
|
||
|
||
return $activated;
|
||
}
|
||
|
||
/**
|
||
* Helper function to check for the filesystem permissions.
|
||
*
|
||
* @return bool
|
||
*/
|
||
private function filesystem_permissions_allowed() {
|
||
$ocdi = OneClickDemoImport::get_instance();
|
||
$url = esc_url_raw( $ocdi->get_plugin_settings_url() );
|
||
$creds = request_filesystem_credentials( $url, '', false, false, null );
|
||
|
||
// Check for file system permissions.
|
||
if ( false === $creds || ! WP_Filesystem( $creds ) ) {
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Get the data of a registered plugin via the slug.
|
||
*
|
||
* @param string $slug The plugin slug.
|
||
*
|
||
* @return array
|
||
*/
|
||
public function get_plugin_data( $slug ) {
|
||
$data = [];
|
||
|
||
foreach ( $this->plugins as $plugin ) {
|
||
if ( $plugin['slug'] === $slug ) {
|
||
$data = $plugin;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return $data;
|
||
}
|
||
|
||
/**
|
||
* Get the download URL for a plugin.
|
||
*
|
||
* @param string $slug Plugin slug.
|
||
*
|
||
* @return string Plugin download URL.
|
||
*/
|
||
public function get_download_url( $slug ) {
|
||
$plugin_data = $this->get_plugin_data( $slug );
|
||
|
||
if ( ! empty( $plugin_data['source'] ) ) {
|
||
return $plugin_data['source'];
|
||
}
|
||
|
||
return $this->get_wp_repo_download_url( $slug );
|
||
}
|
||
|
||
/**
|
||
* Get the download URL from the WP.org.
|
||
*
|
||
* @param string $slug Plugin slug.
|
||
*
|
||
* @return string Plugin download URL from WP.org.
|
||
*/
|
||
protected function get_wp_repo_download_url( $slug ) {
|
||
$source = '';
|
||
$api = $this->get_plugins_api( $slug );
|
||
|
||
if ( false !== $api && isset( $api->download_link ) ) {
|
||
$source = $api->download_link;
|
||
}
|
||
|
||
return $source;
|
||
}
|
||
|
||
/**
|
||
* Try to grab information from WordPress API.
|
||
*
|
||
* @param string $slug Plugin slug.
|
||
*
|
||
* @return object Plugins_api response object on success, WP_Error on failure.
|
||
*/
|
||
protected function get_plugins_api( $slug ) {
|
||
static $api = array(); // Cache received responses.
|
||
|
||
if ( ! isset( $api[ $slug ] ) ) {
|
||
if ( ! function_exists( 'plugins_api' ) ) {
|
||
require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
|
||
}
|
||
|
||
$api[ $slug ] = plugins_api( 'plugin_information', array( 'slug' => $slug, 'fields' => array( 'sections' => false ) ) );
|
||
}
|
||
|
||
return $api[ $slug ];
|
||
}
|
||
|
||
/**
|
||
* Wrapper around the core WP get_plugins function, making sure it's actually available.
|
||
*
|
||
* @param string $plugin_folder Optional. Relative path to single plugin folder.
|
||
*
|
||
* @return array Array of installed plugins with plugin information.
|
||
*/
|
||
public function get_plugins( $plugin_folder = '' ) {
|
||
if ( ! function_exists( 'get_plugins' ) ) {
|
||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||
}
|
||
|
||
return get_plugins( $plugin_folder );
|
||
}
|
||
|
||
/**
|
||
* Helper function to extract the plugin file path from the
|
||
* plugin slug, if the plugin is installed.
|
||
*
|
||
* @param string $slug Plugin slug (typically folder name) as provided by the developer.
|
||
*
|
||
* @return string|bool Either plugin file path for plugin if installed, or false.
|
||
*/
|
||
protected function get_plugin_basename_from_slug( $slug ) {
|
||
$keys = array_keys( $this->get_plugins() );
|
||
|
||
foreach ( $keys as $key ) {
|
||
if ( preg_match( '/^' . $slug . '\//', $key ) ) {
|
||
return $key;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Check if a plugin is installed. Does not take must-use plugins into account.
|
||
*
|
||
* @param string $slug Plugin slug.
|
||
*
|
||
* @return bool True if installed, false otherwise.
|
||
*/
|
||
public function is_plugin_installed( $slug ) {
|
||
return ( ! empty( $this->get_plugin_basename_from_slug( $slug ) ) );
|
||
}
|
||
|
||
/**
|
||
* Check if a plugin is active.
|
||
*
|
||
* @param string $slug Plugin slug.
|
||
*
|
||
* @return bool True if active, false otherwise.
|
||
*/
|
||
public function is_plugin_active( $slug ) {
|
||
$plugin_path = $this->get_plugin_basename_from_slug( $slug );
|
||
|
||
if ( empty( $plugin_path ) ) {
|
||
return false;
|
||
}
|
||
|
||
return is_plugin_active( $plugin_path );
|
||
}
|
||
|
||
/**
|
||
* Get the list of plugins (with their data) of all non-active and non-installed registered plugins.
|
||
*
|
||
* @return array
|
||
*/
|
||
public function get_missing_plugins() {
|
||
$missing = [];
|
||
|
||
foreach ( $this->plugins as $plugin_data ) {
|
||
if ( ! $this->is_plugin_active( $plugin_data['slug'] ) ) {
|
||
$missing[] = $plugin_data;
|
||
}
|
||
}
|
||
|
||
return $missing;
|
||
}
|
||
|
||
/**
|
||
* Return only plugins with required attributes:
|
||
* - name
|
||
* - slug
|
||
*
|
||
* @param array $plugins The array of plugin's data.
|
||
*
|
||
* @return array
|
||
*/
|
||
private function filter_plugins( $plugins ) {
|
||
return array_filter(
|
||
$plugins,
|
||
function ( $plugin ) {
|
||
if ( empty( $plugin['slug'] ) || empty( $plugin['name'] ) ) {
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
);
|
||
}
|
||
}
|