Plugin Page

WooCommerce – Retroactive Download Access

View Plugin

Developer Reference

Settings Keys

All plugin settings are individual WordPress options readable with get_option(). There is no single serialized array.

Option KeyTypeDefaultDescription
wcrda_sync_methodstringasyncActive sync method: async (Background Process) or fly (On-the-Fly)
wcrda_batch_sizeint20Orders per background job (Background Process only)
wcrda_force_resetstringnoDelete existing permissions before re-creating: yes or no
wcrda_disable_cachestringnoBypass on-the-fly scan cache: yes or no
wcrda_cache_durationint60On-the-fly scan cache window in minutes
wcrda_order_statusesarray['wc-completed', 'wc-processing']Eligible order statuses (with wc- prefix)
wcrda_date_fromstring''Orders from date (YYYY-MM-DD); empty = no lower limit
wcrda_date_tostring''Orders to date (YYYY-MM-DD); empty = no upper limit
wcrda_expiry_handlingstringcurrentExpiry for new permissions: current or preserve
wcrda_download_limit_handlingstringcurrentDownload limit for new permissions: current or inherit
wcrda_send_emailstringnoSend customer notification emails: yes or no
wcrda_email_subjectstring[{site_name}] New downloads available for order #{order_number}Email subject template
wcrda_debug_modestringnoEnable debug logging: yes or no

Example:

// Check active sync method.
$method = get_option( 'wcrda_sync_method', 'async' );

// Read eligible statuses.
$statuses = get_option( 'wcrda_order_statuses', array( 'wc-completed', 'wc-processing' ) );

Product Exclusion Meta

To check or set the per-product exclusion flag programmatically:

// Check if a product is excluded.
$excluded = 'yes' === get_post_meta( $product_id, '_wcrda_exclude', true );

// Exclude a product.
update_post_meta( $product_id, '_wcrda_exclude', 'yes' );

// Re-include a product.
update_post_meta( $product_id, '_wcrda_exclude', 'no' );

Hooks & Filters

The plugin exposes 20 hooks across four categories. See Hooks & Filters for the full reference with parameters and usage examples.

Hooks & Filters

All hooks were introduced in version 1.2.0.


Permission Grant Hooks

These hooks fire inside WCRDA_Grant_Helper::grant_permission(), which is called by both sync methods whenever a missing permission is detected.

wcrda_should_grant_permission

Type: Filter Return: bool — return false to skip granting this file.

Fires before a download permission is created. Return false to prevent the grant for this specific file without affecting other files or orders in the same batch.

add_filter( 'wcrda_should_grant_permission', function( $should_grant, $download_id, $product, $order, $quantity ) {
    // Skip a specific product category.
    if ( has_term( 'restricted', 'product_cat', $product->get_id() ) ) {
        return false;
    }
    return $should_grant;
}, 10, 5 );

Parameters:

#TypeDescription
1boolWhether to proceed with the grant.
2stringThe WooCommerce download ID (file hash).
3WC_ProductThe product being granted.
4WC_OrderThe order receiving the permission.
5intLine item quantity.

wcrda_before_grant_permission

Type: Action

Fires immediately before wc_downloadable_file_permission() is called. Use this to perform setup or logging before the permission row is written.

add_action( 'wcrda_before_grant_permission', function( $download_id, $product, $order, $quantity ) {
    // Custom logging before the grant.
}, 10, 4 );

Parameters: string $download_id, WC_Product $product, WC_Order $order, int $quantity


wcrda_after_grant_permission

Type: Action

Fires immediately after the permission row has been created by WooCommerce. Use this to trigger integrations or record the grant in an external system.

add_action( 'wcrda_after_grant_permission', function( $download_id, $product, $order, $quantity ) {
    // Notify an external service.
}, 10, 4 );

Parameters: string $download_id, WC_Product $product, WC_Order $order, int $quantity


wcrda_permission_expiry

Type: Filter Return: WC_DateTime|null — the expiry date, or null for no expiry.

Filters the expiry date applied to a newly granted permission. The initial value passed to the filter reflects the wcrda_expiry_handling setting: preserve passes the expiry from the customer’s first existing permission on the order; current passes the product’s default expiry.

add_filter( 'wcrda_permission_expiry', function( $expires, $permission, $order, $product ) {
    // Always set a 30-day expiry from today, regardless of settings.
    return new WC_DateTime( '+30 days' );
}, 10, 4 );

