khaihihi
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* WC_Helper_API Class
|
||||
*
|
||||
* Provides a communication interface with the WooCommerce.com Helper API.
|
||||
*/
|
||||
class WC_Helper_API {
|
||||
public static $api_base;
|
||||
|
||||
/**
|
||||
* Load
|
||||
*
|
||||
* Allow devs to point the API base to a local API development or staging server.
|
||||
* Note that sslverify will be turned off for the woocommerce.dev + WP_DEBUG combination.
|
||||
* The URL can be changed on plugins_loaded before priority 10.
|
||||
*/
|
||||
public static function load() {
|
||||
self::$api_base = apply_filters( 'woocommerce_helper_api_base', 'https://woocommerce.com/wp-json/helper/1.0' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an HTTP request to the Helper API.
|
||||
*
|
||||
* @param string $endpoint The endpoint to request.
|
||||
* @param array $args Additional data for the request. Set authenticated to a truthy value to enable auth.
|
||||
*
|
||||
* @return array|WP_Error The response from wp_safe_remote_request()
|
||||
*/
|
||||
public static function request( $endpoint, $args = array() ) {
|
||||
$url = self::url( $endpoint );
|
||||
|
||||
if ( ! empty( $args['authenticated'] ) ) {
|
||||
if ( ! self::_authenticate( $url, $args ) ) {
|
||||
return new WP_Error( 'authentication', 'Authentication failed.' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow developers to filter the request args passed to wp_safe_remote_request().
|
||||
* Useful to remove sslverify when working on a local api dev environment.
|
||||
*/
|
||||
$args = apply_filters( 'woocommerce_helper_api_request_args', $args, $endpoint );
|
||||
|
||||
// TODO: Check response signatures on certain endpoints.
|
||||
return wp_safe_remote_request( $url, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds authentication headers to an HTTP request.
|
||||
*
|
||||
* @param string $url The request URI.
|
||||
* @param array $args By-ref, the args that will be passed to wp_remote_request().
|
||||
* @return bool Were the headers added?
|
||||
*/
|
||||
private static function _authenticate( $url, &$args ) {
|
||||
$auth = WC_Helper_Options::get( 'auth' );
|
||||
|
||||
if ( empty( $auth['access_token'] ) || empty( $auth['access_token_secret'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$request_uri = parse_url( $url, PHP_URL_PATH );
|
||||
$query_string = parse_url( $url, PHP_URL_QUERY );
|
||||
|
||||
if ( is_string( $query_string ) ) {
|
||||
$request_uri .= '?' . $query_string;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'host' => parse_url( $url, PHP_URL_HOST ),
|
||||
'request_uri' => $request_uri,
|
||||
'method' => ! empty( $args['method'] ) ? $args['method'] : 'GET',
|
||||
);
|
||||
|
||||
if ( ! empty( $args['body'] ) ) {
|
||||
$data['body'] = $args['body'];
|
||||
}
|
||||
|
||||
$signature = hash_hmac( 'sha256', json_encode( $data ), $auth['access_token_secret'] );
|
||||
if ( empty( $args['headers'] ) ) {
|
||||
$args['headers'] = array();
|
||||
}
|
||||
|
||||
$args['headers'] = array(
|
||||
'Authorization' => 'Bearer ' . $auth['access_token'],
|
||||
'X-Woo-Signature' => $signature,
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for self::request().
|
||||
*
|
||||
* @param string $endpoint The helper API endpoint to request.
|
||||
* @param array $args Arguments passed to wp_remote_request().
|
||||
*
|
||||
* @return array The response object from wp_safe_remote_request().
|
||||
*/
|
||||
public static function get( $endpoint, $args = array() ) {
|
||||
$args['method'] = 'GET';
|
||||
return self::request( $endpoint, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for self::request().
|
||||
*
|
||||
* @param string $endpoint The helper API endpoint to request.
|
||||
* @param array $args Arguments passed to wp_remote_request().
|
||||
*
|
||||
* @return array The response object from wp_safe_remote_request().
|
||||
*/
|
||||
public static function post( $endpoint, $args = array() ) {
|
||||
$args['method'] = 'POST';
|
||||
return self::request( $endpoint, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the API base, form a request URL from a given endpoint.
|
||||
*
|
||||
* @param string $endpoint The endpoint to request.
|
||||
*
|
||||
* @return string The absolute endpoint URL.
|
||||
*/
|
||||
public static function url( $endpoint ) {
|
||||
$endpoint = ltrim( $endpoint, '/' );
|
||||
$endpoint = sprintf( '%s/%s', self::$api_base, $endpoint );
|
||||
$endpoint = esc_url_raw( $endpoint );
|
||||
return $endpoint;
|
||||
}
|
||||
}
|
||||
|
||||
WC_Helper_API::load();
|
||||
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* WC_Helper_Compat Class
|
||||
*
|
||||
* Some level of compatibility with the legacy WooCommerce Helper plugin.
|
||||
*/
|
||||
class WC_Helper_Compat {
|
||||
|
||||
/**
|
||||
* Loads the class, runs on init.
|
||||
*/
|
||||
public static function load() {
|
||||
add_action( 'woocommerce_helper_loaded', array( __CLASS__, 'helper_loaded' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs during woocommerce_helper_loaded
|
||||
*/
|
||||
public static function helper_loaded() {
|
||||
// Stop the nagging about WooThemes Updater
|
||||
remove_action( 'admin_notices', 'woothemes_updater_notice' );
|
||||
|
||||
// A placeholder dashboard menu for legacy helper users.
|
||||
add_action( 'admin_menu', array( __CLASS__, 'admin_menu' ) );
|
||||
|
||||
if ( empty( $GLOBALS['woothemes_updater'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::remove_actions();
|
||||
self::migrate_connection();
|
||||
self::deactivate_plugin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove legacy helper actions (notices, menus, etc.)
|
||||
*/
|
||||
public static function remove_actions() {
|
||||
// Remove WooThemes Updater notices
|
||||
remove_action( 'network_admin_notices', array( $GLOBALS['woothemes_updater']->admin, 'maybe_display_activation_notice' ) );
|
||||
remove_action( 'admin_notices', array( $GLOBALS['woothemes_updater']->admin, 'maybe_display_activation_notice' ) );
|
||||
remove_action( 'network_admin_menu', array( $GLOBALS['woothemes_updater']->admin, 'register_settings_screen' ) );
|
||||
remove_action( 'admin_menu', array( $GLOBALS['woothemes_updater']->admin, 'register_settings_screen' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to migrate a legacy connection to a new one.
|
||||
*/
|
||||
public static function migrate_connection() {
|
||||
// Don't attempt to migrate if attempted before.
|
||||
if ( WC_Helper_Options::get( 'did-migrate' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$auth = WC_Helper_Options::get( 'auth' );
|
||||
if ( ! empty( $auth ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
WC_Helper::log( 'Attempting oauth/migrate' );
|
||||
WC_Helper_Options::update( 'did-migrate', true );
|
||||
|
||||
$master_key = get_option( 'woothemes_helper_master_key' );
|
||||
if ( empty( $master_key ) ) {
|
||||
WC_Helper::log( 'Master key not found, aborting' );
|
||||
return;
|
||||
}
|
||||
|
||||
$request = WC_Helper_API::post(
|
||||
'oauth/migrate',
|
||||
array(
|
||||
'body' => array(
|
||||
'home_url' => home_url(),
|
||||
'master_key' => $master_key,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $request ) || wp_remote_retrieve_response_code( $request ) !== 200 ) {
|
||||
WC_Helper::log( 'Call to oauth/migrate returned a non-200 response code' );
|
||||
return;
|
||||
}
|
||||
|
||||
$request_token = json_decode( wp_remote_retrieve_body( $request ) );
|
||||
if ( empty( $request_token ) ) {
|
||||
WC_Helper::log( 'Call to oauth/migrate returned an empty token' );
|
||||
return;
|
||||
}
|
||||
|
||||
// Obtain an access token.
|
||||
$request = WC_Helper_API::post(
|
||||
'oauth/access_token',
|
||||
array(
|
||||
'body' => array(
|
||||
'request_token' => $request_token,
|
||||
'home_url' => home_url(),
|
||||
'migrate' => true,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $request ) || wp_remote_retrieve_response_code( $request ) !== 200 ) {
|
||||
WC_Helper::log( 'Call to oauth/access_token returned a non-200 response code' );
|
||||
return;
|
||||
}
|
||||
|
||||
$access_token = json_decode( wp_remote_retrieve_body( $request ), true );
|
||||
if ( empty( $access_token ) ) {
|
||||
WC_Helper::log( 'Call to oauth/access_token returned an invalid token' );
|
||||
return;
|
||||
}
|
||||
|
||||
WC_Helper_Options::update(
|
||||
'auth',
|
||||
array(
|
||||
'access_token' => $access_token['access_token'],
|
||||
'access_token_secret' => $access_token['access_token_secret'],
|
||||
'site_id' => $access_token['site_id'],
|
||||
'user_id' => null, // Set this later
|
||||
'updated' => time(),
|
||||
)
|
||||
);
|
||||
|
||||
// Obtain the connected user info.
|
||||
if ( ! WC_Helper::_flush_authentication_cache() ) {
|
||||
WC_Helper::log( 'Could not obtain connected user info in migrate_connection' );
|
||||
WC_Helper_Options::update( 'auth', array() );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to deactivate the legacy helper plugin.
|
||||
*/
|
||||
public static function deactivate_plugin() {
|
||||
include_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
if ( ! function_exists( 'deactivate_plugins' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( is_plugin_active( 'woothemes-updater/woothemes-updater.php' ) ) {
|
||||
deactivate_plugins( 'woothemes-updater/woothemes-updater.php' );
|
||||
|
||||
// Notify the user when the plugin is deactivated.
|
||||
add_action( 'pre_current_active_plugins', array( __CLASS__, 'plugin_deactivation_notice' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display admin notice directing the user where to go.
|
||||
*/
|
||||
public static function plugin_deactivation_notice() {
|
||||
?>
|
||||
<div id="message" class="error is-dismissible">
|
||||
<p><?php printf( __( 'The WooCommerce Helper plugin is no longer needed. <a href="%s">Manage subscriptions</a> from the extensions tab instead.', 'woocommerce' ), esc_url( admin_url( 'admin.php?page=wc-addons§ion=helper' ) ) ); ?></p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Register menu item.
|
||||
*/
|
||||
public static function admin_menu() {
|
||||
// No additional menu items for users who did not have a connected helper before.
|
||||
$master_key = get_option( 'woothemes_helper_master_key' );
|
||||
if ( empty( $master_key ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not show the menu item if user has already seen the new screen.
|
||||
$auth = WC_Helper_Options::get( 'auth' );
|
||||
if ( ! empty( $auth['user_id'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_dashboard_page( __( 'WooCommerce Helper', 'woocommerce' ), __( 'WooCommerce Helper', 'woocommerce' ), 'manage_options', 'woothemes-helper', array( __CLASS__, 'render_compat_menu' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the legacy helper compat view.
|
||||
*/
|
||||
public static function render_compat_menu() {
|
||||
$helper_url = add_query_arg(
|
||||
array(
|
||||
'page' => 'wc-addons',
|
||||
'section' => 'helper',
|
||||
), admin_url( 'admin.php' )
|
||||
);
|
||||
include WC_Helper::get_view_filename( 'html-helper-compat.php' );
|
||||
}
|
||||
}
|
||||
|
||||
WC_Helper_Compat::load();
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* WC_Helper_Options Class
|
||||
*
|
||||
* An interface to the woocommerce_helper_data entry in the wp_options table.
|
||||
*/
|
||||
class WC_Helper_Options {
|
||||
/**
|
||||
* The option name used to store the helper data.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private static $option_name = 'woocommerce_helper_data';
|
||||
|
||||
/**
|
||||
* Update an option by key
|
||||
*
|
||||
* All helper options are grouped in a single options entry. This method
|
||||
* is not thread-safe, use with caution.
|
||||
*
|
||||
* @param string $key The key to update.
|
||||
* @param mixed $value The new option value.
|
||||
*
|
||||
* @return bool True if the option has been updated.
|
||||
*/
|
||||
public static function update( $key, $value ) {
|
||||
$options = get_option( self::$option_name, array() );
|
||||
$options[ $key ] = $value;
|
||||
return update_option( self::$option_name, $options, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an option by key
|
||||
*
|
||||
* @see self::update
|
||||
*
|
||||
* @param string $key The key to fetch.
|
||||
* @param mixed $default The default option to return if the key does not exist.
|
||||
*
|
||||
* @return mixed An option or the default.
|
||||
*/
|
||||
public static function get( $key, $default = false ) {
|
||||
$options = get_option( self::$option_name, array() );
|
||||
if ( array_key_exists( $key, $options ) ) {
|
||||
return $options[ $key ];
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* WC_Helper_Plugin_Info Class
|
||||
*
|
||||
* Provides the "View Information" core modals with data for WooCommerce.com
|
||||
* hosted extensions.
|
||||
*/
|
||||
class WC_Helper_Plugin_Info {
|
||||
|
||||
/**
|
||||
* Loads the class, runs on init.
|
||||
*/
|
||||
public static function load() {
|
||||
add_filter( 'plugins_api', array( __CLASS__, 'plugins_api' ), 20, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin information callback for Woo extensions.
|
||||
*
|
||||
* @param object $response The response core needs to display the modal.
|
||||
* @param string $action The requested plugins_api() action.
|
||||
* @param object $args Arguments passed to plugins_api().
|
||||
*
|
||||
* @return object An updated $response.
|
||||
*/
|
||||
public static function plugins_api( $response, $action, $args ) {
|
||||
if ( 'plugin_information' !== $action ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
if ( empty( $args->slug ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
// Only for slugs that start with woo-
|
||||
if ( 0 !== strpos( $args->slug, 'woocommerce-com-' ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$clean_slug = str_replace( 'woocommerce-com-', '', $args->slug );
|
||||
|
||||
// Look through update data by slug.
|
||||
$update_data = WC_Helper_Updater::get_update_data();
|
||||
$products = wp_list_filter( $update_data, array( 'slug' => $clean_slug ) );
|
||||
|
||||
if ( empty( $products ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$product_id = array_keys( $products );
|
||||
$product_id = array_shift( $product_id );
|
||||
|
||||
// Fetch the product information from the Helper API.
|
||||
$request = WC_Helper_API::get(
|
||||
add_query_arg(
|
||||
array(
|
||||
'product_id' => absint( $product_id ),
|
||||
), 'info'
|
||||
), array( 'authenticated' => true )
|
||||
);
|
||||
|
||||
$results = json_decode( wp_remote_retrieve_body( $request ), true );
|
||||
if ( ! empty( $results ) ) {
|
||||
$response = (object) $results;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
WC_Helper_Plugin_Info::load();
|
||||
@@ -0,0 +1,322 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* WC_Helper_Updater Class
|
||||
*
|
||||
* Contains the logic to fetch available updates and hook into Core's update
|
||||
* routines to serve WooCommerce.com-provided packages.
|
||||
*/
|
||||
class WC_Helper_Updater {
|
||||
|
||||
/**
|
||||
* Loads the class, runs on init.
|
||||
*/
|
||||
public static function load() {
|
||||
add_action( 'pre_set_site_transient_update_plugins', array( __CLASS__, 'transient_update_plugins' ), 21, 1 );
|
||||
add_action( 'pre_set_site_transient_update_themes', array( __CLASS__, 'transient_update_themes' ), 21, 1 );
|
||||
add_action( 'upgrader_process_complete', array( __CLASS__, 'upgrader_process_complete' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs in a cron thread, or in a visitor thread if triggered
|
||||
* by _maybe_update_plugins(), or in an auto-update thread.
|
||||
*
|
||||
* @param object $transient The update_plugins transient object.
|
||||
*
|
||||
* @return object The same or a modified version of the transient.
|
||||
*/
|
||||
public static function transient_update_plugins( $transient ) {
|
||||
$update_data = self::get_update_data();
|
||||
|
||||
foreach ( WC_Helper::get_local_woo_plugins() as $plugin ) {
|
||||
if ( empty( $update_data[ $plugin['_product_id'] ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$data = $update_data[ $plugin['_product_id'] ];
|
||||
$filename = $plugin['_filename'];
|
||||
|
||||
$item = array(
|
||||
'id' => 'woocommerce-com-' . $plugin['_product_id'],
|
||||
'slug' => 'woocommerce-com-' . $data['slug'],
|
||||
'plugin' => $filename,
|
||||
'new_version' => $data['version'],
|
||||
'url' => $data['url'],
|
||||
'package' => '',
|
||||
'upgrade_notice' => $data['upgrade_notice'],
|
||||
);
|
||||
|
||||
if ( self::_has_active_subscription( $plugin['_product_id'] ) ) {
|
||||
$item['package'] = $data['package'];
|
||||
}
|
||||
|
||||
if ( version_compare( $plugin['Version'], $data['version'], '<' ) ) {
|
||||
$transient->response[ $filename ] = (object) $item;
|
||||
unset( $transient->no_update[ $filename ] );
|
||||
} else {
|
||||
$transient->no_update[ $filename ] = (object) $item;
|
||||
unset( $transient->response[ $filename ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $transient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs on pre_set_site_transient_update_themes, provides custom
|
||||
* packages for WooCommerce.com-hosted extensions.
|
||||
*
|
||||
* @param object $transient The update_themes transient object.
|
||||
*
|
||||
* @return object The same or a modified version of the transient.
|
||||
*/
|
||||
public static function transient_update_themes( $transient ) {
|
||||
$update_data = self::get_update_data();
|
||||
|
||||
foreach ( WC_Helper::get_local_woo_themes() as $theme ) {
|
||||
if ( empty( $update_data[ $theme['_product_id'] ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$data = $update_data[ $theme['_product_id'] ];
|
||||
$slug = $theme['_stylesheet'];
|
||||
|
||||
$item = array(
|
||||
'theme' => $slug,
|
||||
'new_version' => $data['version'],
|
||||
'url' => $data['url'],
|
||||
'package' => '',
|
||||
);
|
||||
|
||||
if ( self::_has_active_subscription( $theme['_product_id'] ) ) {
|
||||
$item['package'] = $data['package'];
|
||||
}
|
||||
|
||||
if ( version_compare( $theme['Version'], $data['version'], '<' ) ) {
|
||||
$transient->response[ $slug ] = $item;
|
||||
} else {
|
||||
unset( $transient->response[ $slug ] );
|
||||
$transient->checked[ $slug ] = $data['version'];
|
||||
}
|
||||
}
|
||||
|
||||
return $transient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get update data for all extensions.
|
||||
*
|
||||
* Scans through all subscriptions for the connected user, as well
|
||||
* as all Woo extensions without a subscription, and obtains update
|
||||
* data for each product.
|
||||
*
|
||||
* @return array Update data {product_id => data}
|
||||
*/
|
||||
public static function get_update_data() {
|
||||
$payload = array();
|
||||
|
||||
// Scan subscriptions.
|
||||
foreach ( WC_Helper::get_subscriptions() as $subscription ) {
|
||||
$payload[ $subscription['product_id'] ] = array(
|
||||
'product_id' => $subscription['product_id'],
|
||||
'file_id' => '',
|
||||
);
|
||||
}
|
||||
|
||||
// Scan local plugins which may or may not have a subscription.
|
||||
foreach ( WC_Helper::get_local_woo_plugins() as $data ) {
|
||||
if ( ! isset( $payload[ $data['_product_id'] ] ) ) {
|
||||
$payload[ $data['_product_id'] ] = array(
|
||||
'product_id' => $data['_product_id'],
|
||||
);
|
||||
}
|
||||
|
||||
$payload[ $data['_product_id'] ]['file_id'] = $data['_file_id'];
|
||||
}
|
||||
|
||||
// Scan local themes
|
||||
foreach ( WC_Helper::get_local_woo_themes() as $data ) {
|
||||
if ( ! isset( $payload[ $data['_product_id'] ] ) ) {
|
||||
$payload[ $data['_product_id'] ] = array(
|
||||
'product_id' => $data['_product_id'],
|
||||
);
|
||||
}
|
||||
|
||||
$payload[ $data['_product_id'] ]['file_id'] = $data['_file_id'];
|
||||
}
|
||||
|
||||
return self::_update_check( $payload );
|
||||
}
|
||||
|
||||
/**
|
||||
* Run an update check API call.
|
||||
*
|
||||
* The call is cached based on the payload (product ids, file ids). If
|
||||
* the payload changes, the cache is going to miss.
|
||||
*
|
||||
* @return array Update data for each requested product.
|
||||
*/
|
||||
private static function _update_check( $payload ) {
|
||||
ksort( $payload );
|
||||
$hash = md5( wp_json_encode( $payload ) );
|
||||
|
||||
$cache_key = '_woocommerce_helper_updates';
|
||||
if ( false !== ( $data = get_transient( $cache_key ) ) ) {
|
||||
if ( hash_equals( $hash, $data['hash'] ) ) {
|
||||
return $data['products'];
|
||||
}
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'hash' => $hash,
|
||||
'updated' => time(),
|
||||
'products' => array(),
|
||||
'errors' => array(),
|
||||
);
|
||||
|
||||
$request = WC_Helper_API::post(
|
||||
'update-check', array(
|
||||
'body' => wp_json_encode( array( 'products' => $payload ) ),
|
||||
'authenticated' => true,
|
||||
)
|
||||
);
|
||||
|
||||
if ( wp_remote_retrieve_response_code( $request ) !== 200 ) {
|
||||
$data['errors'][] = 'http-error';
|
||||
} else {
|
||||
$data['products'] = json_decode( wp_remote_retrieve_body( $request ), true );
|
||||
}
|
||||
|
||||
set_transient( $cache_key, $data, 12 * HOUR_IN_SECONDS );
|
||||
return $data['products'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for an active subscription.
|
||||
*
|
||||
* Checks a given product id against all subscriptions on
|
||||
* the current site. Returns true if at least one active
|
||||
* subscription is found.
|
||||
*
|
||||
* @param int $product_id The product id to look for.
|
||||
*
|
||||
* @return bool True if active subscription found.
|
||||
*/
|
||||
private static function _has_active_subscription( $product_id ) {
|
||||
if ( ! isset( $auth ) ) {
|
||||
$auth = WC_Helper_Options::get( 'auth' );
|
||||
}
|
||||
|
||||
if ( ! isset( $subscriptions ) ) {
|
||||
$subscriptions = WC_Helper::get_subscriptions();
|
||||
}
|
||||
|
||||
if ( empty( $auth['site_id'] ) || empty( $subscriptions ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for an active subscription.
|
||||
foreach ( $subscriptions as $subscription ) {
|
||||
if ( $subscription['product_id'] != $product_id ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( in_array( absint( $auth['site_id'] ), $subscription['connections'] ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of products that have updates.
|
||||
*
|
||||
* @return int The number of products with updates.
|
||||
*/
|
||||
public static function get_updates_count() {
|
||||
$cache_key = '_woocommerce_helper_updates_count';
|
||||
if ( false !== ( $count = get_transient( $cache_key ) ) ) {
|
||||
return $count;
|
||||
}
|
||||
|
||||
// Don't fetch any new data since this function in high-frequency.
|
||||
if ( ! get_transient( '_woocommerce_helper_subscriptions' ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( ! get_transient( '_woocommerce_helper_updates' ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
$update_data = self::get_update_data();
|
||||
|
||||
if ( empty( $update_data ) ) {
|
||||
set_transient( $cache_key, $count, 12 * HOUR_IN_SECONDS );
|
||||
return $count;
|
||||
}
|
||||
|
||||
// Scan local plugins.
|
||||
foreach ( WC_Helper::get_local_woo_plugins() as $plugin ) {
|
||||
if ( empty( $update_data[ $plugin['_product_id'] ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( version_compare( $plugin['Version'], $update_data[ $plugin['_product_id'] ]['version'], '<' ) ) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Scan local themes.
|
||||
foreach ( WC_Helper::get_local_woo_themes() as $theme ) {
|
||||
if ( empty( $update_data[ $theme['_product_id'] ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( version_compare( $theme['Version'], $update_data[ $theme['_product_id'] ]['version'], '<' ) ) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
set_transient( $cache_key, $count, 12 * HOUR_IN_SECONDS );
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the updates count markup.
|
||||
*
|
||||
* @return string Updates count markup, empty string if no updates avairable.
|
||||
*/
|
||||
public static function get_updates_count_html() {
|
||||
$count = self::get_updates_count();
|
||||
if ( ! $count ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$count_html = sprintf( '<span class="update-plugins count-%d"><span class="update-count">%d</span></span>', $count, number_format_i18n( $count ) );
|
||||
return $count_html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes cached update data.
|
||||
*/
|
||||
public static function flush_updates_cache() {
|
||||
delete_transient( '_woocommerce_helper_updates' );
|
||||
delete_transient( '_woocommerce_helper_updates_count' );
|
||||
delete_site_transient( 'update_plugins' );
|
||||
delete_site_transient( 'update_themes' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires when a user successfully updated a theme or a plugin.
|
||||
*/
|
||||
public static function upgrader_process_complete() {
|
||||
delete_transient( '_woocommerce_helper_updates_count' );
|
||||
}
|
||||
}
|
||||
|
||||
WC_Helper_Updater::load();
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
||||
<?php defined( 'ABSPATH' ) or exit(); ?>
|
||||
|
||||
<div class="wrap">
|
||||
<h1><?php _e( 'Looking for the WooCommerce Helper?', 'woocommerce' ); ?></h1>
|
||||
<p><?php printf( __( 'We\'ve made things simpler and easier to manage moving forward. From now on you can manage all your WooCommerce purchases directly from the Extensions menu within the WooCommerce plugin itself. <a href="%s">View and manage</a> your extensions now.', 'woocommerce' ), esc_url( $helper_url ) ); ?></p>
|
||||
</div>
|
||||
@@ -0,0 +1,214 @@
|
||||
<?php defined( 'ABSPATH' ) or exit(); ?>
|
||||
|
||||
<div class="wrap woocommerce wc_addons_wrap wc-helper">
|
||||
<?php require WC_Helper::get_view_filename( 'html-section-nav.php' ); ?>
|
||||
<h1 class="screen-reader-text"><?php _e( 'WooCommerce Extensions', 'woocommerce' ); ?></h1>
|
||||
|
||||
<?php require WC_Helper::get_view_filename( 'html-section-notices.php' ); ?>
|
||||
|
||||
<div class="subscriptions-header">
|
||||
<h2><?php _e( 'Subscriptions', 'woocommerce' ); ?></h2>
|
||||
<?php require WC_Helper::get_view_filename( 'html-section-account.php' ); ?>
|
||||
<p><?php printf( __( 'Below is a list of extensions available on your WooCommerce.com account. To receive extension updates please make sure the extension is installed, and its subscription activated and connected to your WooCommerce.com account. Extensions can be activated from the <a href="%s">Plugins</a> screen.', 'woocommerce' ), admin_url( 'plugins.php' ) ); ?></p>
|
||||
</div>
|
||||
|
||||
<ul class="subscription-filter">
|
||||
<label><?php _e( 'Sort by:', 'woocommerce' ); ?> <span class="chevron dashicons dashicons-arrow-up-alt2"></span></label>
|
||||
<?php
|
||||
$filters = array_keys( WC_Helper::get_filters() );
|
||||
$last_filter = array_pop( $filters );
|
||||
$current_filter = WC_Helper::get_current_filter();
|
||||
$counts = WC_Helper::get_filters_counts();
|
||||
?>
|
||||
|
||||
<?php
|
||||
foreach ( WC_Helper::get_filters() as $key => $label ) :
|
||||
// Don't show empty filters.
|
||||
if ( empty( $counts[ $key ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$url = admin_url( 'admin.php?page=wc-addons§ion=helper&filter=' . $key );
|
||||
$class_html = $current_filter === $key ? 'class="current"' : '';
|
||||
?>
|
||||
<li>
|
||||
<a <?php echo $class_html; ?> href="<?php echo esc_url( $url ); ?>">
|
||||
<?php echo esc_html( $label ); ?>
|
||||
<span class="count">(<?php echo absint( $counts[ $key ] ); ?>)</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<?php if ( ! empty( $subscriptions ) ) : ?>
|
||||
<?php foreach ( $subscriptions as $subscription ) : ?>
|
||||
<tbody>
|
||||
<tr class="wp-list-table__row is-ext-header">
|
||||
<td class="wp-list-table__ext-details">
|
||||
<div class="wp-list-table__ext-title">
|
||||
<a href="<?php echo esc_url( $subscription['product_url'] ); ?>" target="_blank">
|
||||
<?php echo esc_html( $subscription['product_name'] ); ?>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="wp-list-table__ext-description">
|
||||
<?php if ( $subscription['lifetime'] ) : ?>
|
||||
<span class="renews">
|
||||
<?php _e( 'Lifetime Subscription', 'woocommerce' ); ?>
|
||||
</span>
|
||||
<?php elseif ( $subscription['expired'] ) : ?>
|
||||
<span class="renews">
|
||||
<strong><?php _e( 'Expired :(', 'woocommerce' ); ?></strong>
|
||||
<?php echo date_i18n( 'F jS, Y', $subscription['expires'] ); ?>
|
||||
</span>
|
||||
<?php elseif ( $subscription['autorenew'] ) : ?>
|
||||
<span class="renews">
|
||||
<?php _e( 'Auto renews on:', 'woocommerce' ); ?>
|
||||
<?php echo date_i18n( 'F jS, Y', $subscription['expires'] ); ?>
|
||||
</span>
|
||||
<?php elseif ( $subscription['expiring'] ) : ?>
|
||||
<span class="renews">
|
||||
<strong><?php _e( 'Expiring soon!', 'woocommerce' ); ?></strong>
|
||||
<?php echo date_i18n( 'F jS, Y', $subscription['expires'] ); ?>
|
||||
</span>
|
||||
<?php else : ?>
|
||||
<span class="renews">
|
||||
<?php _e( 'Expires on:', 'woocommerce' ); ?>
|
||||
<?php echo date_i18n( 'F jS, Y', $subscription['expires'] ); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
|
||||
<br/>
|
||||
<span class="subscription">
|
||||
<?php
|
||||
if ( ! $subscription['active'] && $subscription['maxed'] ) {
|
||||
/* translators: %1$d: sites active, %2$d max sites active */
|
||||
printf( __( 'Subscription: Not available - %1$d of %2$d already in use', 'woocommerce' ), absint( $subscription['sites_active'] ), absint( $subscription['sites_max'] ) );
|
||||
} elseif ( $subscription['sites_max'] > 0 ) {
|
||||
/* translators: %1$d: sites active, %2$d max sites active */
|
||||
printf( __( 'Subscription: Using %1$d of %2$d sites available', 'woocommerce' ), absint( $subscription['sites_active'] ), absint( $subscription['sites_max'] ) );
|
||||
} else {
|
||||
_e( 'Subscription: Unlimited', 'woocommerce' );
|
||||
}
|
||||
|
||||
// Check shared.
|
||||
if ( ! empty( $subscription['is_shared'] ) && ! empty( $subscription['owner_email'] ) ) {
|
||||
printf( '</br>' . __( 'Shared by %s', 'woocommerce' ), esc_html( $subscription['owner_email'] ) );
|
||||
} elseif ( isset( $subscription['master_user_email'] ) ) {
|
||||
printf( '</br>' . __( 'Shared by %s', 'woocommerce' ), esc_html( $subscription['master_user_email'] ) );
|
||||
}
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="wp-list-table__ext-actions">
|
||||
<?php if ( ! $subscription['active'] && $subscription['maxed'] ) : ?>
|
||||
<a class="button" href="https://woocommerce.com/my-account/my-subscriptions/" target="_blank"><?php _e( 'Upgrade', 'woocommerce' ); ?></a>
|
||||
<?php elseif ( ! $subscription['local']['installed'] && ! $subscription['expired'] ) : ?>
|
||||
<a class="button <?php echo empty( $subscription['download_primary'] ) ? 'button-secondary' : ''; ?>" href="<?php echo esc_url( $subscription['download_url'] ); ?>" target="_blank"><?php _e( 'Download', 'woocommerce' ); ?></a>
|
||||
<?php elseif ( $subscription['active'] ) : ?>
|
||||
<span class="form-toggle__wrapper">
|
||||
<a href="<?php echo esc_url( $subscription['deactivate_url'] ); ?>" class="form-toggle active is-compact" role="link" aria-checked="true"><?php _e( 'Active', 'woocommerce' ); ?></a>
|
||||
<label class="form-toggle__label" for="activate-extension">
|
||||
<span class="form-toggle__label-content">
|
||||
<label for="activate-extension"><?php _e( 'Active', 'woocommerce' ); ?></label>
|
||||
</span>
|
||||
<span class="form-toggle__switch"></span>
|
||||
</label>
|
||||
</span>
|
||||
<?php elseif ( ! $subscription['expired'] ) : ?>
|
||||
<span class="form-toggle__wrapper">
|
||||
<a href="<?php echo esc_url( $subscription['activate_url'] ); ?>" class="form-toggle is-compact" role="link" aria-checked="false"><?php _e( 'Inactive', 'woocommerce' ); ?></a>
|
||||
<label class="form-toggle__label" for="activate-extension">
|
||||
<span class="form-toggle__label-content">
|
||||
<label for="activate-extension"><?php _e( 'Inactive', 'woocommerce' ); ?></label>
|
||||
</span>
|
||||
<span class="form-toggle__switch"></span>
|
||||
</label>
|
||||
</span>
|
||||
<?php else : ?>
|
||||
<span class="form-toggle__wrapper">
|
||||
<span class="form-toggle disabled is-compact"><?php _e( 'Inactive', 'woocommerce' ); ?></span>
|
||||
<label class="form-toggle__label" for="activate-extension">
|
||||
<span class="form-toggle__label-content">
|
||||
<label for="activate-extension"><?php _e( 'Inactive', 'woocommerce' ); ?></label>
|
||||
</span>
|
||||
</label>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<?php foreach ( $subscription['actions'] as $action ) : ?>
|
||||
<tr class="wp-list-table__row wp-list-table__ext-updates">
|
||||
<td class="wp-list-table__ext-status <?php echo sanitize_html_class( $action['status'] ); ?>">
|
||||
<p><span class="dashicons <?php echo sanitize_html_class( $action['icon'] ); ?>"></span>
|
||||
<?php echo $action['message']; ?>
|
||||
</p>
|
||||
</td>
|
||||
<td class="wp-list-table__ext-actions">
|
||||
<?php if ( ! empty( $action['button_label'] ) && ! empty( $action['button_url'] ) ) : ?>
|
||||
<a class="button <?php echo empty( $action['primary'] ) ? 'button-secondary' : ''; ?>" href="<?php echo esc_url( $action['button_url'] ); ?>"><?php echo esc_html( $action['button_label'] ); ?></a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
||||
</tbody>
|
||||
<?php endforeach; ?>
|
||||
<?php else : ?>
|
||||
<tr>
|
||||
<td colspan="3"><em><?php _e( 'Could not find any subscriptions on your WooCommerce.com account', 'woocommerce' ); ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php if ( ! empty( $no_subscriptions ) ) : ?>
|
||||
<h2><?php _e( 'Installed Extensions without a Subscription', 'woocommerce' ); ?></h2>
|
||||
<p>Below is a list of WooCommerce.com products available on your site - but are either out-dated or do not have a valid subscription.</p>
|
||||
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<?php /* Extensions without a subscription. */ ?>
|
||||
<?php foreach ( $no_subscriptions as $filename => $data ) : ?>
|
||||
<tbody>
|
||||
<tr class="wp-list-table__row is-ext-header">
|
||||
<td class="wp-list-table__ext-details color-bar autorenews">
|
||||
<div class="wp-list-table__ext-title">
|
||||
<a href="<?php echo esc_url( $data['_product_url'] ); ?>" target="_blank"><?php echo esc_html( $data['Name'] ); ?></a>
|
||||
</div>
|
||||
<div class="wp-list-table__ext-description">
|
||||
</div>
|
||||
</td>
|
||||
<td class="wp-list-table__ext-actions">
|
||||
<span class="form-toggle__wrapper">
|
||||
<span class="form-toggle disabled is-compact" ><?php _e( 'Inactive', 'woocommerce' ); ?></span>
|
||||
<label class="form-toggle__label" for="activate-extension">
|
||||
<span class="form-toggle__label-content">
|
||||
<label for="activate-extension"><?php _e( 'Inactive', 'woocommerce' ); ?></label>
|
||||
</span>
|
||||
</label>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<?php foreach ( $data['_actions'] as $action ) : ?>
|
||||
<tr class="wp-list-table__row wp-list-table__ext-updates">
|
||||
<td class="wp-list-table__ext-status <?php echo sanitize_html_class( $action['status'] ); ?>">
|
||||
<p><span class="dashicons <?php echo sanitize_html_class( $action['icon'] ); ?>"></span>
|
||||
<?php echo $action['message']; ?>
|
||||
</p>
|
||||
</td>
|
||||
<td class="wp-list-table__ext-actions">
|
||||
<a class="button" href="<?php echo esc_url( $action['button_url'] ); ?>" target="_blank"><?php echo esc_html( $action['button_label'] ); ?></a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
||||
</tbody>
|
||||
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* Admin -> WooCommerce -> Extensions -> WooCommerce.com Subscriptions main page.
|
||||
*
|
||||
* @package WooCommerce\Views
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit();
|
||||
|
||||
?>
|
||||
|
||||
<div class="wrap woocommerce wc_addons_wrap wc-helper">
|
||||
<?php require WC_Helper::get_view_filename( 'html-section-nav.php' ); ?>
|
||||
<h1 class="screen-reader-text"><?php esc_html_e( 'WooCommerce Extensions', 'woocommerce' ); ?></h1>
|
||||
<?php require WC_Helper::get_view_filename( 'html-section-notices.php' ); ?>
|
||||
|
||||
<div class="start-container">
|
||||
<div class="text">
|
||||
<img src="<?php echo esc_url( WC()->plugin_url() . '/assets/images/woocommerce_logo.png' ); ?>" alt="<?php esc_attr_e( 'WooCommerce', 'woocommerce' ); ?>" style="width:180px;">
|
||||
|
||||
<?php if ( ! empty( $_GET['wc-helper-status'] ) && 'helper-disconnected' === $_GET['wc-helper-status'] ) : ?>
|
||||
<p><strong><?php esc_html_e( 'Sorry to see you go.', 'woocommerce' ); ?></strong> <?php esc_html_e( 'Feel free to reconnect again using the button below.', 'woocommerce' ); ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<h2><?php esc_html_e( 'Manage your subscriptions, get important product notifications, and updates, all from the convenience of your WooCommerce dashboard', 'woocommerce' ); ?></h2>
|
||||
<p><?php esc_html_e( 'Once connected, your WooCommerce.com purchases will be listed here.', 'woocommerce' ); ?></p>
|
||||
<p><a class="button button-primary button-helper-connect" href="<?php echo esc_url( $connect_url ); ?>"><?php esc_html_e( 'Connect', 'woocommerce' ); ?></a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php defined( 'ABSPATH' ) or exit(); ?>
|
||||
|
||||
<a class="button button-update" href="<?php echo esc_url( $refresh_url ); ?>"><span class="dashicons dashicons-image-rotate"></span> <?php _e( 'Update', 'woocommerce' ); ?></a>
|
||||
<div class="user-info">
|
||||
<header>
|
||||
<p><?php printf( __( 'Connected to WooCommerce.com', 'woocommerce' ) ); ?> <span class="chevron dashicons dashicons-arrow-down-alt2"></span></p>
|
||||
</header>
|
||||
<section>
|
||||
<p><?php echo get_avatar( $auth_user_data['email'], 48 ); ?> <?php echo esc_html( $auth_user_data['email'] ); ?></p>
|
||||
<div class="actions">
|
||||
<a class="" href="https://woocommerce.com/my-account/my-subscriptions/" target="_blank"><span class="dashicons dashicons-admin-generic"></span> <?php _e( 'My Subscriptions', 'woocommerce' ); ?></a>
|
||||
<a class="" href="<?php echo esc_url( $disconnect_url ); ?>"><span class="dashicons dashicons-no"></span> <?php _e( 'Disconnect', 'woocommerce' ); ?></a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
/**
|
||||
* Helper admin navigation.
|
||||
*
|
||||
* @package WooCommerce/Helper
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit(); ?>
|
||||
|
||||
<nav class="nav-tab-wrapper woo-nav-tab-wrapper">
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-addons' ) ); ?>" class="nav-tab"><?php esc_html_e( 'Browse Extensions', 'woocommerce' ); ?></a>
|
||||
|
||||
<?php
|
||||
$count_html = WC_Helper_Updater::get_updates_count_html();
|
||||
/* translators: %s: WooCommerce.com Subscriptions tab count HTML. */
|
||||
$menu_title = sprintf( __( 'WooCommerce.com Subscriptions %s', 'woocommerce' ), $count_html );
|
||||
?>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-addons§ion=helper' ) ); ?>" class="nav-tab nav-tab-active"><?php echo wp_kses_post( $menu_title ); ?></a>
|
||||
</nav>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php defined( 'ABSPATH' ) or exit(); ?>
|
||||
|
||||
<?php foreach ( $notices as $notice ) : ?>
|
||||
<div class="notice <?php echo sanitize_html_class( $notice['type'] ); ?>">
|
||||
<?php echo wpautop( $notice['message'] ); ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
Reference in New Issue
Block a user