Skip to main content

Tag Manual Grants with User Role

Premium Beginner Since v1.1.0

The two manual-grant lifecycle actions form a symmetric pair — one fires when a subscriber is comped via the admin “Add subscriber manually” flow, the other when the hourly expiry cron auto-revokes an expired grant. This recipe hooks both to assign a WordPress role at grant time and remove it on expiry, keeping external systems (LMS enrollment, Discord bots, CRM segments) coherent across the full lifecycle.

Notes: (1) benecaster_manual_subscriber_created fires only for admin-created grants — not for regular paid signups, bulk enrollment, or bridge-provisioned subscribers. Hook benecaster_subscription_activated for those. (2) benecaster_manual_grant_expired only fires for grants that had a non-null manual_expiry_at; comps with no expiry never trigger it. (3) Admins can also manually revoke a grant via the Subscribers list before expiry — that path fires benecaster_token_revoked, not benecaster_manual_grant_expired; hook that action too for blanket cleanup.

Code

<?php
// On grant: add the comped subscriber to a "beta-testers" WP role AND
// push them to a CRM segment. Runs on the same request as the admin's
// POST /shows/{id}/subscribers/manual, so it's safe to make outbound
// HTTP calls here — the admin sees the modal spin briefly.
add_action( 'benecaster_manual_subscriber_created', function ( int $user_id, int $show_id, string $tier_slug, ?string $expiry_at ): void {
    $user = get_userdata( $user_id );
    if ( ! $user ) {
        return;
    }

    // Add a WordPress role for gate control on other themes / plugins.
    $user->add_role( 'beta_tester' );

    // Push to a CRM segment via HTTP. $expiry_at is a UTC MySQL
    // datetime string ('YYYY-MM-DD HH:MM:SS') or null for no-expiry.
    wp_remote_post( 'https://crm.example.com/api/tag', [
        'body' => wp_json_encode( [
            'email'      => $user->user_email,
            'tag'        => 'benecaster-comp',
            'show_id'    => $show_id,
            'tier'       => $tier_slug,
            'expires_at' => $expiry_at,
        ] ),
    ] );
}, 10, 4 );

// On auto-expiry: remove the same state. Runs from cron, so an outbound
// HTTP failure will not block anything on the admin side.
add_action( 'benecaster_manual_grant_expired', function ( int $user_id, int $show_id ): void {
    $user = get_userdata( $user_id );
    if ( ! $user ) {
        return;
    }

    $user->remove_role( 'beta_tester' );

    wp_remote_post( 'https://crm.example.com/api/untag', [
        'body' => wp_json_encode( [
            'email'   => $user->user_email,
            'tag'     => 'benecaster-comp',
            'show_id' => $show_id,
        ] ),
    ] );
}, 10, 2 );

View on GitHub →

Hooks Used