Created
March 11, 2026 06:54
-
-
Save mralaminahamed/ec5576c2eefcaea9894345cee8871d60 to your computer and use it in GitHub Desktop.
class-affiliate-role-manager.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Affiliate Role Manager | |
| * | |
| * Registers a custom 'affiliate' WordPress role, assigns it to existing users | |
| * based on the '_wc_affiliate_status' user meta, and automatically maintains | |
| * role assignment whenever that meta value is created or updated. | |
| * Also provides a utility query to retrieve all non-affiliate users. | |
| * | |
| * @package YourPlugin | |
| * @subpackage Affiliate | |
| * @author Al Amin Ahamed <me@alaminahamed.com> | |
| * @copyright 2025 Al Amin Ahamed | |
| * @license GPL-2.0-or-later | |
| * @since 1.0.0 | |
| * | |
| * @wordpress-plugin | |
| * Plugin Name: Affiliate Role Manager | |
| * Plugin URI: https://example.com/affiliate-role-manager | |
| * Description: Registers a custom affiliate role and manages its assignment | |
| * based on WooCommerce affiliate status user meta. | |
| * Version: 1.0.0 | |
| * Author: Al Amin Ahamed | |
| * Author URI: https://example.com | |
| * License: GPL-2.0-or-later | |
| * License URI: https://www.gnu.org/licenses/gpl-2.0.html | |
| * Text Domain: affiliate-role-manager | |
| * Domain Path: /languages | |
| * Requires at least: 5.8 | |
| * Requires PHP: 7.4 | |
| * WC requires at least: 6.0 | |
| * WC tested up to: 8.0 | |
| */ | |
| if ( ! defined( 'ABSPATH' ) ) { | |
| exit; // Prevent direct file access. | |
| } | |
| // ------------------------------------------------------------------------- | |
| // Step 1: Register the custom 'affiliate' role. | |
| // ------------------------------------------------------------------------- | |
| /** | |
| * Registers the 'affiliate' user role with minimal capabilities. | |
| * | |
| * Hooked to 'init' so it runs on every request; the inner guard prevents | |
| * redundant calls to add_role() once the role already exists in the database. | |
| * | |
| * @since 1.0.0 | |
| * @return void | |
| */ | |
| function register_affiliate_role() { | |
| if ( ! get_role( 'affiliate' ) ) { | |
| add_role( | |
| 'affiliate', | |
| __( 'Affiliate', 'affiliate-role-manager' ), | |
| array( | |
| 'read' => true, | |
| 'edit_posts' => false, | |
| 'delete_posts' => false, | |
| ) | |
| ); | |
| } | |
| } | |
| add_action( 'init', 'register_affiliate_role' ); | |
| // ------------------------------------------------------------------------- | |
| // Step 2: Bulk-assign the affiliate role to pre-existing users. | |
| // ------------------------------------------------------------------------- | |
| /** | |
| * Iterates over all users that carry the '_wc_affiliate_status' meta key and | |
| * assigns the 'affiliate' role to those whose status equals 'active'. | |
| * | |
| * A long-lived transient is used as a one-time execution guard so that this | |
| * bulk operation does not repeat on every page load after the initial run. | |
| * | |
| * @since 1.0.0 | |
| * @return void | |
| */ | |
| function assign_affiliate_role_to_existing_users() { | |
| // Bail early if the bulk assignment has already been performed. | |
| if ( get_transient( 'affiliate_role_assigned' ) ) { | |
| return; | |
| } | |
| $users = get_users( | |
| array( | |
| 'meta_key' => '_wc_affiliate_status', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key | |
| 'meta_compare' => 'EXISTS', | |
| 'fields' => 'all', | |
| 'number' => -1, | |
| ) | |
| ); | |
| if ( empty( $users ) ) { | |
| return; | |
| } | |
| foreach ( $users as $user ) { | |
| $affiliate_status = get_user_meta( $user->ID, '_wc_affiliate_status', true ); | |
| // Only assign the role when the affiliate status is explicitly 'active'. | |
| if ( ! empty( $affiliate_status ) && 'active' === $affiliate_status ) { | |
| $user_obj = new WP_User( $user->ID ); | |
| $user_obj->add_role( 'affiliate' ); | |
| } | |
| } | |
| // Mark bulk assignment as complete for one year. | |
| set_transient( 'affiliate_role_assigned', true, DAY_IN_SECONDS * 365 ); | |
| } | |
| add_action( 'init', 'assign_affiliate_role_to_existing_users' ); | |
| // ------------------------------------------------------------------------- | |
| // Step 3: React to meta create / update events for new users. | |
| // ------------------------------------------------------------------------- | |
| /** | |
| * Adds or removes the 'affiliate' role whenever '_wc_affiliate_status' meta | |
| * is created or updated for a user. | |
| * | |
| * Hooked to both 'added_user_meta' and 'updated_user_meta' so that the role | |
| * state remains in sync regardless of whether the meta record is new or | |
| * pre-existing. | |
| * | |
| * @since 1.0.0 | |
| * | |
| * @param int $meta_id ID of the user meta row that was affected. | |
| * @param int $user_id ID of the user whose meta was changed. | |
| * @param string $meta_key Meta key that was added or updated. | |
| * @param mixed $meta_value New value of the meta key. | |
| * @return void | |
| */ | |
| function assign_affiliate_role_on_meta_update( $meta_id, $user_id, $meta_key, $meta_value ) { | |
| if ( '_wc_affiliate_status' !== $meta_key ) { | |
| return; | |
| } | |
| $user = new WP_User( $user_id ); | |
| if ( 'active' === $meta_value ) { | |
| $user->add_role( 'affiliate' ); | |
| } else { | |
| // Remove the role when the status is set to anything other than 'active'. | |
| $user->remove_role( 'affiliate' ); | |
| } | |
| } | |
| add_action( 'updated_user_meta', 'assign_affiliate_role_on_meta_update', 10, 4 ); | |
| add_action( 'added_user_meta', 'assign_affiliate_role_on_meta_update', 10, 4 ); | |
| // ------------------------------------------------------------------------- | |
| // Step 4: Utility — query non-affiliate users only. | |
| // ------------------------------------------------------------------------- | |
| /** | |
| * Retrieves all users who are neither assigned the 'affiliate' role nor carry | |
| * the '_wc_affiliate_status' meta key. | |
| * | |
| * The dual exclusion strategy ensures edge cases are handled: users who have | |
| * the meta key present but whose role was never applied (e.g. due to a failed | |
| * earlier migration) are also excluded from the result set. | |
| * | |
| * @since 1.0.0 | |
| * | |
| * @param array $extra_args Optional additional arguments to merge into the | |
| * get_users() call (e.g. 'number', 'offset', 'orderby'). | |
| * @return WP_User[] Array of WP_User objects representing non-affiliate users. | |
| */ | |
| function get_non_affiliate_users( array $extra_args = array() ) { | |
| $default_args = array( | |
| 'role__not_in' => array( 'affiliate' ), | |
| 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query | |
| array( | |
| 'key' => '_wc_affiliate_status', | |
| 'compare' => 'NOT EXISTS', | |
| ), | |
| ), | |
| 'fields' => 'all', | |
| 'number' => -1, | |
| ); | |
| $args = wp_parse_args( $extra_args, $default_args ); | |
| return get_users( $args ); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment