1
votes

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');
}
2
Please go read How to Ask. You are expected to show us what you tried. Just telling us what you’re planning to do in an abstract way, is not a proper way to ask here.CBroe
Is this requires to based on the subscription status (like active) or on the parent order status? If it's the order status, for which status your order is approved? is it "processing" or "completed" status?LoicTheAztec
Yes it is based on the subscription status. By approved I meant Active subscription.Ben Kalsky
Sorry @LoicTheAztec I was wrong, the subscription status is not changing for upgrades and downgrades (stays active), so this requires to based the parent order "completed" status.Ben Kalsky

2 Answers

4
votes

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

1
votes

Bit updated code from LoicTheAztec. Made to work with different products in subscription.

<?php
// 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(
        //monthly subscriptions
        '530'  => 'subscriber',
        '740'  => 'subscriber-extended',
        '741'  => 'subscriber-advanced',
        //now to the yearly
        '536'  => 'subscriber',
        '739'  => 'subscriber-extended',
        '738'  => 'subscriber-advanced',
    );
}

// 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
    $variation_id = $item['product_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);
            }
        }
    }
}

//Remove subscriber role if subscription is not active
add_action('woocommerce_subscription_status_updated', 'switched_subscription_change_user_role_on_order_status_change_inactive', 100, 5);
function switched_subscription_change_user_role_on_order_status_change_inactive($subscription, $new_status, $old_status)
{
    if ($new_status !== 'active') {
        // Get an instance of the customer WP_User Object
        $order = wc_get_order($subscription->get_parent_id());
        $user = $order->get_user();
        // Check that it's not a guest customer
        if (is_a($user, 'WP_User') && $user->ID > 0) {
            $settings = variation_id_per_user_role_settings();
            foreach ($settings as $key_id => $value_role) {
                if (in_array($value_role, $user->roles)) {
                    $user->remove_role($value_role);
                }
            }
            $user->set_role('customer');
        }
    }
}