Skip to main content

Enumerate WP User IDs Eligible for a Broadcast Audience

Free Intermediate

Resolving “who would this broadcast go to?” into a concrete list of WordPress user IDs is the starting point for a custom send — your own email queue, an ESP API call, an export sheet, a dry-run count before anyone presses Send.

benecaster_find_audience_user_ids( $show_id, $audience ) is the way in. It needs nothing but WordPress and Benecaster loaded — no service container, no class import — so it works from a theme template, a snippet plugin, a WP-CLI command in another plugin, or an add-on.

Four audiences are built in:

Audience Who it reaches
paying Paying subscribers only. Excludes followers and bridge members on a free tier
followers Direct followers only
all Every active token holder for the show
tier:SLUG Active token holders on one tier, e.g. tier:gold

The result is a deduplicated list of user IDs, in no guaranteed order.

The tier slug must match a configured tier exactly, and the match is case-sensitive. tier:Gold does not find gold. An unconfigured or wrong-cased slug resolves to an empty list rather than erroring, so a typo looks exactly like a tier nobody has joined.

tier:follower does not reach your followers. Follower tokens carry the slug follower, which is not a tier-map row on a normal install, so it resolves empty. Use the followers audience.

Custom audiences go through the filter. An unknown slug arrives as an empty array, so a callback can define one completely rather than filtering something core guessed at. The example below builds a temporal segment — everyone who joined in the last 30 days — for a “welcome, here is what you missed” send. That is a question core does not answer, which is what makes it worth writing.

Code

<?php
// Built-in audiences — including per-tier, which needs no callback.
$paying = benecaster_find_audience_user_ids( $show_id, 'paying' );
$gold   = benecaster_find_audience_user_ids( $show_id, 'tier:gold' );

foreach ( $gold as $user_id ) {
    $user = get_userdata( $user_id );
    // Hand off to the email queue, an ESP API call, an export sheet, etc.
}

// A genuinely custom audience: everyone who joined in the last 30 days.
add_filter( 'benecaster_broadcast_audience_user_ids', function (
    array  $user_ids,
    string $audience,
    int    $show_id
): array {
    // Guard first. Without this you rewrite every audience at once.
    if ( 'joined-last-30-days' !== $audience ) {
        return $user_ids;
    }

    global $wpdb;

    // created_at is stored in the site's timezone, so build the cutoff in
    // the same timezone rather than in UTC — an install in UTC+13 would
    // otherwise silently move the window by half a day.
    $cutoff = wp_date( 'Y-m-d H:i:s', time() - 30 * DAY_IN_SECONDS );

    $rows = $wpdb->get_col( $wpdb->prepare(
        "SELECT DISTINCT user_id FROM {$wpdb->prefix}benecaster_tokens
         WHERE show_id = %d AND status = 'active' AND created_at >= %s",
        $show_id,
        $cutoff
    ) );

    return array_map( 'intval', (array) $rows );
}, 10, 3 );

View on GitHub →

Hooks Used

Need this built rather than just documented? See our services →