Skip to content

Commit

Permalink
Merge pull request #2344 from the-events-calendar/bucket/Help_Hub-FF
Browse files Browse the repository at this point in the history
Help Hub FF into Imp
  • Loading branch information
redscar authored Jan 9, 2025
2 parents e51748b + 78bd5a6 commit 5fc31e3
Show file tree
Hide file tree
Showing 8 changed files with 559 additions and 178 deletions.
4 changes: 4 additions & 0 deletions changelog/tweak-TEC-5332_transients
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: tweak

When installing new plugins `TEC_IS_ANY_LICENSE_VALID_TRANSIENT` will update correctly. [TEC-5332]
22 changes: 14 additions & 8 deletions src/Common/Admin/Help_Hub/Hub.php
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,10 @@ public function generate_iframe_content(): void {
* @return void
*/
public function register_iframe_hooks() {
add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_help_page_iframe_assets' ] );
add_action( 'wp_enqueue_scripts', [ __CLASS__, 'dequeue_theme_styles' ] );
add_action( 'tec_help_hub_iframe_header', [ $this, 'enqueue_help_page_iframe_assets' ] );
add_filter( 'emoji_svg_url', '__return_false' );
remove_action( 'wp_print_styles', 'print_emoji_styles' );
remove_action( 'wp_head', 'print_emoji_styles' );
}

/**
Expand All @@ -443,18 +445,18 @@ public function enqueue_help_page_iframe_assets(): void {

tribe_asset(
Tribe__Main::instance(),
'help-hub-iframe-style',
'tec-help-hub-iframe-style',
'help-hub-iframe.css',
null,
'wp_enqueue_scripts'
[],
[],
);

tribe_asset(
Tribe__Main::instance(),
'help-hub-iframe-js',
'tec-help-hub-iframe-js',
'admin/help-hub-iframe.js',
null,
'wp_enqueue_scripts',
[],
[],
[
'localize' => [
'name' => 'helpHubSettings',
Expand All @@ -465,6 +467,10 @@ public function enqueue_help_page_iframe_assets(): void {
],
]
);

tribe_asset_enqueue( 'tec-help-hub-iframe-style' );
tribe_asset_enqueue( 'tec-help-hub-iframe-js' );
tribe_asset_enqueue( 'tribe-common-full-style' );
}

/**
Expand Down
216 changes: 180 additions & 36 deletions src/Tribe/PUE/Checker.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
* @todo switch all plugins over to use the PUE utilities here in Commons
*/

use TEC\Common\StellarWP\Uplink\Config;

use function TEC\Common\StellarWP\Uplink\get_resource;

// Don't load directly.
Expand Down Expand Up @@ -220,21 +222,50 @@ public function __construct( $pue_update_url, $slug = '', $options = [], $plugin
$this->set_options( $options );
$this->hooks();
$this->set_key_status_name();
$this->init( $slug );
// So we can reference our "registered" instances later.
self::$instances[ $slug ] ??= $this;
}

/**
* Initializes the PUE checker and fires the appropriate action if not already initialized.
*
* This method ensures that the `tec_pue_checker_init` action is fired only once per unique slug.
*
* @since TBD
*
* @param string $slug The unique slug for the plugin being initialized.
*/
public function init( $slug ) {
if ( isset( self::$instances[ $slug ] ) ) {
return;
}

/**
* Fires when initializing the PUE checker.
*
* @since TBD
*
* @param Tribe__PUE__Checker $checker An instance of the PUE Checker being initialized.
*/
do_action( 'tec_pue_checker_init', $this );
}

/**
* Gets whether the license key is valid or not.
*
* @since 4.14.9
* @since 6.4.1 Added uplink resource check.
* @since TBD Added check for valid plugin.
*/
public function is_key_valid() {
$uplink_resource = get_resource( $this->get_slug() );
$uplink_resource = $this->get_uplink_resource( $this->get_slug() );

if ( $uplink_resource ) {
return $uplink_resource->has_valid_license();
$uplink_status = $uplink_resource->has_valid_license();
$this->update_any_license_valid_transient( $this->get_slug(), tribe_is_truthy( $uplink_status ) );

return $uplink_status;
}

// @todo remove transient in a major feature release where we release all plugins.
Expand All @@ -244,58 +275,100 @@ public function is_key_valid() {
$status = get_option( $this->pue_key_status_option_name, 'invalid' );
}

$this->update_any_license_valid_transient( $this->get_slug(), 'valid' === $status );

return 'valid' === $status;
}

/**
* Helper function to check the transient structure and if any plugin is valid.
*
* @since TBD
*
* @param array|null $transient_value The current transient value.
*
* @return bool True if a valid license is found, otherwise false.
*/
protected static function transient_contains_valid_license( ?array $transient_value ): bool {
if ( ! is_array( $transient_value ) || ! isset( $transient_value['plugins'] ) ) {
return false;
}

return in_array( true, $transient_value['plugins'] );
}

/**
* Updates the license status in the global transient.
*
* @since TBD
*
* @param string $plugin_slug The slug of the plugin being updated.
* @param bool $status The license status.
*/
protected static function update_any_license_valid_transient( string $plugin_slug, bool $status ): void {
$transient_value = get_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY ) ?: [ 'plugins' => [] ];

// If the transient value is false or a string, initialize it as an empty array with the 'plugins' key.
if ( ! is_array( $transient_value ) ) {
$transient_value = [ 'plugins' => [] ];
}

$transient_value['plugins'][ $plugin_slug ] = $status;

set_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY, $transient_value, HOUR_IN_SECONDS );
}