Parameters:

#TypeDescription
1WC_DateTimenullInitial expiry date (from the wcrda_expiry_handling setting).
2WC_Customer_DownloadThe newly created permission object.
3WC_OrderThe order receiving the permission.
4WC_ProductThe product being granted.

wcrda_permission_download_limit

Type: Filter Return: string — remaining downloads; '' means unlimited.

Filters the download limit applied to a newly granted permission. The initial value reflects the wcrda_download_limit_handling setting: inherit passes the remaining count from the customer’s first existing permission; current passes the product’s default limit.

add_filter( 'wcrda_permission_download_limit', function( $limit, $permission, $order, $product ) {
    // Grant unlimited downloads for all retroactive permissions.
    return '';
}, 10, 4 );

Parameters:

#TypeDescription
1stringInitial remaining downloads; '' = unlimited.
2WC_Customer_DownloadThe newly created permission object.
3WC_OrderThe order receiving the permission.
4WC_ProductThe product being granted.

wcrda_should_notify_customer

Type: Filter Return: bool — return false to suppress the email for this order.

Fires after the global Notify Customers setting is confirmed enabled, allowing per-order suppression without disabling notifications globally.

add_filter( 'wcrda_should_notify_customer', function( $should_notify, $order ) {
    // Suppress notifications for wholesale customers.
    if ( $order->get_billing_email() === 'wholesale@example.com' ) {
        return false;
    }
    return $should_notify;
}, 10, 2 );

Parameters: bool $should_notify, WC_Order $order


Eligibility Hooks

These hooks fire inside WCRDA_Grant_Helper helper methods used by both sync methods to determine whether an order or product is in scope.

wcrda_allowed_order_statuses

Type: Filter Return: string[] — order statuses with the wc- prefix.

Filters the order statuses eligible for retroactive access. The initial value is the wcrda_order_statuses setting (or the default ['wc-completed', 'wc-processing'] if nothing is saved).

add_filter( 'wcrda_allowed_order_statuses', function( $statuses ) {
    // Also include 'on-hold' orders.
    $statuses[] = 'wc-on-hold';
    return $statuses;
} );

Parameters: string[] $statuses


wcrda_is_product_excluded

Type: Filter Return: bool — return true to exclude the product from all retroactive access.

Filters whether a product is excluded. The initial value is true if the _wcrda_exclude post meta is yes, false otherwise.

add_filter( 'wcrda_is_product_excluded', function( $excluded, $product_id ) {
    // Exclude all variable products programmatically.
    $product = wc_get_product( $product_id );
    if ( $product && $product->is_type( 'variable' ) ) {
        return true;
    }
    return $excluded;
}, 10, 2 );

Parameters: bool $excluded, int $product_id


wcrda_is_order_in_date_range

Type: Filter Return: bool — return false to exclude the order from scope.

Filters whether an order passes the configured date range check.

add_filter( 'wcrda_is_order_in_date_range', function( $in_range, $order ) {
    // Also exclude orders from a specific year.
    if ( $order->get_date_created() && '2020' === $order->get_date_created()->format( 'Y' ) ) {
        return false;
    }
    return $in_range;
}, 10, 2 );

Parameters: bool $in_range, WC_Order $order


Background Process Hooks

These hooks fire inside WCRDA_Background_Process and are only relevant when the Background Process sync method is active.

wcrda_file_changes_detected

Type: Action

Fires when new download file IDs are detected on a product save (before the regeneration job is scheduled).

add_action( 'wcrda_file_changes_detected', function( $product_id, $added_ids, $old_ids ) {
    // Log the added file hashes.
}, 10, 3 );

Parameters: int $product_id, string[] $added_download_ids, string[] $previous_download_ids


wcrda_should_schedule_regeneration

Type: Filter Return: bool — return false to prevent the Action Scheduler job from being queued.

Fires inside schedule_regeneration() after file changes are detected. Use this to suppress scheduling during bulk imports or to redirect to a custom processing queue.

add_filter( 'wcrda_should_schedule_regeneration', function( $should_schedule, $product_id ) {
    // Skip scheduling during a WP-CLI import.
    if ( defined( 'WP_CLI' ) && WP_CLI ) {
        return false;
    }
    return $should_schedule;
}, 10, 2 );

