How to Set Up Role-Based Pricing in WooCommerce (Wholesale Without a Separate Store)
WooCommerce Strategy
One Store, Two Price Lists. Here’s How to Make It Work.
Wholesale pricing doesn’t require a second store or a full B2B platform. It requires understanding WordPress user roles β and knowing the three things most guides skip entirely.
You got your first email from a business wanting to buy in bulk. Or maybe a retailer found your store and wants reseller pricing. Either way, you’re suddenly thinking about something WooCommerce doesn’t solve out of the box: showing different prices to different types of customers, on the same store, without letting anyone see what they’re not supposed to see.
The instinct for many store owners at this point is either to create a separate private store for wholesale customers, or to start looking at enterprise B2B plugin suites that cost several hundred dollars a year. Both responses are understandable. Both are usually overkill for what is, at its core, a straightforward configuration problem.
WooCommerce role-based pricing β showing wholesale prices to verified wholesale customers while retail shoppers see the regular price β is achievable without a second store and without a full B2B platform. But most guides explaining how to do it skip the parts that actually trip people up: the user role architecture, the tax display mismatch between business and retail customers, and the approval workflow that keeps random shoppers from self-registering as “wholesale” and claiming your trade prices.
This guide covers all of it, in order.
The real problem with running wholesale on one WooCommerce store
Before getting into the mechanics, it’s worth naming why this feels complicated. It’s not because WooCommerce is incapable of it β it’s because wholesale and retail customers have genuinely different needs, and trying to serve both from one interface requires deliberate design choices at several layers.
Retail customers browse, discover, and buy impulsively. They respond to sale badges, urgency, and a smooth checkout. They expect consumer-standard prices including tax, and they’ve never heard of a minimum order quantity.
Wholesale customers behave like procurement teams. They know what they want, they need pricing that works at volume, and they expect prices quoted ex-tax because their accounting handles VAT/GST separately. They may need invoicing, specific payment terms, and they’re not interested in your flash sale countdown timers.
These differences explain why dedicated B2B platforms exist. But they don’t mean you need one unless the scale of your wholesale operation genuinely demands it. For many stores β particularly those with a modest number of wholesale accounts alongside a retail business β the answer is role-based pricing done carefully.
A pattern that keeps coming up
A handmade ceramics studio starts getting wholesale inquiries from boutique gift shops. They set up a second WooCommerce store, manage inventory in two places, and deal with double the maintenance. Six months later, they shut the second store down and consolidate onto one β with role-based pricing. The second store was never the answer. It was the path of least resistance at the time of least knowledge.
How WordPress user roles work (and why this is the foundation for everything)
Role-based pricing in WooCommerce is built on top of WordPress’s user role system, so understanding that system is non-negotiable. You don’t need to go deep on it β but you need the key concepts.
WordPress assigns every registered user a role. Each role carries a set of capabilities β permissions that determine what the user can do inside WordPress. By default, WordPress ships with six roles: Administrator, Editor, Author, Contributor, Subscriber, and Super Admin (for multisite). WooCommerce adds two more: Customer and Shop Manager.
When someone registers on your WooCommerce store, they’re assigned the Customer role by default. That role has limited capabilities β essentially, it means they can log in, view their account, and make purchases. They can’t access the WordPress admin. They can’t edit content. They’re just a buyer.
The power of this system for wholesale pricing is that you can create custom roles and write logic that responds to them. A user with the role wholesale_customer can be shown different prices, granted access to different content, and treated differently at checkout β all without touching your retail customers’ experience.
The key thing roles do not do automatically
Roles define who someone is. They don’t automatically do anything with that information. When you create a wholesale_customer role, WooCommerce won’t suddenly show that user different prices unless you specifically build or install that pricing logic. The role is the label. The behavior requires separate implementation β which is what the rest of this guide is about.
Creating a wholesale_customer role
The first concrete step is creating the custom role. You have two options: code it directly, or use a plugin to do it for you.
Option A: Code it yourself (one function, five minutes)
Add this to your theme’s functions.php file or a site-specific plugin:
function add_wholesale_customer_role() {
add_role(
'wholesale_customer',
'Wholesale Customer',
array(
'read' => true,
)
);
}
add_action( 'init', 'add_wholesale_customer_role' );
A few important notes about this code. The first argument is the machine name of the role β use lowercase letters and underscores only. The second is the human-readable label that appears in the WordPress admin. The third is the capabilities array: for a wholesale buyer, all you need is read (which allows them to log in and view their account). Don’t assign editing or publishing capabilities unless you have a specific reason to.
One thing that catches people out: add_role() writes to the database and only runs once. If you later change the capabilities array in your code, nothing will change β the role is already stored. To update it, you’d need to remove and re-add the role, or modify it using get_role() with add_cap(). For the purposes of a basic wholesale setup, the one-time write is fine.
Prefer plugins for role management?
User Role Editor (free, by Vladimir Garagulya) lets you create and manage custom roles through a UI without touching code. It’s straightforward, well-maintained, and a reasonable choice if you’re uncomfortable editing functions.php. The result is identical to the code approach above.
Option B: Use a dedicated wholesale plugin
Plugins like Wholesale Suite automatically create a wholesale_customer role during setup. If you’re going this route, you don’t need to create the role manually β it’s handled for you. The tradeoff is that you’re now dependent on that plugin’s implementation for everything downstream.
Assigning the role to customers
Once the role exists, you assign it to individual users from WordPress admin. Go to Users, find the customer account, edit their profile, and change the Role dropdown from “Customer” to “Wholesale Customer.” Save, and they now carry that role whenever they’re logged in.
This manual assignment is the simplest approach and the right one when you’re starting out with a handful of wholesale accounts. You vet each one personally before granting wholesale access. We’ll come back to automated registration workflows in a later section, because that’s where things get risky.
Your three pricing logic options (and when each one makes sense)
Having a wholesale_customer role is the infrastructure. What you do with it for pricing is a separate decision. There are three common approaches, and they have meaningfully different tradeoffs.
Option 1: Percentage discount off retail (role-wide)
The simplest model: wholesale customers get a fixed percentage discount applied to all products automatically when they’re logged in. If your retail price is $40 and wholesale is 30% off, logged-in wholesale accounts always see $28.
Good for: Stores with relatively consistent margins across their catalog, and wholesale buyers who need a clear, predictable discount they can communicate to their own customers.
The catch: A flat percentage ignores the margin reality of individual products. If some products have 60% margins and others have 20%, a blanket 30% discount is fine on the former and margin-destroying on the latter. You either need to be careful about which products are in scope, or accept the variability.
Option 2: Explicit wholesale price per product
Each product has a separate wholesale price field. Retail customers see the regular price. Wholesale accounts see the wholesale price. No calculation β you set the exact figure per product.
Good for: Stores with varied margin profiles, or where your wholesale pricing isn’t a clean percentage off retail (because you’ve negotiated specific trade prices, or because your costs vary significantly by SKU).
The catch: If you have a large catalog, maintaining a separate price field per product per role is tedious. It scales poorly. This approach works well when you have dozens of products, not hundreds.
Option 3: Tiered pricing by role
You create multiple wholesale roles β say wholesale_tier_1 and wholesale_tier_2 β each with different discount levels. A small independent retailer gets 20% off. A larger distributor who orders 10x the volume gets 35% off.
Good for: Stores with a genuine B2B operation where different wholesale accounts have different commercial relationships.
The catch: This adds real complexity. You’re now managing multiple roles, multiple pricing configurations, and potentially multiple approval workflows. Don’t start here. Build the single-role model first, and add tiers only if your business genuinely requires it.
Start simple and earn complexity
Most stores that overthink this upfront end up with a configuration they can’t maintain. Start with one wholesale role and a percentage discount. Add product-specific overrides later if you need them. Add multiple tiers only if you have multiple wholesale relationships that genuinely require different terms.
Implementing role-conditional pricing in WooCommerce
WooCommerce core does not include role-based pricing. You need either code or a plugin to apply different prices based on the logged-in user’s role. Here’s what each path looks like in practice.
The code approach (percentage discount)
This filter hooks into WooCommerce’s price output and applies a discount when the current user has the wholesale_customer role:
function apply_wholesale_pricing( $price, $product ) {
if ( is_admin() ) {
return $price;
}
if ( current_user_can( 'wholesale_customer' ) ) {
$wholesale_discount = 0.30; // 30% off
$price = $price * ( 1 - $wholesale_discount );
}
return $price;
}
add_filter( 'woocommerce_product_get_price', 'apply_wholesale_pricing', 10, 2 );
add_filter( 'woocommerce_product_get_regular_price', 'apply_wholesale_pricing', 10, 2 );
add_filter( 'woocommerce_product_variation_get_price', 'apply_wholesale_pricing', 10, 2 );
add_filter( 'woocommerce_product_variation_get_regular_price', 'apply_wholesale_pricing', 10, 2 );
You need all four filters to cover simple products, variable products, and their regular price variants. Missing any of them leads to price inconsistencies β the displayed price changes but the cart price doesn’t, or vice versa.
Mind the sale price filter
If your products use WooCommerce’s built-in sale price field (the crossed-out regular price with a lower sale price), you also need to filter woocommerce_product_get_sale_price and its variation equivalent. Otherwise, wholesale customers may see a sale price that’s lower than their discounted wholesale price β which is mathematically fine but looks confusing and can create unexpected pricing conflicts.
The plugin approach
If you’d rather not write PHP, several plugins handle the pricing logic for you. The free version of Wholesale Suite (the plugin behind the “Wholesale Customer” role) adds a wholesale price field to each product’s admin page, and displays that price to logged-in wholesale accounts automatically. You set the price per product, and the plugin does the display logic.
The limitation of the free version is that it’s product-by-product. Category-wide percentage discounts and multiple wholesale tiers require the premium version. That’s a fair tradeoff at the lower scale β if you have 20-30 products and a handful of wholesale accounts, the manual per-product approach is perfectly manageable.
Using a campaign-based discount plugin
There’s a third approach that’s worth understanding, particularly if you already use a campaign scheduling plugin on your store. Some plugins β including Smart Cycle Discounts β let you create discount campaigns with customer role targeting built in. You configure a campaign (percentage off, specific products or categories, active dates), and restrict it to a specific user role. Wholesale accounts who are logged in see the campaign price. Retail customers don’t.
This isn’t a replacement for dedicated wholesale pricing infrastructure if you need it. But if your wholesale pricing is effectively a structured ongoing discount for a defined group of customers, and you already use campaign-based discounting for retail promotions, this approach consolidates your discount management into one place rather than two separate systems.
The tax display problem that catches everyone off guard
This is the section that most guides skip, and it’s one of the most common sources of confusion for store owners moving into wholesale.
In most jurisdictions, retail consumers see prices inclusive of tax (VAT or GST). Business customers β wholesale buyers β typically need to see prices exclusive of tax, because they’ll reclaim the tax separately through their business accounting. These are two different ways of displaying the same underlying price, and they matter because the number displayed significantly affects whether your pricing looks competitive to each audience.
WooCommerce handles this through the tax settings. Under WooCommerce > Settings > Tax, you can configure how prices are displayed to customers. The option “Display prices during cart and checkout” can be set to “Including tax” or “Excluding tax.” The problem is that this is a global setting β it applies to everyone, not just to wholesale or retail customers separately.
If you sell to both retail consumers (who expect inclusive prices) and wholesale businesses (who expect exclusive prices), a single global setting will be wrong for at least one of them.
How to handle the tax display split
There are a few approaches, each with a different level of complexity:
- Show prices excluding tax by default, and note that consumers will see tax added at checkout. This is simpler but can feel unusual for retail shoppers accustomed to seeing the full price upfront.
- Use a plugin that switches tax display based on user role. Some wholesale plugins handle this automatically β wholesale accounts see ex-tax prices, retail accounts see inclusive prices. This is the cleanest solution if you need both simultaneously.
- Separate your wholesale-facing pages. If your wholesale customers primarily use a specific category or page, you can use conditional logic to display prices differently in that context. This is fragile to maintain but possible.
For most stores starting out with a handful of wholesale accounts, the pragmatic answer is to communicate the tax situation clearly to wholesale customers when you onboard them β “prices shown include tax, your invoice will show the ex-tax breakdown” β rather than trying to engineer a separate display from day one. As wholesale volume grows, invest in proper per-role tax display.
Tax compliance isn’t optional
Tax display is a UX issue. Tax calculation is a legal one. However you display prices, make sure your WooCommerce tax configuration actually calculates and remits tax correctly for both retail and wholesale transactions. If your wholesale customers are in a different country or state, you may have additional obligations around zero-rated supply or reverse charge mechanisms. This is an accountant conversation, not a plugin conversation.
Hiding prices and controlling what each role sees
There are two related but distinct visibility problems to solve.
Problem 1: Retail customers seeing wholesale prices
If wholesale prices are just conditional discounts applied via a filter, retail customers will never see them β they don’t have the wholesale role, so the filter doesn’t fire. This works automatically with the code approach described above.
Where it gets complicated is if you display wholesale prices openly anywhere β on a dedicated trade page, in a price list document, or in any publicly accessible location. Don’t. If you communicate trade prices, do it within a logged-in-only section or directly to your wholesale contacts. Price lists that leak publicly undermine your retail pricing and create awkward conversations with retail customers who find them.
Problem 2: Wholesale customers seeing retail prices
This is less obvious but worth considering. If a wholesale customer logs out and browses your store as a guest, they’ll see retail prices. If they then place an order without logging in, they pay retail. This can create support headaches and confusion about why their order total is different from what they expected.
The most reliable fix is to require login before prices are displayed to users you’ve identified as wholesale accounts. You can redirect wholesale-registered accounts to a login page when they visit unauthenticated. Alternatively, brief your wholesale customers to always log in before shopping β simple but effective for a small number of accounts.
Hiding “Add to Cart” from non-logged-in visitors
If your wholesale business is primarily B2B and you don’t want retail visitors purchasing at all (a pure wholesale store), WooCommerce lets you hide the Add to Cart button and replace it with a login prompt for guest visitors. This is sometimes called “catalog mode.” You can implement it with a short code snippet or a plugin β several free options exist. It’s a strong signal to visitors that this isn’t a public retail store, and it prevents accidental retail purchases in what’s meant to be a trade environment.
Registration and approval: don’t leave the gate open
This is where most role-based pricing setups fail β not technically, but operationally.
If you enable WooCommerce’s standard customer registration (which is on by default), anyone can create an account on your store. The default role they receive is Customer. That’s fine. But if you also create a public-facing registration form that assigns the wholesale_customer role automatically on signup, you’ve just let anyone self-register as a wholesale customer and claim your trade prices. That’s not fine.
The wholesale role should only be assigned after you’ve verified that someone is a legitimate business customer. The exact bar you set depends on your product and market β some stores require a business registration number, others just need a business email and a brief conversation. But the role assignment must be a deliberate act on your part, not an automatic response to a form submission.
Three ways to manage wholesale registration
- Fully manual. Wholesale customers contact you (email, inquiry form), you vet them, and you manually assign the role in WordPress admin. This doesn’t scale to hundreds of accounts, but it’s completely appropriate for dozens. You have full control, zero automation risk.
- Application form with admin approval. A registration form collects business details and puts the account into a pending state. The admin reviews and approves (which assigns the role). This requires a plugin β Wholesale Suite’s Lead Capture add-on does this, as do various registration management plugins. It’s the right approach once manual management gets tedious.
- Automated with verification. Some stores automate role assignment based on criteria like business email domain or tax ID number. This is generally too permissive unless you can programmatically verify what you’re checking. Domain checks can be spoofed. Tax ID verification requires an API. Don’t automate this unless you have a reliable verification mechanism.
What open registration actually costs you
A stationery brand set up a wholesale registration form that automatically assigned the wholesale role on signup. Within a week, several retail customers had registered using business-sounding names and were purchasing at a 35% discount. The dollar cost was manageable. The harder problem was that their genuine wholesale accounts β who valued exclusive trade pricing β saw the program as meaningless once they realized anyone could access it. Trust in the program collapsed. They ended up reverting to manual role assignment and contacting existing wholesale accounts to explain what had happened.
Wholesale-lite vs. a full B2B suite: how to know which you need
The approach described in this guide β a custom user role, role-conditional pricing, manual or semi-automated account approval β is what I’d call “wholesale-lite.” It handles the core requirement: different prices for different customers, on one store, without the overhead of a dedicated B2B platform.
But there are genuine limits to it. Here’s an honest assessment of when wholesale-lite is enough, and when it isn’t.
| Scenario | Wholesale-lite | Full B2B suite |
|---|---|---|
| Fewer than 50 wholesale accounts | Works well | Overkill |
| Single discount tier for all wholesale customers | Works well | More than needed |
| Multiple pricing tiers across wholesale accounts | Workable with multiple roles | Built for this |
| Wholesale customers need invoicing and payment terms | Not supported | Core feature |
| Minimum order quantities per product | Requires additional plugin | Usually included |
| Bulk ordering forms (add 50 SKUs at once) | Not supported | Core feature |
| Wholesale customers need their own portal/dashboard | Not supported | Core feature |
| Per-role tax display (ex-tax for wholesale, inc-tax for retail) | Requires plugin | Built in |
If your wholesale customers are primarily just “loyal bulk buyers” and not genuine B2B procurement accounts, wholesale-lite is probably sufficient for a long time. If your wholesale operation is growing into a distinct business line with its own operational needs, the dedicated B2B suite investment starts to make sense β not because the role-based approach is wrong, but because the operational complexity justifies the infrastructure.
Four mistakes that quietly undermine wholesale setups
These don’t all announce themselves. Some take weeks to surface as a problem.
Mistake 1: Open wholesale registration
Already covered above, but worth naming explicitly as the first mistake because it’s the most damaging. Any form that assigns a wholesale role automatically on submission is a risk. Vet first, assign second.
Mistake 2: Forgetting the cart and checkout prices
When you apply role-based pricing via a WooCommerce price filter, you need to make sure the discount applies consistently across product pages, category pages, the cart, and the checkout. Different hooks control different parts of the price display. Test the full purchase journey as a logged-in wholesale account before going live. Don’t assume that filtering the product price automatically updates everything downstream.
Mistake 3: Applying wholesale discounts on top of existing sale prices
If a product is already on sale (using WooCommerce’s regular/sale price fields), and your wholesale price filter applies a percentage off the current price, wholesale customers may get a discount stacked on top of a discount. That’s probably not what you intended. Decide whether wholesale pricing should apply to the regular price or the sale price β and make sure your code or plugin reflects that decision consistently.
Mistake 4: No expiry or review process for wholesale accounts
Business relationships change. A wholesale account that was a legitimate small retailer two years ago may no longer be in business β or worse, may have changed hands and is now being used inappropriately. It’s worth building a lightweight review process: annually or semi-annually, confirm that your wholesale accounts are still active businesses with an ongoing commercial relationship with you. Remove or downgrade the role for accounts that go quiet. A wholesale pricing program without maintenance slowly becomes a discount program for people you’ve lost track of.
Frequently asked questions
Can I show wholesale prices to logged-in users only, without hiding prices from everyone else?
Yes. The role-based pricing filters described in this guide apply only to users with the wholesale role. All other visitors β including guests and regular customers β see the standard retail price. You don’t have to hide prices from anyone; you simply show additional (discounted) pricing to the specific role.
Does WooCommerce have built-in role-based pricing?
No. WooCommerce core does not include role-based pricing as a native feature. You need either custom PHP code (using WooCommerce’s price filters) or a third-party plugin to implement it. The user role system comes from WordPress itself; the pricing logic on top of it requires additional implementation.
What happens if a wholesale customer places an order while logged out?
They’ll pay retail prices. The role-based discount only applies when the user is authenticated and their session carries the wholesale role. This is worth communicating to wholesale accounts during onboarding β they should always log in before adding items to their cart. For a more robust solution, you can redirect logged-out users with known wholesale email addresses to a login page, though this requires additional logic.
Can I have multiple wholesale tiers β say, silver, gold, and platinum wholesale customers β each with different discounts?
Yes. You create a separate role for each tier (e.g., wholesale_silver, wholesale_gold, wholesale_platinum), and your pricing logic checks which role the current user has and applies the corresponding discount. This works but adds meaningful complexity β you’re managing multiple roles, multiple pricing configurations, and potentially different registration/approval criteria for each tier.
How do I stop wholesale customers from using retail coupons?
WooCommerce doesn’t offer role-based coupon restrictions natively, but you can build it with a filter. The woocommerce_coupon_is_valid hook lets you check the current user’s role and return false (invalid) for wholesale accounts trying to use a coupon that shouldn’t apply to them. Some wholesale plugins include this restriction as a built-in option.
Will role-based pricing work with WooCommerce’s High-Performance Order Storage (HPOS)?
Yes. Role-based pricing operates at the product price and cart calculation layer, not the order storage layer. HPOS affects how completed orders are stored and retrieved β it doesn’t change how prices are calculated during the shopping session. If you’re using a plugin for wholesale pricing, check that the plugin is marked HPOS compatible in its changelog or readme, as older plugins may have HPOS-adjacent issues with order queries.
Do I need a separate WooCommerce store for wholesale customers?
No, and in most cases you shouldn’t. A second store doubles your maintenance burden β two sets of products to update, two inventory systems to keep in sync, two sets of orders to manage. Role-based pricing on a single store handles the core requirement (different prices for different customers) without the operational overhead. A separate store only makes sense if your wholesale and retail operations are genuinely distinct businesses with different product catalogs, branding, and fulfillment systems.
Wrapping up
Wholesale pricing on a single WooCommerce store is a solved problem β just not a simple one. The mechanics are manageable once you understand the architecture: WordPress user roles provide the customer segmentation, WooCommerce price filters (or a plugin) apply the logic, and a handful of operational decisions around tax display, visibility, and account approval determine whether it actually works in practice.
The places this tends to go wrong aren’t technical. They’re decisions made too quickly: an open registration form, a flat discount that ignores margin variation, a tax display that confuses business customers, or an account list that nobody reviews for two years. The plumbing is the easy part. The judgment calls around it are where the work is.
Start small. One wholesale role, one discount tier, manual account approval. Build the simplest version that serves your current wholesale accounts well. If you outgrow it, you’ll know exactly what complexity you’re adding and why β and that’s a much better position than building a full B2B platform for three wholesale accounts that reorder twice a year.
Key takeaways
- WooCommerce doesn’t include role-based pricing natively β you need PHP code or a plugin to apply different prices based on user role.
- The foundation is a custom WordPress user role (e.g.,
wholesale_customer), created withadd_role()and assigned manually to verified accounts. - Start with a single wholesale tier and a percentage discount. Add per-product overrides or multiple tiers only when your actual business requires it.
- Never automate wholesale role assignment on signup. Vet accounts first, assign the role second β the integrity of your pricing program depends on it.
- Tax display differences between retail and wholesale customers are real and often overlooked. Decide how to handle this before wholesale customers start asking why their prices look different than expected.
- Test the full purchase journey as a wholesale account β product page, category page, cart, checkout β before going live. Price filters need to fire consistently across all surfaces.
- A second store is almost never the answer. One store with role-based pricing handles the core problem without doubling your maintenance overhead.
If you’re thinking about how to layer campaign discounts alongside wholesale pricing without the two systems conflicting, the Webstepper guide on WooCommerce discount strategy covers several related topics including campaign conflict handling and discount priority.