/**
* Iterate on all the registered PUE Product Licenses we have and find if any are valid.
* Will revalidate the licenses if none are found to be valid.
*
* @todo In scenarios where a user goes from a Free license to an active license the transient may give a false positive.
*
* @since 6.3.2
* @since TBD Refactored logic to account for the transient structure.
*
* @return bool
*/
public static function is_any_license_valid(): bool {
$valid_slug = 'valid';
$has_valid = false;

// Check our transient.
$transient_value = get_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY );
if ( ! empty( $transient_value ) ) {
return $transient_value === $valid_slug;

if ( ! is_array( $transient_value ) ) {
$transient_value = [];
}

// Check our local transient/cache first.
foreach ( self::$instances as $checker ) {
if ( $checker->is_key_valid() ) {
set_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY, $valid_slug, HOUR_IN_SECONDS );
$has_valid = true;
break;
}
// Check if the transient has a valid license.
if ( self::transient_contains_valid_license( $transient_value ) ) {
return true;
}

if ( ! $has_valid ) {
// Revalidate if we haven't found a valid license yet.
foreach ( self::$instances as $checker ) {
$license = get_option( $checker->get_license_option_key() );
$response = $checker->validate_key( $license );
// Is it valid?
if ( ! empty( $response['status'] ) ) {
set_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY, $valid_slug, HOUR_IN_SECONDS );
$has_valid = true;
break;
}
}
// Ensure instances exist.
if ( empty( self::$instances ) ) {
set_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY, [ 'plugins' => [] ], HOUR_IN_SECONDS );

return false;
}

// We found no valid licenses above.
if ( ! $has_valid ) {
set_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY, 'invalid', HOUR_IN_SECONDS );
// Revalidate licenses.
foreach ( self::$instances as $plugin_slug => $checker ) {
// First, check if the key is already valid.
if ( $checker->is_key_valid() ) {
self::update_any_license_valid_transient( $plugin_slug, true );

return true;
}

// If not valid, attempt to revalidate the license.
$license = get_option( $checker->get_license_option_key() );
$response = $checker->validate_key( $license );

if ( ! empty( $response['status'] ) ) {
self::update_any_license_valid_transient( $plugin_slug, true );

return true;
} else {
self::update_any_license_valid_transient( $plugin_slug, false );
}
}

return get_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY ) === $valid_slug;
return false;
}