Parameters: bool $should_schedule, int $product_id


wcrda_batch_order_ids

Type: Filter Return: int[] — modified list of order IDs to process in this batch.

Filters the order IDs fetched from the database for a per-product batch. Use this to inject, remove, or reorder specific orders.

add_filter( 'wcrda_batch_order_ids', function( $order_ids, $product_id, $page ) {
    // Prepend a specific order on the first page.
    if ( 1 === $page ) {
        array_unshift( $order_ids, 9999 );
    }
    return $order_ids;
}, 10, 3 );

Parameters: int[] $order_ids, int $product_id, int $page (1-based)


wcrda_skip_order

Type: Filter Return: bool — return true to skip this order entirely.

Fires for each order before status and date range checks run. $product_id is 0 when called from a global scan.

add_filter( 'wcrda_skip_order', function( $skip, $order, $product_id ) {
    // Skip orders placed by a specific customer.
    if ( $order->get_customer_id() === 42 ) {
        return true;
    }
    return $skip;
}, 10, 3 );

Parameters: bool $skip, WC_Order $order, int $product_id (0 in a global scan)


wcrda_before_process_order

Type: Action

Fires before the plugin evaluates the items of an order during batch processing.

add_action( 'wcrda_before_process_order', function( $order, $product_id ) {
    // Set up per-order context.
}, 10, 2 );

Parameters: WC_Order $order, int $product_id (0 in a global scan)


wcrda_after_process_order

Type: Action

Fires after all items of an order have been evaluated.

add_action( 'wcrda_after_process_order', function( $order, $permissions_granted, $product_id ) {
    if ( $permissions_granted ) {
        // React to the fact that this order received new files.
    }
}, 10, 3 );

Parameters: WC_Order $order, bool $permissions_granted, int $product_id (0 in a global scan)


wcrda_regeneration_complete

Type: Action

Fires when all batch pages for a per-product regeneration have finished processing.

add_action( 'wcrda_regeneration_complete', function( $product_id ) {
    // All orders for this product have been processed.
} );

Parameters: int $product_id


On-the-Fly Hooks

These hooks fire inside WCRDA_On_The_Fly and are only relevant when the On-the-Fly sync method is active.

wcrda_on_the_fly_enabled

Type: Filter Return: bool — return false to skip the scan for this user entirely.

Fires at the start of the on-the-fly check, before the cache is consulted. Use this to disable the feature for specific roles or during maintenance.

add_filter( 'wcrda_on_the_fly_enabled', function( $enabled, $user_id ) {
    // Disable for administrators (they manage products, not customers).
    if ( user_can( $user_id, 'manage_options' ) ) {
        return false;
    }
    return $enabled;
}, 10, 2 );

Parameters: bool $enabled, int $user_id


wcrda_on_the_fly_cache_duration

Type: Filter Return: int — throttle window in seconds; 0 disables the throttle for this user.

Filters the scan cache duration for a specific user, overriding the global Cache Duration setting.

add_filter( 'wcrda_on_the_fly_cache_duration', function( $duration, $user_id ) {
    // VIP customers get a shorter cache (10 minutes).
    if ( get_user_meta( $user_id, 'is_vip', true ) ) {
        return 10 * 60;
    }
    return $duration;
}, 10, 2 );

Parameters: int $cache_duration_seconds, int $user_id


wcrda_on_the_fly_orders

Type: Filter Return: WC_Order[] — modified list of orders to scan for this user.

Filters the orders retrieved for a user’s on-the-fly scan. Use this to add, remove, or reorder orders before the permission check loop runs.

add_filter( 'wcrda_on_the_fly_orders', function( $orders, $user_id ) {
    // Remove a specific order from the scan.
    return array_filter( $orders, function( $order ) {
        return $order->get_id() !== 1234;
    } );
}, 10, 2 );

Parameters: WC_Order[] $orders, int $user_id


wcrda_after_on_the_fly_processing

Type: Action

Fires after the on-the-fly scan has completed for a user, after the cache timestamp is updated.

add_action( 'wcrda_after_on_the_fly_processing', function( $user_id, $permissions_granted ) {
    if ( $permissions_granted ) {
        // New files were granted to this user on this visit.
    }
}, 10, 2 );

Parameters: int $user_id, bool $permissions_granted