Fetch Marketplace promotions - ensure callback is always registered for `woocommerce_marketplace_fetch_promotions` action (#47262)
* Marketplace promotions - ensure action is always there We started getting errors 'Scheduled action for woocommerce_marketplace_fetch_promotions will not be executed as no callbacks are registered.' on some environments. In this commit we ensure that WC_Admin_Marketplace_Promotions::fetch_marketplace_promotions() is always added as a calback to our action hook. * Marketplace promotions - switch from Action Scheduler to transients We're switching fetching marketplace promotions from using Action Scheduler every 12 hours, to a 1 day transient. This makes it easier to ensure that the requests are triggered only for admins, and that they don't impact frontend users of the stores. * Changelog * Clear action from Action Scheduler Action woocommerce_marketplace_fetch_promotions is no longer used, so we're clearing it when it's triggered. Since we cannot self-clear the action, we're triggering a new single action when woocommerce_marketplace_fetch_promotions is run. This new action's sole responsibility is to clear the original action.
This commit is contained in:
parent
a7a1264fec
commit
5cd46f48ad
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: fix
|
||||
|
||||
Switch marketplace promotions from Action Scheduler to transient.
|
|
@ -558,7 +558,7 @@ if ( ! class_exists( 'WC_Admin_Assets', false ) ) :
|
|||
// Marketplace promotions.
|
||||
if ( in_array( $screen_id, array( 'woocommerce_page_wc-admin' ), true ) ) {
|
||||
|
||||
$promotions = get_transient( WC_Admin_Marketplace_Promotions::TRANSIENT_NAME );
|
||||
$promotions = WC_Admin_Marketplace_Promotions::get_active_promotions();
|
||||
|
||||
if ( false === $promotions ) {
|
||||
return;
|
||||
|
|
|
@ -15,10 +15,9 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||
*/
|
||||
class WC_Admin_Marketplace_Promotions {
|
||||
|
||||
const TRANSIENT_NAME = 'woocommerce_marketplace_promotions';
|
||||
const SCHEDULED_ACTION_HOOK = 'woocommerce_marketplace_fetch_promotions';
|
||||
const PROMOTIONS_API_URL = 'https://woocommerce.com/wp-json/wccom-extensions/3.0/promotions';
|
||||
const SCHEDULED_ACTION_INTERVAL = 12 * HOUR_IN_SECONDS;
|
||||
const TRANSIENT_NAME = 'woocommerce_marketplace_promotions_v2';
|
||||
const TRANSIENT_LIFE_SPAN = DAY_IN_SECONDS;
|
||||
const PROMOTIONS_API_URL = 'https://woocommerce.com/wp-json/wccom-extensions/3.0/promotions';
|
||||
|
||||
/**
|
||||
* The user's locale, for example en_US.
|
||||
|
@ -28,7 +27,7 @@ class WC_Admin_Marketplace_Promotions {
|
|||
public static string $locale;
|
||||
|
||||
/**
|
||||
* On all admin pages, schedule an action to fetch promotions data.
|
||||
* On all admin pages, try go get Marketplace promotions every day.
|
||||
* Shows notice and adds menu badge to WooCommerce Extensions item
|
||||
* if the promotions API requests them.
|
||||
*
|
||||
|
@ -38,25 +37,9 @@ class WC_Admin_Marketplace_Promotions {
|
|||
* @return void
|
||||
*/
|
||||
public static function init() {
|
||||
/**
|
||||
* Filter to suppress the requests for and showing of marketplace promotions.
|
||||
*
|
||||
* @since 8.8
|
||||
*/
|
||||
if ( apply_filters( 'woocommerce_marketplace_suppress_promotions', false ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
register_deactivation_hook( WC_PLUGIN_FILE, array( __CLASS__, 'clear_scheduled_event' ) );
|
||||
|
||||
// Add the callback for our scheduled action.
|
||||
if ( ! has_action( self::SCHEDULED_ACTION_HOOK, array( __CLASS__, 'fetch_marketplace_promotions' ) ) ) {
|
||||
add_action( self::SCHEDULED_ACTION_HOOK, array( __CLASS__, 'fetch_marketplace_promotions' ) );
|
||||
}
|
||||
|
||||
if ( is_admin() ) {
|
||||
add_action( 'init', array( __CLASS__, 'schedule_promotion_fetch' ), 12 );
|
||||
}
|
||||
// A legacy hook that can be triggered by action scheduler.
|
||||
add_action( 'woocommerce_marketplace_fetch_promotions', array( __CLASS__, 'clear_deprecated_action' ) );
|
||||
add_action( 'woocommerce_marketplace_fetch_promotions_clear', array( __CLASS__, 'clear_scheduled_event' ) );
|
||||
|
||||
if (
|
||||
defined( 'DOING_AJAX' ) && DOING_AJAX
|
||||
|
@ -66,31 +49,73 @@ class WC_Admin_Marketplace_Promotions {
|
|||
return;
|
||||
}
|
||||
|
||||
if ( ! is_admin() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::maybe_update_promotions();
|
||||
|
||||
self::$locale = ( self::$locale ?? get_user_locale() ) ?? 'en_US';
|
||||
self::maybe_show_bubble_promotions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule the action to fetch promotions data.
|
||||
* Fetch promotions from the API and store them in a transient.
|
||||
* Fetching can be suppressed by the `woocommerce_marketplace_suppress_promotions` filter.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function schedule_promotion_fetch() {
|
||||
// Schedule the action twice a day using Action Scheduler.
|
||||
if (
|
||||
function_exists( 'as_has_scheduled_action' )
|
||||
&& function_exists( 'as_schedule_recurring_action' )
|
||||
&& false === as_has_scheduled_action( self::SCHEDULED_ACTION_HOOK )
|
||||
) {
|
||||
as_schedule_recurring_action( time(), self::SCHEDULED_ACTION_INTERVAL, self::SCHEDULED_ACTION_HOOK );
|
||||
private static function maybe_update_promotions() {
|
||||
// Fetch promotions if they're not in the transient.
|
||||
if ( false !== get_transient( self::TRANSIENT_NAME ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch promotions from the API.
|
||||
$promotions = self::fetch_marketplace_promotions();
|
||||
set_transient( self::TRANSIENT_NAME, $promotions, self::TRANSIENT_LIFE_SPAN );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get active Marketplace promotions from the transient.
|
||||
* Use `woocommerce_marketplace_suppress_promotions` filter to suppress promotions.
|
||||
*
|
||||
* @since 9.0
|
||||
*/
|
||||
public static function get_active_promotions() {
|
||||
/**
|
||||
* Filter to suppress the requests for and showing of marketplace promotions.
|
||||
*
|
||||
* @since 8.8
|
||||
*/
|
||||
if ( apply_filters( 'woocommerce_marketplace_suppress_promotions', false ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$promotions = get_transient( self::TRANSIENT_NAME );
|
||||
if ( ! $promotions ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return self::filter_out_inactive_promotions( $promotions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get promotions to show in the Woo in-app marketplace and load them into a transient
|
||||
* with a 12-hour life. Run as a recurring scheduled action.
|
||||
*
|
||||
* @return void
|
||||
* @return array
|
||||
*/
|
||||
public static function fetch_marketplace_promotions() {
|
||||
private static function fetch_marketplace_promotions() {
|
||||
/**
|
||||
* Filter to suppress the requests for and showing of marketplace promotions.
|
||||
*
|
||||
* @since 8.8
|
||||
*/
|
||||
if ( apply_filters( 'woocommerce_marketplace_suppress_promotions', false ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// Fetch promotions from the API.
|
||||
$fetch_options = array(
|
||||
'auth' => true,
|
||||
|
@ -131,9 +156,7 @@ class WC_Admin_Marketplace_Promotions {
|
|||
}
|
||||
// phpcs:enable WordPress.NamingConventions.ValidHookName.UseUnderscores
|
||||
|
||||
// Filter out any expired promotions.
|
||||
$active_promotions = self::get_active_promotions( $promotions );
|
||||
set_transient( self::TRANSIENT_NAME, $active_promotions, 12 * HOUR_IN_SECONDS );
|
||||
return $promotions;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,10 +164,21 @@ class WC_Admin_Marketplace_Promotions {
|
|||
* add a filter to show a bubble on the Extensions item in the
|
||||
* WooCommerce menu.
|
||||
*
|
||||
* Use `woocommerce_marketplace_suppress_promotions` filter to suppress the bubble.
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception If we are unable to create a DateTime from the date_to_gmt.
|
||||
*/
|
||||
private static function maybe_show_bubble_promotions() {
|
||||
/**
|
||||
* Filter to suppress the requests for and showing of marketplace promotions.
|
||||
*
|
||||
* @since 8.8
|
||||
*/
|
||||
if ( apply_filters( 'woocommerce_marketplace_suppress_promotions', false ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$promotions = get_transient( self::TRANSIENT_NAME );
|
||||
if ( ! $promotions ) {
|
||||
return;
|
||||
|
@ -211,7 +245,7 @@ class WC_Admin_Marketplace_Promotions {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function get_active_promotions( $promotions = array() ) {
|
||||
private static function filter_out_inactive_promotions( $promotions = array() ) {
|
||||
$now_date_time = new DateTime( 'now', new DateTimeZone( 'UTC' ) );
|
||||
$active_promotions = array();
|
||||
|
||||
|
@ -292,13 +326,25 @@ class WC_Admin_Marketplace_Promotions {
|
|||
}
|
||||
|
||||
/**
|
||||
* When WooCommerce is deactivated, clear the scheduled action.
|
||||
* Clear the scheduled action that was used to fetch promotions in WooCommerce 8.8.
|
||||
* It's no longer needed as a transient is used to store the data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function clear_scheduled_event() {
|
||||
if ( function_exists( 'as_unschedule_all_actions' ) ) {
|
||||
as_unschedule_all_actions( self::SCHEDULED_ACTION_HOOK );
|
||||
as_unschedule_all_actions( 'woocommerce_marketplace_fetch_promotions' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We can't clear deprecated action from AS when it's running,
|
||||
* so we schedule a new single action to clear the deprecated
|
||||
* `woocommerce_marketplace_fetch_promotions` action.
|
||||
*/
|
||||
public static function clear_deprecated_action() {
|
||||
if ( function_exists( 'as_schedule_single_action' ) ) {
|
||||
as_schedule_single_action( time(), 'woocommerce_marketplace_fetch_promotions_clear' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -585,6 +585,7 @@ final class WooCommerce {
|
|||
include_once WC_ABSPATH . 'includes/queue/class-wc-action-queue.php';
|
||||
include_once WC_ABSPATH . 'includes/queue/class-wc-queue.php';
|
||||
include_once WC_ABSPATH . 'includes/admin/marketplace-suggestions/class-wc-marketplace-updater.php';
|
||||
include_once WC_ABSPATH . 'includes/admin/class-wc-admin-marketplace-promotions.php';
|
||||
include_once WC_ABSPATH . 'includes/blocks/class-wc-blocks-utils.php';
|
||||
|
||||
/**
|
||||
|
@ -652,10 +653,6 @@ final class WooCommerce {
|
|||
include_once WC_ABSPATH . 'includes/admin/class-wc-admin.php';
|
||||
}
|
||||
|
||||
if ( $this->is_request( 'admin' ) || $this->is_request( 'cron' ) ) {
|
||||
include_once WC_ABSPATH . 'includes/admin/class-wc-admin-marketplace-promotions.php';
|
||||
}
|
||||
|
||||
// We load frontend includes in the post editor, because they may be invoked via pre-loading of blocks.
|
||||
$in_post_editor = doing_action( 'load-post.php' ) || doing_action( 'load-post-new.php' );
|
||||
|
||||
|
|
Loading…
Reference in New Issue