Search code examples
phpwordpresswoocommerceuser-roleswoocommerce-subscriptions

Change user role based on WooCommerce active subscription


I have a Woocommerce store with a variable subscription and 3 types of subscription variations: subscription-a, subscription-b and subscription-c. I also added 3 new types of user roles: subscriber-a, subscriber-b and subscriber-c.

I'm trying to create a function that when a customer purchase, upgrade or downgrade a subscription and the subscription is active, the parallel user role will be assign to this customer.

For example: If a costumer purchase subscription-a, the user role subscriber-a a will be assigned once active. If a costumer upgrade from subscription-b to subscription-c, the user role will chance from subscriber-b to subscriber-c once active.

I tried the function offered in a similar thread but it didn't work for me: Woocommerce change user role on purchase

function change_role_on_purchase( $order_id ) {

    $order = new WC_Order( $order_id );
    $items = $order->get_items();

    foreach ( $items as $item ) {
        $product_name = $item['name'];
        $product_id = $item['product_id'];
        $product_variation_id = $item['variation_id'];

        if ( $order->user_id > 0 && $product_variation_id == '416' ) {
            update_user_meta( $order->user_id, 'paying_customer', 1 );
            $user = new WP_User( $order->user_id );

            // Remove role
            $user->remove_role( 'subscriber' ); 

            // Add role
            $user->add_role( 'subscriber-a' );
        }
    }
}

add_action( 'woocommerce_subscription_status_active', 'change_role_on_purchase' );

Update: The solution of @LoicTheAztec works great. I am now trying to remove roles when the subscription is cancelled. This is what I got, not sure if this is the most elegant way to do it but it works.

add_action('woocommerce_subscription_status_cancelled', 'cancelled_subscription_remove_role', 10, 1);

function cancelled_subscription_remove_role($subscription) {
    $user_id = $subscription->get_user_id();
    $user = new WP_User($user_id);
    $user->remove_role('subscriber_a');
    $user->remove_role('subscriber_b');
    $user->remove_role('subscriber_c');
}