/**
Expand Down Expand Up @@ -341,6 +414,7 @@ public function set_key_status_transient_name() {
* Sets the key status based on the key validation check results.
*
* @since 4.14.9
* @since TBD Clear `self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY` when a key is checked.
*
* @param int $valid 0 for invalid, 1 or 2 for valid.
*/
Expand All @@ -352,6 +426,9 @@ public function set_key_status( $valid ) {
// We set a transient in addition to an option for compatibility reasons.
// @todo remove transient in a major feature release where we release all plugins.
set_transient( $this->pue_key_status_transient_name, $status, $this->check_period * HOUR_IN_SECONDS );

// Update the global license transient.
self::update_any_license_valid_transient( $this->get_slug(), tribe_is_truthy( $valid ) );
}

/**
Expand All @@ -369,7 +446,7 @@ public function set_key_status_transient( $valid ) {
/**
* Install the hooks required to run periodic update checks and inject update info
* into WP data structures.
* Also other hooks related to the automatic updates (such as checking agains API and what not (@from Darren)
* Also other hooks related to the automatic updates (such as checking against API and what not (@from Darren)
*/
public function hooks() {
// Override requests for plugin information.
Expand Down Expand Up @@ -397,6 +474,9 @@ public function hooks() {

// Package name.
add_filter( 'upgrader_pre_download', [ Tribe__PUE__Package_Handler::instance(), 'filter_upgrader_pre_download' ], 5, 3 );

add_action( 'admin_init', [ $this, 'monitor_uplink_actions' ], 1000 );
add_action( 'tec_pue_checker_init', [ __CLASS__, 'monitor_active_plugins' ] );
}


Expand Down Expand Up @@ -1014,7 +1094,7 @@ public function get_stats() {
*/
public function get_key( $type = 'any', $return_type = 'key' ) {

$resource = get_resource( $this->get_slug() );
$resource = $this->get_uplink_resource( $this->get_slug() );
$license_key = $resource ? $resource->get_license_key( $type ) : false;
if ( $license_key ) {
return $license_key;
Expand Down Expand Up @@ -1105,7 +1185,7 @@ public function validate_key( $key, $network = false ) {
$response = [];
$response['status'] = 0;

$uplink_resource = get_resource( $this->get_slug() );
$uplink_resource = $this->get_uplink_resource( $this->get_slug() );

if ( $uplink_resource ) {
$key = $uplink_resource->get_license_key();
Expand Down Expand Up @@ -2090,5 +2170,69 @@ public function is_valid_key_format() {

return true;
}

/**
* Hooks into the Uplink plugin's 'connected' action for the current plugin.
*
* This method registers a callback for the 'stellarwp/uplink/{slug}/connected' action.
* When the action is triggered, it updates the license validity transient for the plugin.
*
* @since TBD
*
* @return void
*/
public static function monitor_uplink_actions(): void {
// Hook into the existing 'connected' action for the specific plugin slug.
add_action(
'stellarwp/uplink/' . Config::get_hook_prefix() . '/connected',
function ( $plugin ) {
self::update_any_license_valid_transient( $plugin->get_slug(), true );
},
);
}

/**
* Monitor active plugins and validate the transient for the given slug.
*
* @param Tribe__PUE__Checker $checker An instance of the PUE Checker.
*/
public static function monitor_active_plugins( Tribe__PUE__Checker $checker ) {
$slug = $checker->get_slug();

if ( empty( $slug ) ) {
return;
}

$transient_data = get_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY );
if ( empty( $transient_data['plugins'] ) || ! is_array( $transient_data['plugins'] ) ) {
$transient_data = [
'plugins' => [],
];
}

$transient_data['plugins'][ $slug ] = $checker->is_key_valid();

$transient_data['plugins'] = array_filter( $transient_data['plugins'] );
set_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY, $transient_data );
}

/**
* Retrieves the uplink resource for the given slug, if available.
*
* Ensures the `get_resource()` function exists before calling it.
*
* @param string $slug The slug of the resource to retrieve.
*
* @return mixed The resource object if available, or `null` if the function does not exist or fails to retrieve the resource.
*/
public function get_uplink_resource( string $slug ) {
try {
$resource = get_resource( $slug );
} catch ( Throwable $e ) {
return null;
}

return $resource;
}
}
}
Loading

0 comments on commit 5fc31e3

Please sign in to comment.