required_pass_id = $required_pass_id;
}
$this->pass_manager = new Pass_Manager();
add_action( 'wp_ajax_edd_activate_extension', array( $this, 'activate' ) );
add_action( 'wp_ajax_edd_install_extension', array( $this, 'install' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'register_assets' ) );
}
/**
* Registers the extension manager script and style.
*
* @since 2.11.4
* @return void
*/
public function register_assets() {
if ( wp_script_is( 'edd-extension-manager', 'registered' ) ) {
return;
}
$minify = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
wp_register_style( 'edd-extension-manager', EDD_PLUGIN_URL . "assets/css/edd-admin-extension-manager.min.css", array(), EDD_VERSION );
wp_register_script( 'edd-extension-manager', EDD_PLUGIN_URL . "assets/js/edd-admin-extension-manager.js", array( 'jquery' ), EDD_VERSION, true );
wp_localize_script(
'edd-extension-manager',
'EDDExtensionManager',
array(
'activating' => __( 'Activating', 'easy-digital-downloads' ),
'installing' => __( 'Installing', 'easy-digital-downloads' ),
'plugin_install_failed' => __( 'Could not install the plugin. Please download and install it manually via Plugins > Add New.', 'easy-digital-downloads' ),
'extension_install_failed' => sprintf(
/* translators: 1. opening anchor tag, do not translate; 2. closing anchor tag, do not translate */
__( 'Could not install the extension. Please %1$sdownload it from your account%2$s and install it manually.', 'easy-digital-downloads' ),
'',
''
),
'extension_manager_nonce' => wp_create_nonce( 'edd_extensionmanager' ),
)
);
}
/**
* Enqueues the extension manager script/style.
*
* @since 2.11.4
* @return void
*/
public function enqueue() {
wp_enqueue_style( 'edd-extension-manager' );
wp_enqueue_script( 'edd-extension-manager' );
}
/**
* Outputs a standard extension card.
*
* @since 2.11.4
* @param ProductData $product The product data object.
* @param array $inactive_parameters The array of information to build the button for an inactive/not installed plugin.
* @param array $active_parameters The array of information needed to build the link to configure an active plugin.
* @param array $configuration The optional array of data to override the product data retrieved from the API.
* @return void
*/
public function do_extension_card( ProductData $product, $inactive_parameters, $active_parameters, $configuration = array() ) {
$this->enqueue();
if ( ! empty( $configuration ) ) {
$product = $product->mergeConfig( $configuration );
}
?>
title ); ?>
image ) ) : ?>
description ) ) : ?>
description ) ); ?>
features ) && is_array( $product->features ) ) : ?>
features as $feature ) : ?>
basename ) && ! $this->is_plugin_active( $product->basename ) ) {
?>
button( $inactive_parameters ); ?>
link( $active_parameters ); ?>
style ) ) {
$variation = $product->style;
}
if ( 'detailed-2col' === $variation && ( empty( $product->features ) || ! is_array( $product->features ) ) ) {
$variation = 'detailed';
}
$card_classes[] = "{$base_class}--{$variation}";
return $card_classes;
}
/**
* Outputs the button to activate/install a plugin/extension.
* If a link is passed in the args, create a button style link instead (@uses $this->link()).
*
* @since 2.11.4
* @param array $args The array of parameters for the button.
* @return void
*/
public function button( $args ) {
if ( ! empty( $args['href'] ) ) {
$this->link( $args );
return;
}
$defaults = array(
'button_class' => 'button-primary',
'plugin' => '',
'action' => '',
'button_text' => '',
'type' => 'plugin',
'id' => '',
'product' => '',
'pass' => $this->required_pass_id,
);
$args = wp_parse_args( $args, $defaults );
if ( empty( $args['button_text'] ) ) {
return;
}
?>
'button-primary',
'button_text' => '',
);
$args = wp_parse_args( $args, $defaults );
if ( empty( $args['button_text'] ) ) {
return;
}
?>
>
$generic_error,
'is_activated' => false,
);
if ( ! $type ) {
wp_send_json_error( $result );
}
// Check if new installations are allowed.
if ( ! $this->can_install( $type, $required_pass ) ) {
wp_send_json_error( $result );
}
$result['message'] = 'plugin' === $type
? __( 'Could not install the plugin. Please download and install it manually via Plugins > Add New.', 'easy-digital-downloads' )
: sprintf(
/* translators: 1. opening anchor tag, do not translate; 2. closing anchor tag, do not translate */
__( 'Could not install the extension. Please %1$sdownload it from your account%2$s and install it manually.', 'easy-digital-downloads' ),
'',
''
);
$plugin = ! empty( $_POST['plugin'] ) ? sanitize_text_field( $_POST['plugin'] ) : '';
if ( empty( $plugin ) ) {
wp_send_json_error( $result );
}
// Set the current screen to avoid undefined notices.
set_current_screen( 'download_page_edd-settings' );
// Prepare variables.
$url = esc_url_raw(
edd_get_admin_url(
array(
'page' => 'edd-addons',
)
)
);
ob_start();
$creds = request_filesystem_credentials( $url, '', false, false, null );
// Hide the filesystem credentials form.
ob_end_clean();
// Check for file system permissions.
if ( ! $creds ) {
wp_send_json_error( $result );
}
if ( ! WP_Filesystem( $creds ) ) {
wp_send_json_error( $result );
}
/*
* We do not need any extra credentials if we have gotten this far, so let's install the plugin.
*/
require_once EDD_PLUGIN_DIR . 'includes/admin/installers/class-plugin-silent-upgrader.php';
require_once EDD_PLUGIN_DIR . 'includes/admin/installers/class-plugin-silent-upgrader-skin.php';
require_once EDD_PLUGIN_DIR . 'includes/admin/installers/class-install-skin.php';
// Do not allow WordPress to search/download translations, as this will break JS output.
remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
// Create the plugin upgrader with our custom skin.
$installer = new \EDD\Admin\Installers\PluginSilentUpgrader( new \EDD\Admin\Installers\Install_Skin() );
// Error check.
if ( ! method_exists( $installer, 'install' ) || empty( $plugin ) ) {
wp_send_json_error( $result );
}
$installer->install( $plugin ); // phpcs:ignore
// Flush the cache and return the newly installed plugin basename.
wp_cache_flush();
$plugin_basename = $installer->plugin_info();
// Check for permissions.
if ( ! current_user_can( 'activate_plugins' ) ) {
$result['message'] = 'plugin' === $type ? esc_html__( 'Plugin installed.', 'easy-digital-downloads' ) : esc_html__( 'Extension installed.', 'easy-digital-downloads' );
wp_send_json_error( $result );
}
$this->activate( $plugin_basename );
}
/**
* Activates an existing extension.
*
* @since 2.11.4
* @param string $plugin_basename Optional: the plugin basename.
*/
public function activate( $plugin_basename = '' ) {
$result = array(
'message' => __( 'There was an error while performing your request.', 'easy-digital-downloads' ),
'is_activated' => false,
);
// Check for permissions.
if ( ! check_ajax_referer( 'edd_extensionmanager', 'nonce', false ) || ! current_user_can( 'activate_plugins' ) ) {
$result['message'] = __( 'Plugin activation is not available for you on this site.', 'easy-digital-downloads' );
wp_send_json_error( $result );
}
$already_installed = false;
if ( empty( $plugin_basename ) ) {
$plugin_basename = ! empty( $_POST['plugin'] ) ? sanitize_text_field( $_POST['plugin'] ) : '';
$already_installed = true;
}
$plugin_basename = sanitize_text_field( wp_unslash( $plugin_basename ) );
$type = ! empty( $_POST['type'] ) ? sanitize_text_field( $_POST['type'] ) : '';
if ( 'plugin' !== $type ) {
$type = 'extension';
}
$result = array(
/* translators: "extension" or "plugin" as defined by $type */
'message' => sprintf( __( 'Could not activate the %s.', 'easy-digital-downloads' ), esc_html( $type ) ),
'is_activated' => false,
);
if ( empty( $plugin_basename ) || empty( $type ) ) {
wp_send_json_error( $result );
}
$result['basename'] = $plugin_basename;
// Activate the plugin silently.
$activated = activate_plugin( $plugin_basename );
if ( ! is_wp_error( $activated ) ) {
if ( $already_installed ) {
$message = 'plugin' === $type ? esc_html__( 'Plugin activated.', 'easy-digital-downloads' ) : esc_html__( 'Extension activated.', 'easy-digital-downloads' );
} else {
$message = 'plugin' === $type ? esc_html__( 'Plugin installed & activated.', 'easy-digital-downloads' ) : esc_html__( 'Extension installed & activated.', 'easy-digital-downloads' );
}
$result['is_activated'] = true;
$result['message'] = $message;
wp_send_json_success( $result );
}
// Fallback error just in case.
wp_send_json_error( $result );
}
/**
* Determine if the plugin/extension installations are allowed.
*
* @since 2.11.4
*
* @param string $type Should be `plugin` or `extension`.
*
* @return bool
*/
public function can_install( $type, $required_pass_id = false ) {
if ( ! current_user_can( 'install_plugins' ) ) {
return false;
}
// Determine whether file modifications are allowed.
if ( ! wp_is_file_mod_allowed( 'edd_can_install' ) ) {
return false;
}
// All plugin checks are done.
if ( 'plugin' === $type ) {
return true;
}
return $this->pass_can_download( $required_pass_id );
}
/**
* Checks if a user's pass can download an extension.
*
* @since 2.11.4
* @return bool Returns true if the current site has an active pass and it is greater than or equal to the extension's minimum pass.
*/
public function pass_can_download( $required_pass_id = false ) {
$highest_pass_id = $this->pass_manager->highest_pass_id;
if ( ! $required_pass_id ) {
$required_pass_id = $this->required_pass_id;
}
return ! empty( $highest_pass_id ) && ! empty( $required_pass_id ) && $this->pass_manager->pass_compare( $highest_pass_id, $required_pass_id, '>=' );
}
/**
* Get all installed plugins.
*
* @since 2.11.4
* @return array
*/
public function get_plugins() {
if ( $this->all_plugins ) {
return $this->all_plugins;
}
$this->all_plugins = get_plugins();
return $this->all_plugins;
}
/**
* Check if a plugin is installed.
*
* @since 2.11.4
* @param string $plugin The path to the main plugin file, eg 'my-plugin/my-plugin.php'.
* @return boolean
*/
public function is_plugin_installed( $plugin ) {
return array_key_exists( $plugin, $this->get_plugins() );
}
/**
* Whether a given plugin is active or not.
*
* @since 2.11.4
* @param string|ProductData $basename_or_data The path to the main plugin file, eg 'my-plugin/my-plugin.php', or the product data object.
* @return boolean
*/
public function is_plugin_active( $basename_or_data ) {
$basename = ! empty( $basename_or_data->basename ) ? $basename_or_data->basename : $basename_or_data;
return ! empty( $basename ) && is_plugin_active( $basename );
}
}