Solution

  • Updated to handle switched subscriptions too (upgrade or downgrade a subscription)

    You can try to use use woocommerce_subscription_status_updated related hook.In the code below, you will set for each variation ID, the related user role in the settings array (commented code):

    // Custom function for your settings - Variation id per user role
    function variation_id_per_user_role_settings(){
        // Settings: set the variation ID as key with the related user role as value
        return array(
            '417'  => 'subscriber-a',
            '418'  => 'subscriber-b',
            '419'  => 'subscriber-c',
        );
    }
    
    // Custom function that check item and change user role based on variation ID
    function check_order_item_and_change_user_role( $item, $user, $settings ){
        $product = $item->get_product(); // The product object
        
        // Only for variation subscriptions
        if( $product->is_type('subscription_variation') ) {
            $variation_id = $item->get_variation_id(); // the variation ID
            $user_role    = $settings[$variation_id]; // The right user role for the current variation ID
            
            // If current user role doesn't match with the right role
            if( ! in_array( $user_role, $user->roles) ) {
                // Remove "subscriber" user role (if it is set)
                if( in_array('subscriber', $user->roles) ) {
                    $user->remove_role( 'subscriber' );
                }
    
                // Remove other user roles (if they are set)
                foreach ( $settings as $key_id => $value_role ) {
                    if( in_array($value_role, $user->roles) && $user_role !== $value_role ) {
                        $user->remove_role( $value_role );
                    }
                }
    
                // Set the right user role (if it is not set yet)
                $user->set_role( $user_role );
            }
        }
    }
    
    // On first purchase (if needed)
    add_action( 'woocommerce_subscription_status_updated', 'active_subscription_change_user_role', 100, 3 );
    function active_subscription_change_user_role( $subscription, $new_status, $old_status ) {
        // When subscrition status is updated to "active"
        if ( $new_status === 'active' ) {
            // Get the WC_Order Object from subscription
            $order = wc_get_order( $subscription->get_parent_id() );
    
            // Get an instance of the customer WP_User Object
            $user = $order->get_user();
    
            // Check that it's not a guest customer
            if( is_a( $user, 'WP_User' ) && $user->ID > 0 ) {
                // Load settings
                $settings = variation_id_per_user_role_settings();
    
                // Loop through order items
                foreach ( $subscription->get_items() as $item ) {
                    check_order_item_and_change_user_role( $item, $user, $settings );
                }
            }
        }
    }
    
    // On switched purchased subscription
    add_action( 'woocommerce_order_status_changed', 'switched_subscription_change_user_role_on_order_status_change', 100, 4 );
    function switched_subscription_change_user_role_on_order_status_change( $order_id, $old_status, $new_status, $order ) {
        // When order status is updated to 'processing' or 'completed' status
        if ( in_array( $new_status, array('processing','completed') ) ) {
            // Get an instance of the customer WP_User Object
            $user = $order->get_user();
        
            // Check that it's not a guest customer
            if( is_a( $user, 'WP_User' ) && $user->ID > 0 ) {
                // Load settings
                $settings = variation_id_per_user_role_settings();
        
                // Loop through order items
                foreach ( $order->get_items() as $item ) {
                    check_order_item_and_change_user_role( $item, $user, $settings );
                }
            }
        }
    }
    

    Code goes in functions.php file of your active child theme (or active theme). It could works.


    Or you can also try with woocommerce_subscription_status_active hook:

    // Custom function for your settings - Variation id per user role
    function variation_id_per_user_role_settings(){
        // Settings: set the variation ID as key with the related user role as value
        return array(
            '417'  => 'subscriber-a',
            '418'  => 'subscriber-b',
            '419'  => 'subscriber-c',
        );
    }
    
    // Custom function that check item and change user role based on variation ID
    function check_order_item_and_change_user_role( $item, $user, $settings ){
        $product = $item->get_product(); // The product object
    
        // Only for variation subscriptions
        if( $product->is_type('subscription_variation') ) {
            $variation_id = $item->get_variation_id(); // the variation ID
            $user_role    = $settings[$variation_id]; // The right user role for the current variation ID
    
            // If current user role doesn't match with the right role
            if( ! in_array( $user_role, $user->roles) ) {
                // Remove "subscriber" user role (if it is set)
                if( in_array('subscriber', $user->roles) ) {
                    $user->remove_role( 'subscriber' );
                }
    
                // Remove other user roles (if they are set)
                foreach ( $settings as $key_id => $value_role ) {
                    if( in_array($value_role, $user->roles) && $user_role !== $value_role ) {
                        $user->remove_role( $value_role );
                    }
                }
    
                // Set the right user role (if it is not set yet)
                $user->set_role( $user_role );
            }
        }
    }
    
    // On first purchase (if needed)
    add_action( 'woocommerce_subscription_status_active', 'active_subscription_change_user_role', 100 );
    function active_subscription_change_user_role( $subscription ) {
        // Get the WC_Order Object from subscription
        $order = wc_get_order( $subscription->get_parent_id() );
    
        // Get an instance of the customer WP_User Object
        $user = $order->get_user();
    
        // Check that it's not a guest customer
        if( is_a( $user, 'WP_User' ) && $user->ID > 0 ) {
            // Load settings
            $settings = variation_id_per_user_role_settings();
    
            // Loop through order items
            foreach ( $subscription->get_items() as $item ) {
                check_order_item_and_change_user_role( $item, $user, $settings );
            }
        }
    }
    
    // On switched purchased subscription
    add_action( 'woocommerce_order_status_changed', 'switched_subscription_change_user_role_on_order_status_change', 100, 4 );
    function switched_subscription_change_user_role_on_order_status_change( $order_id, $old_status, $new_status, $order ) {
        // When order status is updated to 'processing' or 'completed' status
        if ( in_array( $new_status, array('processing','completed') ) ) {
            // Get an instance of the customer WP_User Object
            $user = $order->get_user();
    
            // Check that it's not a guest customer
            if( is_a( $user, 'WP_User' ) && $user->ID > 0 ) {
                // Load settings
                $settings = variation_id_per_user_role_settings();
    
                // Loop through order items
                foreach ( $order->get_items() as $item ) {
                    check_order_item_and_change_user_role( $item, $user, $settings );
                }
            }
        }
    }
    

    Code goes in functions.php file of your active child theme (or active theme). It should works.

    Documentation: Subscriptions Action Hook Reference