Automattic\WooCommerce\Internal\PushNotifications\DataStores

PushTokensDataStore::get_tokens_for_rolespublicWC 10.7.0

Returns push tokens belonging to users with the given roles.

When called without pagination parameters, returns all tokens as a flat array (cached per-request). When $page and $per_page are provided, returns a paginated result with total counts.

The eligible-user lookup is restricted to users that actually own push tokens, so the role check runs against a handful of IDs instead of scanning every user's capabilities meta, which does not scale on sites with very large user tables.

Method of the class: PushTokensDataStore{}

No Hooks.

Returns

PushToken[]|Array{tokens:. PushToken[], total: int, total_pages: int}

Usage

$PushTokensDataStore = new PushTokensDataStore();
$PushTokensDataStore->get_tokens_for_roles( $roles, ?int $page, ?int $per_page );
$roles(string[]) (required)
The roles to query tokens for.
?int $page
.
Default: null
?int $per_page
.
Default: null

Changelog

Since 10.7.0 Introduced.

PushTokensDataStore::get_tokens_for_roles() code WC 11.0.1

public function get_tokens_for_roles( array $roles, ?int $page = null, ?int $per_page = null ) {
	$paginate  = null !== $page && null !== $per_page;
	$cache_key = $paginate ? implode( ',', $roles ) . ":$page:$per_page" : implode( ',', $roles );

	$empty_result = $paginate
		? array(
			'tokens'      => array(),
			'total'       => 0,
			'total_pages' => 0,
		)
		: array();

	if ( empty( $roles ) ) {
		return $empty_result;
	}

	if ( isset( $this->tokens_by_roles_cache[ $cache_key ] ) ) {
		return $this->tokens_by_roles_cache[ $cache_key ];
	}

	global $wpdb;

	// Exactly this SQL to leverage the wp_posts type_status_author index; low token cardinality keeps it fast at any store size.
	$users_with_tokens = $wpdb->get_col(
		$wpdb->prepare(
			"SELECT DISTINCT post_author FROM {$wpdb->posts} WHERE post_type = %s AND post_status = 'private'",
			PushToken::POST_TYPE
		)
	);

	// An empty include must short-circuit: WP_User_Query would ignore it and scan all users by role.
	$user_ids = empty( $users_with_tokens ) ? array() : get_users(
		array(
			'role__in' => $roles,
			'fields'   => 'ID',
			'include'  => $users_with_tokens,
		)
	);

	if ( empty( $user_ids ) ) {
		$this->tokens_by_roles_cache[ $cache_key ] = $empty_result;
		return $this->tokens_by_roles_cache[ $cache_key ];
	}

	$query_args = array(
		'post_type'      => PushToken::POST_TYPE,
		'post_status'    => 'private',
		'author__in'     => $user_ids,
		'posts_per_page' => $paginate ? $per_page : -1,
		'fields'         => 'ids',
	);

	if ( $paginate ) {
		$query_args['paged']   = $page;
		$query_args['orderby'] = 'ID';
		$query_args['order']   = 'ASC';
	}

	$query = new WP_Query( $query_args );

	/**
	 * Typehint for PHPStan, specifies these are IDs and not instances of
	 * WP_Post.
	 *
	 * @var int[] $post_ids
	 */
	$post_ids = $query->posts;

	if ( empty( $post_ids ) ) {
		$this->tokens_by_roles_cache[ $cache_key ] = $empty_result;
		return $this->tokens_by_roles_cache[ $cache_key ];
	}

	_prime_post_caches( $post_ids, false, true );

	$tokens = array();

	foreach ( $post_ids as $post_id ) {
		try {
			$tokens[] = $this->read( (int) $post_id );
		} catch ( WC_Data_Exception $e ) {
			wc_get_logger()->warning(
				'Skipping malformed push token during role-based query.',
				array(
					'token_id' => $post_id,
					'error'    => $e->getMessage(),
				)
			);
		}
	}

	$result = $paginate
		? array(
			'tokens'      => $tokens,
			'total'       => (int) $query->found_posts,
			'total_pages' => (int) $query->max_num_pages,
		)
		: $tokens;

	$this->tokens_by_roles_cache[ $cache_key ] = $result;
	return $result;
}