Home / Admin / WooCommerce: Restrict Shipping Methods by User Role (Logged In, Logged Out, Custom Roles)
Duplicate Snippet

Embed Snippet on Your Site

WooCommerce: Restrict Shipping Methods by User Role (Logged In, Logged Out, Custom Roles)

This snippet allows you to control which shipping methods are visible at checkout based on the customer's user role in WooCommerce.
- Supports all shipping methods (Flat Rate, Free Shipping, Local Pickup, etc.)
- Easily configure allowed roles per shipping method (including "Logged In" and "Logged Out")
-If no roles are selected, the shipping method remains available to everyone

Code Preview
php
<?php
// 💡 Load multiselect field to all shipping methods
add_action('woocommerce_init', 'woocommerce_shipping_instances_form_fields_filters');
function woocommerce_shipping_instances_form_fields_filters() {
    foreach (WC()->shipping->get_shipping_methods() as $shipping_method) {
        add_filter('woocommerce_shipping_instance_form_fields_' . $shipping_method->id, 'add_allowed_roles_field_to_shipping_methods');
    }
}
// 🎯 Add multiselect role option (styled like tag input)
function add_allowed_roles_field_to_shipping_methods($settings) {
    $settings['allowed_user_roles'] = array(
        'title'       => __('Allowed User Roles', 'woocommerce'),
        'type'        => 'multiselect', // Uses WooCommerce's select2 UI
        'class'       => 'wc-enhanced-select', // Enables tag-style dropdown
        'options'     => get_all_user_roles_with_extras(),
        'default'     => '',
        'desc_tip'    => true,
        'description' => __('Select roles that can access this shipping method (Can choose multiple). Leave empty to allow all.', 'woocommerce'),
    );
    return $settings;
}
// 🚫 Filter shipping methods per package based on selected roles
add_filter('woocommerce_package_rates', 'filter_shipping_methods_by_user_role_proper', 10, 2);
function filter_shipping_methods_by_user_role_proper($rates, $package) {
    $is_logged_in = is_user_logged_in();
    $user_roles   = $is_logged_in ? wp_get_current_user()->roles : [];
    foreach ($rates as $rate_id => $rate) {
        // WooCommerce rate ID is like "flat_rate:3"
        $rate_parts = explode(':', $rate_id);
        $instance_id = $rate_parts[1] ?? '';
        $method_id = $rate_parts[0];
        // Skip if instance ID not found
        if (!$instance_id || !isset(WC()->shipping()->get_shipping_methods()[$method_id])) {
            continue;
        }
        // Load method settings
        $zone = wc_get_shipping_zone($package);
        $zone_methods = $zone->get_shipping_methods();
        $matched_method = null;
        // Find matching instance
        foreach ($zone_methods as $method_obj) {
            if ($method_obj->instance_id == $instance_id) {
                $matched_method = $method_obj;
                break;
            }
        }
        if (!$matched_method || empty($matched_method->instance_settings['allowed_user_roles'])) {
            continue; // No restriction
        }
        $allowed_roles = (array) $matched_method->instance_settings['allowed_user_roles'];
        // If allowed for everyone (empty), keep
        if (empty($allowed_roles)) continue;
        // Allow if matches any allowed roles or pseudo roles
        if (
            ($is_logged_in && in_array('logged_in', $allowed_roles)) ||
            (!$is_logged_in && in_array('logged_out', $allowed_roles)) ||
            array_intersect($user_roles, $allowed_roles)
        ) {
            continue;
        }
        // ❌ Remove if no match
        unset($rates[$rate_id]);
    }
    return $rates;
}
// 🔄 Get all WP roles + pseudo-roles
function get_all_user_roles_with_extras() {
    global $wp_roles;
    $roles = $wp_roles->get_names();
    $roles = array_merge(
		$roles,
        ['logged_in' => __('Logged In Users', 'woocommerce')],
        ['logged_out' => __('Logged Out Users', 'woocommerce')]
        
    );
    return $roles;
}

Comments

Add a Comment