This code solves your simple paid membership site needs.
If you are selling one-time content and hiding some of the site sections with user role check. This code is for you.
I wrote this code for my upcoming WordPress Development Course site and this code is enough for my case.
I could probably make this work with a subscription membership payment method too but maybe another time 🙂
Features;
- Adding Custom Role “student” to WordPress:
- Adding a Special User Roles Section for Products:
- Custom User Role for Each Product:
- Giving Roles to Buyers When They Purchase The Role with the Product:
- Updating Roles When Users Log In (just incase if the role not assigned in first place. maybe payment failed manual confirmation needed…etc):
- Every time a user logs into the website, it checks what products they have bought in the past. If they bought something tagged for a special role, like “student”, and they don’t already have that role, the code will auto-assign it.

/**
* Function to add a new user role named "Student"
*/
function add_student_user_role() {
// Add a new user role with the name 'Student'
// The 'read' capability is a minimal capability that can be assigned
add_role('student', 'student', array('read' => true));
}
// Hook the function to WordPress 'init'
add_action('init', 'add_student_user_role');
// Add the custom tab
add_filter('woocommerce_product_data_tabs', 'add_user_role_custom_tab');
function add_user_role_custom_tab($tabs) {
$tabs['user_role_tab'] = array(
'label' => __('User Role', 'woocommerce'),
'target' => 'user_role_options',
'class' => array('show_if_simple', 'show_if_variable'),
);
return $tabs;
}
// Create the tab content
add_action('woocommerce_product_data_panels', 'user_role_options_product_tab_content');
function user_role_options_product_tab_content() {
global $post;
?><div id='user_role_options' class='panel woocommerce_options_panel'><?php
?><div class='options_group'><?php
// Dropdown for user roles
$roles = wp_roles()->get_names();
woocommerce_wp_select(array(
'id' => 'custom_user_role',
'label' => __('Select User Role', 'woocommerce'),
'options' => array('' => __('Select a role', 'woocommerce')) + $roles
));
?></div>
</div><?php
}
// Save the custom field
add_action('woocommerce_process_product_meta', 'save_user_role_option_fields');
function save_user_role_option_fields($post_id) {
$custom_user_role = isset($_POST['custom_user_role']) ? $_POST['custom_user_role'] : '';
update_post_meta($post_id, 'custom_user_role', sanitize_text_field($custom_user_role));
}
add_action('woocommerce_order_status_completed', 'assign_custom_user_role_on_purchase_optimized');
function assign_custom_user_role_on_purchase_optimized($order_id) {
$order = wc_get_order($order_id);
$user = $order->get_user();
if (!$user) {
// No user associated with the order
return;
}
// Fetch all roles once instead of checking in every iteration
$available_roles = array_keys(wp_roles()->get_names());
// Collect all product IDs from the order
$product_ids = array_map(function ($item) {
return $item->get_product_id();
}, $order->get_items());
// Remove duplicate product IDs to minimize redundant queries
$unique_product_ids = array_unique($product_ids);
// Loop through unique product IDs
foreach ($unique_product_ids as $product_id) {
$custom_role = get_post_meta($product_id, 'custom_user_role', true);
if (!empty($custom_role) && in_array($custom_role, $available_roles)) {
// Assign the custom role to the user
$user->set_role($custom_role);
// Break the loop as we've found a valid role and assigned it
break;
}
}
}
// Hook Function to Login
add_action('wp_login', 'assign_role_based_on_order_history');
function assign_role_based_on_order_history($user_login) {
$user = get_user_by('login', $user_login);
if (!$user) {
return;
}
$user_id = $user->ID;
// Fetch all roles once
$available_roles = array_keys(wp_roles()->get_names());
// Get all completed orders for the user
$orders = wc_get_orders(array(
'status' => 'completed',
'customer_id' => $user_id,
));
foreach ($orders as $order) {
foreach ($order->get_items() as $item) {
$product_id = $item->get_product_id();
$custom_role = get_post_meta($product_id, 'custom_user_role', true);
if (!empty($custom_role) && in_array($custom_role, $available_roles) && !$user->has_cap('custom_role')) {
// Add the custom role to the user without removing existing roles
$user->add_role($custom_role);
// Consider breaking the loop if only one role should be assigned
// break 2; // Uncomment to break out of both loops
}
}
}
}
Recommended Plugins with this code:
Blocks visibility Plugin: if you need to show or hide your some of your sections or posts depending on users status or roles you can use this free plugin.
User Role Editor Plugin: You can use this plugin if you want to add and sell other roles.