Search code examples
phpwordpresswoocommercehook-woocommerceorders

Restrict user role to change only some order statuses in Woocommerce


I would like to restrict access by role to certain order statuses from the dropdown list in woocommerce. I have tried in functions.php child theme the code on Restrict woocommerce order status by role but cannot get it to work and do not have enough rep to post a comment.

https://prnt.sc/mpfl3b is the screenshot of what is showing - I would like shop manager (or a custom role created) to only be able to mark an order as processing or on-hold with no other options visible from the dropdown.

Any advice will be appreciated.


Solution

  • The linked answer code will not work for what you want. Instead try the following:

    // Admin orders list: bulk order status change dropdown
    add_filter( 'bulk_actions-edit-shop_order', 'filter_dropdown_bulk_actions_shop_order', 20, 1 );
    function filter_dropdown_bulk_actions_shop_order( $actions ) {
        $new_actions = [];
        foreach( $actions as $key => $option ){
            // Targeting "shop_manager" | order statuses "on-hold" and "processing"
            if( current_user_can('shop_manager') && in_array( $key, array('mark_on-hold', 'mark_processing') ) ){
                $new_actions[$key] = $option;
            }
        }
        if( sizeof($new_actions) > 0 ) {
            return $new_actions;
        }
        return $actions;
    }
    
    // Admin order pages: Order status change dropdown
    add_filter('wc_order_statuses', 'filter_order_statuses');
    function filter_order_statuses($order_statuses) {
        global $pagenow;
    
        if( $pagenow === 'post.php' || $pagenow === 'post-new.php' ) {
            $new_order_statuses = array();
    
            foreach ($order_statuses as $key => $option ) {
                // Targeting "shop_manager" | order statuses "on-hold" and "processing"
                if( current_user_can('shop_manager') && in_array( $key, array('wc-on-hold', 'wc-processing') ) ){
                    $new_order_statuses[$key] = $option;
                }
            }
            if( sizeof($new_order_statuses) > 0 ) {
                return $new_order_statuses;
            }
        }
        return $order_statuses;
    }
    

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