first commit
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace Essential_Addons_Elementor\Pro\Classes\License;
|
||||
|
||||
// Exit if accessed directly
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
use Exception;
|
||||
use Essential_Addons_Elementor\Pro\Classes\License\Contracts\ApiAdapter;
|
||||
|
||||
/**
|
||||
* @property string $textdomain
|
||||
* @property string $action_prefix
|
||||
*/
|
||||
#[\AllowDynamicProperties]
|
||||
class AJAXApi extends ApiAdapter {
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function register() {
|
||||
if ( ! isset( $this->action_prefix ) ) {
|
||||
throw new Exception( "action_prefix needs to be set in ajax configuration" );
|
||||
}
|
||||
|
||||
add_action( "wp_ajax_{$this->action_prefix}/license/activate", [ $this, 'activate' ] );
|
||||
add_action( "wp_ajax_{$this->action_prefix}/license/deactivate", [ $this, 'deactivate' ] );
|
||||
add_action( "wp_ajax_{$this->action_prefix}/license/submit-otp", [ $this, 'submit_otp' ] );
|
||||
add_action( "wp_ajax_{$this->action_prefix}/license/resend-otp", [ $this, 'resend_otp' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API Config
|
||||
* @return array
|
||||
*/
|
||||
public function get_api_config() {
|
||||
return array_merge( parent::get_api_config(), [
|
||||
'action' => $this->action_prefix,
|
||||
'api_url' => esc_url( admin_url( 'admin-ajax.php' ) )
|
||||
] );
|
||||
}
|
||||
|
||||
public function error( $code, $message ) {
|
||||
wp_send_json_error( [
|
||||
'code' => $code,
|
||||
'message' => $message
|
||||
] );
|
||||
}
|
||||
|
||||
private function nonce_permission_check( ) {
|
||||
if ( ! isset( $_POST['_nonce'] ) || ! $this->verify_nonce( $_POST['_nonce'] ) ) {
|
||||
$this->error( 'nonce_error', __( 'Nonce Verifications Failed.', $this->textdomain ) );
|
||||
}
|
||||
|
||||
if ( ! $this->permission_check() ) {
|
||||
$this->error( 'no_permission', __( 'You don\'t have permission to take this action.', $this->textdomain ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $request array
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function activate( $request = [] ) {
|
||||
$this->nonce_permission_check();
|
||||
|
||||
$response = $this->license_manager->activate( [
|
||||
'license_key' => sanitize_text_field( $_POST['license_key'] )
|
||||
] );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$this->error( $response->get_error_code(), $response->get_error_message() );
|
||||
}
|
||||
|
||||
wp_send_json_success( $response );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $request array
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deactivate( $request = [] ) {
|
||||
$response = $this->license_manager->deactivate();
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$this->error( $response->get_error_code(), $response->get_error_message() );
|
||||
}
|
||||
|
||||
wp_send_json_success( $response );
|
||||
}
|
||||
|
||||
public function submit_otp( $request = [] ) {
|
||||
$this->nonce_permission_check();
|
||||
|
||||
$args = [
|
||||
'otp' => sanitize_text_field( $_POST['otp'] ),
|
||||
'license_key' => sanitize_text_field( $_POST['license'] )
|
||||
];
|
||||
|
||||
$response = $this->license_manager->submit_otp( $args );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$this->error( $response->get_error_code(), $response->get_error_message() );
|
||||
}
|
||||
|
||||
wp_send_json_success( $response );
|
||||
}
|
||||
|
||||
public function resend_otp( $request = [] ) {
|
||||
$this->nonce_permission_check();
|
||||
|
||||
$args = [
|
||||
'license_key' => sanitize_text_field( $_POST['license'] )
|
||||
];
|
||||
|
||||
$response = $this->license_manager->resend_otp( $args );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$this->error( $response->get_error_code(), $response->get_error_message() );
|
||||
}
|
||||
|
||||
wp_send_json_success( $response );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace Essential_Addons_Elementor\Pro\Classes\License\Contracts;
|
||||
|
||||
// Exit if accessed directly
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
use Exception;
|
||||
use Essential_Addons_Elementor\Pro\Classes\License\LicenseManager;
|
||||
|
||||
#[\AllowDynamicProperties]
|
||||
abstract class ApiAdapter {
|
||||
protected $config = null;
|
||||
|
||||
/**
|
||||
* @var LicenseManager
|
||||
*/
|
||||
protected $license_manager;
|
||||
|
||||
public function __construct( $license_manager ) {
|
||||
$this->license_manager = $license_manager;
|
||||
$this->config = $this->license_manager->get_args( $this->license_manager->api );
|
||||
$this->config['handle'] = $this->license_manager->get_args( 'scripts_handle' );
|
||||
$this->config['screen_id'] = $this->license_manager->get_args( 'screen_id' );
|
||||
$this->config['item_id'] = $this->license_manager->get_args( 'item_id' );
|
||||
|
||||
$this->register();
|
||||
|
||||
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue' ], 11 );
|
||||
}
|
||||
|
||||
public function enqueue( $hook ) {
|
||||
if ( is_array( $this->screen_id ) && ! in_array( $hook, $this->screen_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! is_array( $this->screen_id ) && $this->screen_id !== $hook ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_localize_script( $this->handle, 'wpdeveloperLicenseManagerConfig', $this->get_api_config() );
|
||||
}
|
||||
|
||||
public function get_api_config() {
|
||||
return [
|
||||
'textdomain' => $this->license_manager->textdomain,
|
||||
'apiType' => $this->license_manager->api,
|
||||
'nonce' => wp_create_nonce( "wpdeveloper_sl_{$this->item_id}_nonce" )
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __get( $name ) {
|
||||
if ( isset( $this->config[ $name ] ) ) {
|
||||
return $this->config[ $name ];
|
||||
} elseif ( isset( $this->license_manager->{$name} ) ) {
|
||||
return $this->license_manager->get_args( $name );
|
||||
} else {
|
||||
throw new Exception( "Please provide $name for api configuration." );
|
||||
}
|
||||
}
|
||||
|
||||
public function __isset( $name ) {
|
||||
return isset( $this->config[ $name ] );
|
||||
}
|
||||
|
||||
protected function verify_nonce( $nonce ) {
|
||||
return wp_verify_nonce( $nonce, "wpdeveloper_sl_{$this->item_id}_nonce" );
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is responsible for checking permissions.
|
||||
* @return bool
|
||||
*/
|
||||
public function permission_check() {
|
||||
return current_user_can( isset( $this->permission ) ? $this->permission : 'delete_users' );
|
||||
}
|
||||
|
||||
abstract public function register();
|
||||
|
||||
abstract public function activate( $request );
|
||||
|
||||
abstract public function deactivate( $request );
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
<?php
|
||||
|
||||
namespace Essential_Addons_Elementor\Pro\Classes\License;
|
||||
|
||||
// Exit if accessed directly
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
use Exception;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* @property int $item_id
|
||||
* @property string $version
|
||||
* @property string $storeURL
|
||||
* @property string $db_prefix
|
||||
* @property string $textdomain
|
||||
* @property string $item_name
|
||||
*/
|
||||
#[\AllowDynamicProperties]
|
||||
class LicenseManager {
|
||||
private static $_instance = null;
|
||||
protected $license = '';
|
||||
protected $license_data = null;
|
||||
protected $args = [
|
||||
'version' => '',
|
||||
// 'author' => '',
|
||||
// 'beta' => '',
|
||||
'plugin_file' => '',
|
||||
'item_id' => 0,
|
||||
'item_name' => '',
|
||||
'item_slug' => '',
|
||||
'storeURL' => '',
|
||||
'textdomain' => '',
|
||||
'db_prefix' => '',
|
||||
'scripts_handle' => '',
|
||||
'screen_id' => '',
|
||||
'page_slug' => '',
|
||||
'api' => ''
|
||||
];
|
||||
|
||||
public static function get_instance( $args ) {
|
||||
if ( self::$_instance === null ) {
|
||||
self::$_instance = new self( $args );
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct( $args ) {
|
||||
foreach ( $this->args as $property => $value ) {
|
||||
if ( ! array_key_exists( $property, $args ) ) {
|
||||
throw new Exception( "$property is missing in licensing." );
|
||||
}
|
||||
}
|
||||
|
||||
$this->args = wp_parse_args( $args, $this->args );
|
||||
$this->license_data = $this->get_license_data();
|
||||
|
||||
if ( ( empty( $this->license_data ) ) && current_user_can( 'activate_plugins' ) ) {
|
||||
add_action( 'admin_notices', [ $this, 'admin_notices' ] );
|
||||
add_action( 'eael_admin_notices', [ $this, 'admin_notices' ] );
|
||||
}
|
||||
|
||||
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue' ], 11 );
|
||||
|
||||
if ( isset( $this->args['api'] ) ) {
|
||||
switch ( strtolower( $this->args['api'] ) ) {
|
||||
case 'rest':
|
||||
if ( ! isset( $this->args['rest'] ) ) {
|
||||
throw new Exception( "rest is missing in licensing." );
|
||||
}
|
||||
new RESTApi( $this );
|
||||
break;
|
||||
case 'ajax':
|
||||
if ( ! isset( $this->args['ajax'] ) ) {
|
||||
throw new Exception( "ajax is missing in licensing." );
|
||||
}
|
||||
new AJAXApi( $this );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
add_action( 'init', [ $this, 'plugin_updater' ] );
|
||||
add_action( 'eael_licensing', array( $this, 'render_licenses_page' ) );
|
||||
}
|
||||
|
||||
public function admin_notices() {
|
||||
$message = sprintf( __( 'Please %1$sactivate your license%2$s key to enable updates for %3$s.', $this->textdomain ), '<a style="text-decoration: none;" href="' . admin_url( 'admin.php?page=' . $this->page_slug ) . '">', '</a>', '<strong>' . $this->item_name . '</strong>' );
|
||||
|
||||
$notice = sprintf( '<div style="padding: 10px;" class="%1$s-notice wpdeveloper-licensing-notice notice notice-error">%2$s</div>', $this->textdomain, $message );
|
||||
|
||||
echo wp_kses_post( $notice );
|
||||
}
|
||||
|
||||
public function plugin_updater() {
|
||||
$_license = get_option( "{$this->db_prefix}-license-key" );
|
||||
|
||||
new PluginUpdater( $this->storeURL, $this->plugin_file, [
|
||||
'version' => $this->version, // current version number
|
||||
'license' => $_license, // license key (used get_option above to retrieve from DB)
|
||||
'item_id' => $this->item_id, // ID of the product
|
||||
'author' => empty( $this->author ) ? 'WPDeveloper' : $this->author, // author of this plugin
|
||||
'beta' => isset( $this->beta ) ? $this->beta : false
|
||||
] );
|
||||
}
|
||||
|
||||
public function get_args( $name = '' ) {
|
||||
return empty( $name ) ? $this->args : $this->args[ $name ];
|
||||
}
|
||||
|
||||
public function enqueue( $hook ) {
|
||||
if ( is_array( $this->screen_id ) && ! in_array( $hook, $this->screen_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! is_array( $this->screen_id ) && $this->screen_id !== $hook ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_localize_script( $this->scripts_handle, 'wpdeveloperLicenseData', $this->get_license_data() );
|
||||
}
|
||||
|
||||
public function get_license_data() {
|
||||
$_license = get_option( "{$this->db_prefix}-license-key" );
|
||||
$_license_status = get_option( "{$this->db_prefix}-license-status" );
|
||||
$_license_data = get_transient( "{$this->db_prefix}-license_data" );
|
||||
|
||||
if ( $_license_data !== false ) {
|
||||
$_license_data = (array) $_license_data;
|
||||
}
|
||||
|
||||
if ( $_license_data == false || empty( $_license_data ) ) {
|
||||
$response = $this->check();
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$_license_data = (array) $response;
|
||||
}
|
||||
|
||||
return array_merge( [
|
||||
'license_key' => $_license,
|
||||
'hidden_license_key' => $this->hide_license_key( $_license ),
|
||||
'license_status' => $_license_status
|
||||
], $_license_data );
|
||||
}
|
||||
|
||||
public function hide_license_key( $_license ) {
|
||||
$length = mb_strlen( $_license ) - 10;
|
||||
$_license = substr_replace( $_license, mb_substr( preg_replace( '/\S/', '*', $_license ), 5, $length ), 5, $length );
|
||||
|
||||
return $_license;
|
||||
}
|
||||
|
||||
public function activate( $args = [] ) {
|
||||
$this->license = sanitize_text_field( isset( $args['license_key'] ) ? trim( $args['license_key'] ) : '' );
|
||||
$response = $this->remote_post( 'activate_license' );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if license required OTP to activate.
|
||||
*/
|
||||
if ( isset( $response->license ) && $response->license == 'required_otp' ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
update_option( "{$this->db_prefix}-license-key", $this->license, 'no' );
|
||||
update_option( "{$this->db_prefix}-license-status", $response->license, 'no' );
|
||||
set_transient( "{$this->db_prefix}-license_data", $response, MONTH_IN_SECONDS * 3 );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function deactivate( $args = [] ) {
|
||||
$this->license = get_option( "{$this->db_prefix}-license-key", '' );
|
||||
$response = $this->remote_post( 'deactivate_license' );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
delete_option( "{$this->db_prefix}-license-key" );
|
||||
delete_option( "{$this->db_prefix}-license-status" );
|
||||
delete_transient( "{$this->db_prefix}-license_data" );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function submit_otp( $args = [] ) {
|
||||
$this->license = sanitize_text_field( isset( $args['license_key'] ) ? trim( $args['license_key'] ) : '' );
|
||||
$response = $this->remote_post( 'activate_license_by_otp', $args );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
update_option( "{$this->db_prefix}-license-key", $this->license, 'no' );
|
||||
update_option( "{$this->db_prefix}-license-status", $response->license, 'no' );
|
||||
set_transient( "{$this->db_prefix}-license_data", $response, MONTH_IN_SECONDS * 3 );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function resend_otp( $args ) {
|
||||
$this->license = sanitize_text_field( isset( $args['license_key'] ) ? trim( $args['license_key'] ) : '' );
|
||||
|
||||
return $this->remote_post( 'resend_otp_for_license', $args );
|
||||
}
|
||||
|
||||
public function check( $args = [] ) {
|
||||
$this->license = get_option( "{$this->db_prefix}-license-key", '' );
|
||||
$_license_data = get_transient( "{$this->db_prefix}-license_data" );
|
||||
|
||||
if ( $_license_data !== false ) {
|
||||
$_license_data = (array) $_license_data;
|
||||
}
|
||||
|
||||
if ( ! empty( $_license_data ) ) {
|
||||
return $_license_data;
|
||||
}
|
||||
|
||||
$response = $this->remote_post( 'check_license' );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
delete_transient( "{$this->db_prefix}-license_data" );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
set_transient( "{$this->db_prefix}-license_data", $response, MONTH_IN_SECONDS * 3 );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 'activate_license'
|
||||
*
|
||||
* @param mixed $args
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function remote_post( $action, $args = [] ) {
|
||||
if ( empty( $this->license ) ) {
|
||||
return new WP_Error( 'empty_license', __( 'Please provide a valid license.', $this->textdomain ) );
|
||||
}
|
||||
|
||||
$defaults = [
|
||||
'edd_action' => $action,
|
||||
'license' => $this->license,
|
||||
'item_id' => $this->item_id,
|
||||
'item_name' => rawurlencode( $this->item_name ), // the name of our product in EDD
|
||||
'url' => home_url(),
|
||||
'version' => $this->version,
|
||||
'environment' => function_exists( 'wp_get_environment_type' ) ? wp_get_environment_type() : 'production'
|
||||
];
|
||||
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
|
||||
$response = wp_safe_remote_post( $this->storeURL, [
|
||||
'timeout' => 15,
|
||||
'sslverify' => false,
|
||||
'body' => $args
|
||||
] );
|
||||
|
||||
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
return new WP_Error( 'unknown', __( 'An error occurred, please try again.', $this->textdomain ) );
|
||||
}
|
||||
|
||||
$license_data = $this->maybe_error( json_decode( wp_remote_retrieve_body( $response ) ) );
|
||||
|
||||
if ( ! is_wp_error( $license_data ) ) {
|
||||
$license_data->license_key = $this->hide_license_key( $this->license );
|
||||
}
|
||||
|
||||
return $license_data;
|
||||
}
|
||||
|
||||
private function maybe_error( $license_data ) {
|
||||
if ( false === $license_data->success ) {
|
||||
$message = '';
|
||||
$error_code = isset($license_data->error) ? $license_data->error : 'unknown';
|
||||
|
||||
switch ( $error_code ) {
|
||||
case 'expired':
|
||||
$message = sprintf( /* translators: the license key expiration date */ __( 'Your license key expired on %s.', $this->textdomain ), date_i18n( get_option( 'date_format' ), $license_data->expires ) );
|
||||
break;
|
||||
|
||||
case 'invalid_otp':
|
||||
$message = __( 'Your license confirmation code is invalid.', $this->textdomain );
|
||||
break;
|
||||
|
||||
case 'expired_otp':
|
||||
$message = __( 'Your license confirmation code has been expired.', $this->textdomain );
|
||||
break;
|
||||
|
||||
case 'disabled':
|
||||
case 'revoked':
|
||||
$message = __( 'Your license key has been disabled.', $this->textdomain );
|
||||
break;
|
||||
|
||||
case 'missing':
|
||||
$message = __( 'Invalid license.', $this->textdomain );
|
||||
break;
|
||||
|
||||
case 'invalid':
|
||||
case 'site_inactive':
|
||||
$message = __( 'Your license is not active for this URL.', $this->textdomain );
|
||||
break;
|
||||
|
||||
case 'item_name_mismatch':
|
||||
/* translators: the plugin name */ $message = sprintf( __( 'This appears to be an invalid license key for %s.', $this->textdomain ), $this->item_name );
|
||||
break;
|
||||
|
||||
case 'no_activations_left':
|
||||
$message = __( 'Your license key has reached its activation limit.', $this->textdomain );
|
||||
break;
|
||||
|
||||
default:
|
||||
$message = __( 'An error occurred, please try again.', $this->textdomain );
|
||||
break;
|
||||
}
|
||||
|
||||
return new WP_Error( $error_code, wp_kses( $message, 'post' ) );
|
||||
}
|
||||
|
||||
return $license_data;
|
||||
}
|
||||
|
||||
public function __get( $name ) {
|
||||
if ( isset( $this->args[ $name ] ) ) {
|
||||
return $this->args[ $name ];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function render_licenses_page() {
|
||||
$hidden_license_key = $this->license_data['hidden_license_key'] ?? '';
|
||||
$status = $this->license_data['license_status'] ?? '';
|
||||
$title = sprintf( __( '%s License', $this->text_domain ), $this->product_name );
|
||||
// if ( $status !== 'valid' ) {
|
||||
// $this->set_license_key( '' );
|
||||
// }
|
||||
include_once __DIR__ . '/views/settings.php';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,671 @@
|
||||
<?php
|
||||
|
||||
namespace Essential_Addons_Elementor\Pro\Classes\License;
|
||||
|
||||
// Exit if accessed directly
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Allows plugins to use their own update API.
|
||||
*
|
||||
* @author Easy Digital Downloads
|
||||
* @version 1.9.2
|
||||
*/
|
||||
|
||||
#[\AllowDynamicProperties]
|
||||
class PluginUpdater {
|
||||
|
||||
private $api_url = '';
|
||||
private $api_data = [];
|
||||
private $plugin_file = '';
|
||||
private $name = '';
|
||||
private $slug = '';
|
||||
private $version = '';
|
||||
private $wp_override = false;
|
||||
private $beta = false;
|
||||
private $failed_request_cache_key;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @uses plugin_basename()
|
||||
* @uses hook()
|
||||
*
|
||||
* @param string $_api_url The URL pointing to the custom API endpoint.
|
||||
* @param string $_plugin_file Path to the plugin file.
|
||||
* @param array $_api_data Optional data to send with API calls.
|
||||
*/
|
||||
public function __construct( $_api_url, $_plugin_file, $_api_data = null ) {
|
||||
|
||||
global $edd_plugin_data;
|
||||
|
||||
$this->api_url = trailingslashit( $_api_url );
|
||||
$this->api_data = $_api_data;
|
||||
$this->plugin_file = $_plugin_file;
|
||||
$this->name = plugin_basename( $_plugin_file );
|
||||
$this->slug = basename( $_plugin_file, '.php' );
|
||||
$this->version = $_api_data['version'];
|
||||
$this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false;
|
||||
$this->beta = ! empty( $this->api_data['beta'] ) ? true : false;
|
||||
$this->failed_request_cache_key = 'edd_sl_failed_http_' . md5( $this->api_url );
|
||||
|
||||
$edd_plugin_data[$this->slug] = $this->api_data;
|
||||
|
||||
/**
|
||||
* Fires after the $edd_plugin_data is setup.
|
||||
*
|
||||
* @since x.x.x
|
||||
*
|
||||
* @param array $edd_plugin_data Array of EDD SL plugin data.
|
||||
*/
|
||||
do_action( 'post_edd_sl_plugin_updater_setup', $edd_plugin_data );
|
||||
|
||||
// Set up hooks.
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up WordPress filters to hook into WP's update process.
|
||||
*
|
||||
* @uses add_filter()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init() {
|
||||
add_filter( 'pre_set_site_transient_update_plugins', [$this, 'check_update'] );
|
||||
add_filter( 'plugins_api', [$this, 'plugins_api_filter'], 10, 3 );
|
||||
add_action( 'after_plugin_row', [$this, 'show_update_notification'], 10, 2 );
|
||||
add_action( 'admin_init', [$this, 'show_changelog'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for Updates at the defined API endpoint and modify the update array.
|
||||
*
|
||||
* This function dives into the update API just when WordPress creates its update array,
|
||||
* then adds a custom API call and injects the custom plugin data retrieved from the API.
|
||||
* It is reassembled from parts of the native WordPress plugin update code.
|
||||
* See wp-includes/update.php line 121 for the original wp_update_plugins() function.
|
||||
*
|
||||
* @uses api_request()
|
||||
*
|
||||
* @param array $_transient_data Update array build by WordPress.
|
||||
* @return array|object Modified update array with custom plugin data.
|
||||
*/
|
||||
public function check_update( $_transient_data ) {
|
||||
|
||||
global $pagenow;
|
||||
|
||||
if ( ! is_object( $_transient_data ) ) {
|
||||
$_transient_data = new stdClass();
|
||||
}
|
||||
|
||||
if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[$this->name] ) && false === $this->wp_override ) {
|
||||
return $_transient_data;
|
||||
}
|
||||
|
||||
$current = $this->get_repo_api_data();
|
||||
if ( false !== $current && is_object( $current ) && isset( $current->new_version ) ) {
|
||||
if ( version_compare( $this->version, $current->new_version, '<' ) ) {
|
||||
$_transient_data->response[$this->name] = $current;
|
||||
} else {
|
||||
// Populating the no_update information is required to support auto-updates in WordPress 5.5.
|
||||
$_transient_data->no_update[$this->name] = $current;
|
||||
}
|
||||
}
|
||||
$_transient_data->last_checked = time();
|
||||
$_transient_data->checked[$this->name] = $this->version;
|
||||
|
||||
return $_transient_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get repo API data from store.
|
||||
* Save to cache.
|
||||
*
|
||||
* @return stdClass|bool
|
||||
*/
|
||||
public function get_repo_api_data() {
|
||||
$version_info = $this->get_cached_version_info();
|
||||
|
||||
if ( false === $version_info ) {
|
||||
$version_info = $this->api_request(
|
||||
'plugin_latest_version',
|
||||
[
|
||||
'slug' => $this->slug,
|
||||
'beta' => $this->beta
|
||||
]
|
||||
);
|
||||
if ( ! $version_info ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is required for your plugin to support auto-updates in WordPress 5.5.
|
||||
$version_info->plugin = $this->name;
|
||||
$version_info->id = $this->name;
|
||||
$version_info->tested = $this->get_tested_version( $version_info );
|
||||
|
||||
$this->set_version_info_cache( $version_info );
|
||||
}
|
||||
|
||||
return $version_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the plugin's tested version.
|
||||
*
|
||||
* @since 1.9.2
|
||||
* @param object $version_info
|
||||
* @return null|string
|
||||
*/
|
||||
private function get_tested_version( $version_info ) {
|
||||
|
||||
// There is no tested version.
|
||||
if ( empty( $version_info->tested ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Strip off extra version data so the result is x.y or x.y.z.
|
||||
list( $current_wp_version ) = explode( '-', get_bloginfo( 'version' ) );
|
||||
|
||||
// The tested version is greater than or equal to the current WP version, no need to do anything.
|
||||
if ( version_compare( $version_info->tested, $current_wp_version, '>=' ) ) {
|
||||
return $version_info->tested;
|
||||
}
|
||||
$current_version_parts = explode( '.', $current_wp_version );
|
||||
$tested_parts = explode( '.', $version_info->tested );
|
||||
|
||||
// The current WordPress version is x.y.z, so update the tested version to match it.
|
||||
if ( isset( $current_version_parts[2] ) && $current_version_parts[0] === $tested_parts[0] && $current_version_parts[1] === $tested_parts[1] ) {
|
||||
$tested_parts[2] = $current_version_parts[2];
|
||||
}
|
||||
|
||||
return implode( '.', $tested_parts );
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the update notification on multisite subsites.
|
||||
*
|
||||
* @param string $file
|
||||
* @param array $plugin
|
||||
*/
|
||||
public function show_update_notification( $file, $plugin ) {
|
||||
|
||||
// Return early if in the network admin, or if this is not a multisite install.
|
||||
if ( is_network_admin() || ! is_multisite() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow single site admins to see that an update is available.
|
||||
if ( ! current_user_can( 'activate_plugins' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->name !== $file ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not print any message if update does not exist.
|
||||
$update_cache = get_site_transient( 'update_plugins' );
|
||||
|
||||
if ( ! isset( $update_cache->response[$this->name] ) ) {
|
||||
if ( ! is_object( $update_cache ) ) {
|
||||
$update_cache = new stdClass();
|
||||
}
|
||||
$update_cache->response[$this->name] = $this->get_repo_api_data();
|
||||
}
|
||||
|
||||
// Return early if this plugin isn't in the transient->response or if the site is running the current or newer version of the plugin.
|
||||
if ( empty( $update_cache->response[$this->name] ) || version_compare( $this->version, $update_cache->response[$this->name]->new_version, '>=' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
printf(
|
||||
'<tr class="plugin-update-tr %3$s" id="%1$s-update" data-slug="%1$s" data-plugin="%2$s">',
|
||||
$this->slug,
|
||||
$file,
|
||||
in_array( $this->name, $this->get_active_plugins(), true ) ? 'active' : 'inactive'
|
||||
);
|
||||
|
||||
echo '<td colspan="3" class="plugin-update colspanchange">';
|
||||
echo '<div class="update-message notice inline notice-warning notice-alt"><p>';
|
||||
|
||||
$changelog_link = '';
|
||||
if ( ! empty( $update_cache->response[$this->name]->sections->changelog ) ) {
|
||||
$changelog_link = add_query_arg(
|
||||
[
|
||||
'edd_sl_action' => 'view_plugin_changelog',
|
||||
'plugin' => urlencode( $this->name ),
|
||||
'slug' => urlencode( $this->slug ),
|
||||
'TB_iframe' => 'true',
|
||||
'width' => 77,
|
||||
'height' => 911
|
||||
],
|
||||
self_admin_url( 'index.php' )
|
||||
);
|
||||
}
|
||||
$update_link = add_query_arg(
|
||||
[
|
||||
'action' => 'upgrade-plugin',
|
||||
'plugin' => urlencode( $this->name )
|
||||
],
|
||||
self_admin_url( 'update.php' )
|
||||
);
|
||||
|
||||
printf(
|
||||
/* translators: the plugin name. */
|
||||
esc_html__( 'There is a new version of %1$s available.', 'easy-digital-downloads' ),
|
||||
esc_html( $plugin['Name'] )
|
||||
);
|
||||
|
||||
if ( ! current_user_can( 'update_plugins' ) ) {
|
||||
echo ' ';
|
||||
esc_html_e( 'Contact your network administrator to install the update.', 'easy-digital-downloads' );
|
||||
} elseif ( empty( $update_cache->response[$this->name]->package ) && ! empty( $changelog_link ) ) {
|
||||
echo ' ';
|
||||
printf(
|
||||
/* translators: 1. opening anchor tag, do not translate 2. the new plugin version 3. closing anchor tag, do not translate. */
|
||||
__( '%1$sView version %2$s details%3$s.', 'easy-digital-downloads' ),
|
||||
'<a target="_blank" class="thickbox open-plugin-details-modal" href="' . esc_url( $changelog_link ) . '">',
|
||||
esc_html( $update_cache->response[$this->name]->new_version ),
|
||||
'</a>'
|
||||
);
|
||||
} elseif ( ! empty( $changelog_link ) ) {
|
||||
echo ' ';
|
||||
printf(
|
||||
__( '%1$sView version %2$s details%3$s or %4$supdate now%5$s.', 'easy-digital-downloads' ),
|
||||
'<a target="_blank" class="thickbox open-plugin-details-modal" href="' . esc_url( $changelog_link ) . '">',
|
||||
esc_html( $update_cache->response[$this->name]->new_version ),
|
||||
'</a>',
|
||||
'<a target="_blank" class="update-link" href="' . esc_url( wp_nonce_url( $update_link, 'upgrade-plugin_' . $file ) ) . '">',
|
||||
'</a>'
|
||||
);
|
||||
} else {
|
||||
printf(
|
||||
' %1$s%2$s%3$s',
|
||||
'<a target="_blank" class="update-link" href="' . esc_url( wp_nonce_url( $update_link, 'upgrade-plugin_' . $file ) ) . '">',
|
||||
esc_html__( 'Update now.', 'easy-digital-downloads' ),
|
||||
'</a>'
|
||||
);
|
||||
}
|
||||
|
||||
do_action( "in_plugin_update_message-{$file}", $plugin, $plugin );
|
||||
|
||||
echo '</p></div></td></tr>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the plugins active in a multisite network.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_active_plugins() {
|
||||
$active_plugins = (array) get_option( 'active_plugins' );
|
||||
$active_network_plugins = (array) get_site_option( 'active_sitewide_plugins' );
|
||||
|
||||
return array_merge( $active_plugins, array_keys( $active_network_plugins ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates information on the "View version x.x details" page with custom data.
|
||||
*
|
||||
* @uses api_request()
|
||||
*
|
||||
* @param mixed $_data
|
||||
* @param string $_action
|
||||
* @param object $_args
|
||||
* @return object $_data
|
||||
*/
|
||||
public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
|
||||
|
||||
if ( 'plugin_information' !== $_action ) {
|
||||
return $_data;
|
||||
}
|
||||
|
||||
if ( ! isset( $_args->slug ) || ( $_args->slug !== $this->slug ) ) {
|
||||
return $_data;
|
||||
}
|
||||
|
||||
$to_send = [
|
||||
'slug' => $this->slug,
|
||||
'is_ssl' => is_ssl(),
|
||||
'fields' => [
|
||||
'banners' => [],
|
||||
'reviews' => false,
|
||||
'icons' => []
|
||||
]
|
||||
];
|
||||
|
||||
// Get the transient where we store the api request for this plugin for 24 hours
|
||||
$edd_api_request_transient = $this->get_cached_version_info();
|
||||
|
||||
//If we have no transient-saved value, run the API, set a fresh transient with the API value, and return that value too right now.
|
||||
if ( empty( $edd_api_request_transient ) ) {
|
||||
$api_response = $this->api_request( 'plugin_information', $to_send );
|
||||
|
||||
// Expires in 3 hours
|
||||
$this->set_version_info_cache( $api_response );
|
||||
|
||||
if ( false !== $api_response ) {
|
||||
$_data = $api_response;
|
||||
}
|
||||
} else {
|
||||
$_data = $edd_api_request_transient;
|
||||
}
|
||||
|
||||
// Convert sections into an associative array, since we're getting an object, but Core expects an array.
|
||||
if ( isset( $_data->sections ) && ! is_array( $_data->sections ) ) {
|
||||
$_data->sections = $this->convert_object_to_array( $_data->sections );
|
||||
}
|
||||
|
||||
// Convert banners into an associative array, since we're getting an object, but Core expects an array.
|
||||
if ( isset( $_data->banners ) && ! is_array( $_data->banners ) ) {
|
||||
$_data->banners = $this->convert_object_to_array( $_data->banners );
|
||||
}
|
||||
|
||||
// Convert icons into an associative array, since we're getting an object, but Core expects an array.
|
||||
if ( isset( $_data->icons ) && ! is_array( $_data->icons ) ) {
|
||||
$_data->icons = $this->convert_object_to_array( $_data->icons );
|
||||
}
|
||||
|
||||
// Convert contributors into an associative array, since we're getting an object, but Core expects an array.
|
||||
if ( isset( $_data->contributors ) && ! is_array( $_data->contributors ) ) {
|
||||
$_data->contributors = $this->convert_object_to_array( $_data->contributors );
|
||||
}
|
||||
|
||||
if ( ! isset( $_data->plugin ) ) {
|
||||
$_data->plugin = $this->name;
|
||||
}
|
||||
|
||||
return $_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert some objects to arrays when injecting data into the update API
|
||||
*
|
||||
* Some data like sections, banners, and icons are expected to be an associative array, however due to the JSON
|
||||
* decoding, they are objects. This method allows us to pass in the object and return an associative array.
|
||||
*
|
||||
* @since 3.6.5
|
||||
*
|
||||
* @param stdClass $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function convert_object_to_array( $data ) {
|
||||
if ( ! is_array( $data ) && ! is_object( $data ) ) {
|
||||
return [];
|
||||
}
|
||||
$new_data = [];
|
||||
foreach ( $data as $key => $value ) {
|
||||
$new_data[$key] = is_object( $value ) ? $this->convert_object_to_array( $value ) : $value;
|
||||
}
|
||||
|
||||
return $new_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable SSL verification in order to prevent download update failures
|
||||
*
|
||||
* @param array $args
|
||||
* @param string $url
|
||||
* @return array $array
|
||||
*/
|
||||
public function http_request_args( $args, $url ) {
|
||||
|
||||
if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
|
||||
$args['sslverify'] = $this->verify_ssl();
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the API and, if successfull, returns the object delivered by the API.
|
||||
*
|
||||
* @uses get_bloginfo()
|
||||
* @uses wp_remote_post()
|
||||
* @uses is_wp_error()
|
||||
*
|
||||
* @param string $_action The requested action.
|
||||
* @param array $_data Parameters for the API action.
|
||||
* @return false|object|void
|
||||
*/
|
||||
private function api_request( $_action, $_data ) {
|
||||
$data = array_merge( $this->api_data, $_data );
|
||||
|
||||
if ( $data['slug'] !== $this->slug ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't allow a plugin to ping itself
|
||||
if ( trailingslashit( home_url() ) === $this->api_url ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $this->request_recently_failed() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->get_version_from_remote();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a request has recently failed.
|
||||
*
|
||||
* @since 1.9.1
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function request_recently_failed() {
|
||||
$failed_request_details = get_option( $this->failed_request_cache_key );
|
||||
|
||||
// Request has never failed.
|
||||
if ( empty( $failed_request_details ) || ! is_numeric( $failed_request_details ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Request previously failed, but the timeout has expired.
|
||||
* This means we're allowed to try again.
|
||||
*/
|
||||
if ( time() > $failed_request_details ) {
|
||||
delete_option( $this->failed_request_cache_key );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a failed HTTP request for this API URL.
|
||||
* We set a timestamp for 1 hour from now. This prevents future API requests from being
|
||||
* made to this domain for 1 hour. Once the timestamp is in the past, API requests
|
||||
* will be allowed again. This way if the site is down for some reason we don't bombard
|
||||
* it with failed API requests.
|
||||
*
|
||||
* @see EDD_SL_Plugin_Updater::request_recently_failed
|
||||
*
|
||||
* @since 1.9.1
|
||||
*/
|
||||
private function log_failed_request() {
|
||||
update_option( $this->failed_request_cache_key, strtotime( '+1 hour' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* If available, show the changelog for sites in a multisite install.
|
||||
*/
|
||||
public function show_changelog() {
|
||||
|
||||
if ( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' !== $_REQUEST['edd_sl_action'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( empty( $_REQUEST['plugin'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( empty( $_REQUEST['slug'] ) || $this->slug !== $_REQUEST['slug'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'update_plugins' ) ) {
|
||||
wp_die( esc_html__( 'You do not have permission to install plugin updates', 'easy-digital-downloads' ), esc_html__( 'Error', 'easy-digital-downloads' ), ['response' => 403] );
|
||||
}
|
||||
|
||||
$version_info = $this->get_repo_api_data();
|
||||
if ( isset( $version_info->sections ) ) {
|
||||
$sections = $this->convert_object_to_array( $version_info->sections );
|
||||
if ( ! empty( $sections['changelog'] ) ) {
|
||||
echo '<div style="background:#fff;padding:10px;">' . wp_kses_post( $sections['changelog'] ) . '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current version information from the remote site.
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
private function get_version_from_remote() {
|
||||
$api_params = [
|
||||
'edd_action' => 'get_version',
|
||||
'license' => ! empty( $this->api_data['license'] ) ? $this->api_data['license'] : '',
|
||||
'item_name' => isset( $this->api_data['item_name'] ) ? $this->api_data['item_name'] : false,
|
||||
'item_id' => isset( $this->api_data['item_id'] ) ? $this->api_data['item_id'] : false,
|
||||
'version' => isset( $this->api_data['version'] ) ? $this->api_data['version'] : false,
|
||||
'slug' => $this->slug,
|
||||
'author' => $this->api_data['author'],
|
||||
'url' => home_url(),
|
||||
'beta' => $this->beta,
|
||||
'php_version' => phpversion(),
|
||||
'wp_version' => get_bloginfo( 'version' )
|
||||
];
|
||||
|
||||
/**
|
||||
* Filters the parameters sent in the API request.
|
||||
*
|
||||
* @param array $api_params The array of data sent in the request.
|
||||
* @param array $this->api_data The array of data set up in the class constructor.
|
||||
* @param string $this->plugin_file The full path and filename of the file.
|
||||
*/
|
||||
$api_params = apply_filters( 'edd_sl_plugin_updater_api_params', $api_params, $this->api_data, $this->plugin_file );
|
||||
|
||||
$request = wp_remote_post(
|
||||
$this->api_url,
|
||||
[
|
||||
'timeout' => 15,
|
||||
'sslverify' => $this->verify_ssl(),
|
||||
'body' => $api_params
|
||||
]
|
||||
);
|
||||
|
||||
if ( is_wp_error( $request ) || ( 200 !== wp_remote_retrieve_response_code( $request ) ) ) {
|
||||
$this->log_failed_request();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$request = json_decode( wp_remote_retrieve_body( $request ) );
|
||||
|
||||
if ( $request && isset( $request->sections ) ) {
|
||||
$request->sections = maybe_unserialize( $request->sections );
|
||||
} else {
|
||||
$request = false;
|
||||
}
|
||||
|
||||
if ( $request && isset( $request->banners ) ) {
|
||||
$request->banners = maybe_unserialize( $request->banners );
|
||||
}
|
||||
|
||||
if ( $request && isset( $request->icons ) ) {
|
||||
$request->icons = maybe_unserialize( $request->icons );
|
||||
}
|
||||
|
||||
if ( ! empty( $request->sections ) ) {
|
||||
foreach ( $request->sections as $key => $section ) {
|
||||
$request->$key = (array) $section;
|
||||
}
|
||||
}
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the version info from the cache, if it exists.
|
||||
*
|
||||
* @param string $cache_key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_cached_version_info( $cache_key = '' ) {
|
||||
|
||||
if ( empty( $cache_key ) ) {
|
||||
$cache_key = $this->get_cache_key();
|
||||
}
|
||||
|
||||
$cache = get_option( $cache_key );
|
||||
|
||||
// Cache is expired
|
||||
if ( empty( $cache['timeout'] ) || time() > $cache['timeout'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need to turn the icons into an array, thanks to WP Core forcing these into an object at some point.
|
||||
$cache['value'] = json_decode( $cache['value'] );
|
||||
if ( ! empty( $cache['value']->icons ) ) {
|
||||
$cache['value']->icons = (array) $cache['value']->icons;
|
||||
}
|
||||
|
||||
return $cache['value'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the plugin version information to the database.
|
||||
*
|
||||
* @param string $value
|
||||
* @param string $cache_key
|
||||
*/
|
||||
public function set_version_info_cache( $value = '', $cache_key = '' ) {
|
||||
|
||||
if ( empty( $cache_key ) ) {
|
||||
$cache_key = $this->get_cache_key();
|
||||
}
|
||||
|
||||
$data = [
|
||||
'timeout' => strtotime( '+3 hours', time() ),
|
||||
'value' => wp_json_encode( $value )
|
||||
];
|
||||
|
||||
update_option( $cache_key, $data, 'no' );
|
||||
|
||||
// Delete the duplicate option
|
||||
delete_option( 'edd_api_request_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the SSL of the store should be verified.
|
||||
*
|
||||
* @since 1.6.13
|
||||
* @return bool
|
||||
*/
|
||||
private function verify_ssl() {
|
||||
return (bool) apply_filters( 'edd_sl_api_request_verify_ssl', true, $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unique key (option name) for a plugin.
|
||||
*
|
||||
* @since 1.9.0
|
||||
* @return string
|
||||
*/
|
||||
private function get_cache_key() {
|
||||
$string = $this->slug . $this->api_data['license'] . $this->beta;
|
||||
|
||||
return 'edd_sl_' . md5( serialize( $string ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace Essential_Addons_Elementor\Pro\Classes\License;
|
||||
|
||||
// Exit if accessed directly
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
use Exception;
|
||||
use WP_REST_Server;
|
||||
use Essential_Addons_Elementor\Pro\Classes\License\Contracts\ApiAdapter;
|
||||
|
||||
#[\AllowDynamicProperties]
|
||||
class RESTApi extends ApiAdapter {
|
||||
private $version = 'v1';
|
||||
|
||||
public function register() {
|
||||
if ( ! isset( $this->namespace ) ) {
|
||||
throw new Exception( "namespace is missing in your rest configuration." );
|
||||
}
|
||||
|
||||
add_action( 'rest_api_init', [$this, 'routes'] );
|
||||
}
|
||||
|
||||
public function get_api_config() {
|
||||
return array_merge( parent::get_api_config(), [
|
||||
'api_url' => esc_url( trailingslashit( rest_url( $this->get_namespace() ) ) )
|
||||
] );
|
||||
}
|
||||
|
||||
public function routes() {
|
||||
$this->route( '/license/activate', [$this, 'activate'], $this->args() );
|
||||
$this->route( '/license/deactivate', [$this, 'deactivate'] );
|
||||
$this->route( '/license/submit-otp', [$this, 'submit_otp'], $this->args([
|
||||
'otp' => [
|
||||
'required' => true,
|
||||
'validate_callback' => function ( $param, $request, $key ) {
|
||||
return is_string( $param ) && ! empty( $param );
|
||||
}
|
||||
]
|
||||
]) );
|
||||
$this->route( '/license/resend-otp', [$this, 'resend_otp'], $this->args() );
|
||||
$this->route( '/license/get-license', [$this, 'get_license'] );
|
||||
}
|
||||
|
||||
public function activate( $request ) {
|
||||
return $this->license_manager->activate( [
|
||||
'license_key' => sanitize_text_field( $request->get_param( 'license_key' ) )
|
||||
] );
|
||||
}
|
||||
|
||||
public function deactivate( $request ) {
|
||||
return $this->license_manager->deactivate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles OTP submission request.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function submit_otp( $request ) {
|
||||
$args = [
|
||||
'otp' => sanitize_text_field( $request->get_param( 'otp') ),
|
||||
'license_key' => sanitize_text_field( $request->get_param( 'license_key') )
|
||||
];
|
||||
|
||||
return $this->license_manager->submit_otp( $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles OTP resend request.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function resend_otp( $request ) {
|
||||
$args = [
|
||||
'license_key' => sanitize_text_field( $request->get_param( 'license_key') )
|
||||
];
|
||||
|
||||
return $this->license_manager->resend_otp( $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the license details.
|
||||
*
|
||||
* This method uses the LicenseManager to get the license data, hide the license key, and format the title.
|
||||
* It then returns an array with the title, hidden license key, and license status.
|
||||
*
|
||||
* @return array An array containing the title, hidden license key, and license status.
|
||||
*/
|
||||
public function get_license(){
|
||||
$license_data = $this->license_manager->get_license_data();
|
||||
$license_key = $this->license_manager->hide_license_key($license_data['license_key']);
|
||||
$status = $license_data['license_status'];
|
||||
$title = sprintf(__('%s License', $this->license_manager->textdomain), $this->license_manager->item_name);
|
||||
|
||||
return ['title' => $title, 'key' => $license_key, 'status' => $status];
|
||||
}
|
||||
|
||||
protected function args($args = []) {
|
||||
return wp_parse_args($args, [
|
||||
'license_key' => [
|
||||
'required' => true,
|
||||
'validate_callback' => function ( $param, $request, $key ) {
|
||||
return is_string( $param ) && ! empty( $param );
|
||||
}
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
private function get_namespace() {
|
||||
return $this->namespace . '/' . $this->version;
|
||||
}
|
||||
|
||||
protected function route( $endpoint, $callback, $args = [] ) {
|
||||
return register_rest_route( $this->get_namespace(), $endpoint, [
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => $callback,
|
||||
'permission_callback' => [$this, 'permission_check'],
|
||||
'args' => $args
|
||||
] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<div class="eael-block p45 eael-activate__license__block --activation-form" style="display: <?php echo ( $status === false || $status !== 'valid' ) ? 'block' : 'none'; ?>">
|
||||
<div class="eael__flex eael__flex--wrap align__center mb30">
|
||||
<h3>Just one more step to go!</h3>
|
||||
<img src="<?php echo esc_url( EAEL_PLUGIN_URL . 'assets/admin/images/steps.svg' ); ?>" alt="">
|
||||
</div>
|
||||
<p><?php _e( 'Enter your license key here, to activate <strong>Essential Addons for Elementor</strong>, and get automatic updates and premium support.', $this->text_domain ); ?></p>
|
||||
<p><?php printf( __( 'Visit the <a href="%s" target="_blank">Validation Guide</a> for help.', $this->text_domain ), 'https://essential-addons.com/elementor/docs/getting-started/validating-license/' ); ?></p>
|
||||
<ol>
|
||||
<li>
|
||||
<p><?php printf( __( 'Log in to <a href="%s" target="_blank">your account</a> to get your license key.', $this->text_domain ), 'https://wpdeveloper.com/account/' ); ?></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><?php printf( __( 'If you don\'t yet have a license key, get <a href="%s" target="_blank">Essential Addons for Elementor now</a>.', $this->text_domain ), 'https://wpdeveloper.com/in/upgrade-essential-addons-elementor' ); ?></p>
|
||||
</li>
|
||||
<li><?php _e( __( 'Copy the license key from your account and paste it below.', $this->text_domain ) ); ?></li>
|
||||
<li><?php _e( __( 'Click on <strong>"Activate License"</strong> button.', $this->text_domain ) ); ?></li>
|
||||
</ol>
|
||||
<div class="license__form__block">
|
||||
<div class="eael-license-form-block">
|
||||
<form method="post" action="#">
|
||||
<?php wp_nonce_field( $this->args['item_slug'] . '_license_nonce', $this->args['item_slug'] . '_license_nonce' ); ?>
|
||||
<input id="<?php echo $this->args['item_slug']; ?>-license-key" type="text" class="eael-form__control" placeholder="Place Your License Key & Activate">
|
||||
<button type="submit" class="eael-button button__themeColor" name="license_activate">Activate</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="eael-verification-msg" style="display: none;">
|
||||
<p>License Verification code has been sent to this <span class="eael-customer-email"></span>. Please check your email for the code & insert it below 👇</p>
|
||||
<div class="short-description">
|
||||
<b style="font-weight: 700;">Note: </b> Check out this <a href="https://essential-addons.com/docs/verify-essential-addons-pro-license-key/" target="_blank">guide</a> to
|
||||
verify your license key. If you need any assistance with retrieving your License Verification Key, please <a href="https://wpdeveloper.com/support/"
|
||||
target="_blank">contact support</a>.
|
||||
</div>
|
||||
<div class="eael-verification-input-container license__form__block">
|
||||
<div class="eael-license-form-block">
|
||||
<input type="text" id="<?php echo $this->args['item_slug']; ?>-license-otp" class="eael-form__control" placeholder="Enter Your Verification Code">
|
||||
<button type="submit" class="eael-button button__themeColor">Verify</button>
|
||||
</div>
|
||||
<p>Haven’t received an email? Please hit this <a href="#" class="eael-otp-resend">"Resend"</a> to retry. Please note that this verification code will
|
||||
expire after 15 minutes.</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="eael-license-error-msg error-message" style="display: none;"></p>
|
||||
</div>
|
||||
|
||||
<div class="eael-block p45 eael-activate__license__block --deactivation-form" style="display: <?php echo ( $status !== false && $status === 'valid' ) ? 'block' : 'none'; ?>">
|
||||
<div class="eael-grid">
|
||||
<div class="eael-col-md-6">
|
||||
<ul class="eael-feature__list ls-none">
|
||||
<li class="feature__item">
|
||||
<span class="icon">
|
||||
<img src="<?php echo EAEL_PRO_PLUGIN_URL . 'assets/admin/images/icon-auto-update.svg'; ?>" alt="essential-addons-auto-update">
|
||||
</span>
|
||||
<div class="content">
|
||||
<h4>Premium Support</h4>
|
||||
<p>Supported by professional and courteous staff.</p>
|
||||
</div>
|
||||
</li>
|
||||
<li class="feature__item">
|
||||
<span class="icon">
|
||||
<img src="<?php echo EAEL_PRO_PLUGIN_URL . 'assets/admin/images/icon-auto-update.svg'; ?>" alt="essential-addons-auto-update">
|
||||
</span>
|
||||
<div class="content">
|
||||
<h4>Auto Update</h4>
|
||||
<p>Update the plugin right from your WordPress Dashboard.</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="eael-col-md-6">
|
||||
<div class="license__form__block">
|
||||
<div class="eael-license-form-block">
|
||||
<form method="post" action="#">
|
||||
<input class="eael-form__control regular-text" disabled type="text" value="<?php echo esc_attr( $hidden_license_key ); ?>"
|
||||
placeholder="Place Your License Key and Activate"/>
|
||||
<button type="submit" class="eael-button button__danger" name="license_deactivate">Deactivate</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user