Building Shopify B2B themes and portals.
How themes detect a wholesale buyer, gate content, render quantity rules and volume pricing, and wire sign-in. And where the theme stops and the portal begins.
A Shopify B2B theme becomes B2B-aware through a small set of Liquid objects: customer.b2b? detects the logged-in wholesale buyer, company and company_location expose who they buy for, and variant.quantity_rule and variant.quantity_price_breaks render their catalog terms. Free Shopify themes display quantity rules from version 8.0.0 and volume pricing from version 11.0.0, and Trade is Shopify's purpose-built B2B theme. The theme handles presentation only: approvals, quoting, order search, and invoice payment need a portal layer on top.
Search for a Shopify B2B theme and you get listicles ranking theme names. That answers the wrong question. On Shopify, B2B pricing, quantity rules, and catalogs live in the platform, not the theme: price lists resolve through any theme's normal price outputs once a buyer signs in, because variant.price, variant.quantity_rule, and variant.quantity_price_breaks all return values in the current customer context. What a theme decides is presentation: who sees prices, how volume terms display, where buyers sign in, and what a company contact sees that a retail visitor does not.
This chapter covers the four jobs of Shopify B2B theme development: detecting the buyer in Liquid, gating B2B-only content, rendering quantity rules and volume pricing, and wiring login entry points. It closes with the line where a theme stops and a B2B portal begins.
Which Shopify theme is best for B2B?
Trade is Shopify's B2B-optimized free theme. It ships with a quick order list, quantity rule display, volume pricing, and customer account requests prebuilt, and it hides pricing from users who are not logged in. Shopify's B2B customization docs name Trade and Horizon as the specialized themes for dedicated B2B stores.
You do not need Trade, or any dedicated wholesale theme, to run B2B. Free Shopify themes at version 11.0.0 or later display quantity rules, volume pricing, and the quick order list automatically. Older and custom themes support all of it too; they just need the manual Liquid and JavaScript covered below.
| B2B display capability | Free Shopify themes | Older or custom themes |
|---|---|---|
| Quantity rules on product pages | Automatic from v8.0.0 | Manual code (product template, theme JS, locale files) |
| Volume pricing display | Automatic from v11.0.0 | Manual code, per Shopify's advanced tutorial |
| Quick order list section | Included from v11.0.0 | Manual Liquid + JavaScript |
| No-code B2B overrides in the theme editor | Shopify Plus only (the "Shopify B2B" context) | |
| No-code market overrides in the theme editor | Advanced plan or higher | |
One clarification for plan shoppers: B2B itself is not Plus-exclusive. Volume pricing and quantity rules work in themes on every plan that supports B2B. The plan differences sit elsewhere: Basic, Grow, and Advanced stores get up to 3 active B2B catalogs across all B2B markets, while Plus gets unlimited catalogs and can assign them directly to company locations, with a ceiling of 25 catalogs per location.
How does Liquid detect a B2B buyer?
Shopify exposes B2B state to themes through the customer, company, and company_location objects:
customer.b2b?returns true when the logged-in customer is a verified B2B customer (a company contact). This is the canonical check for rendering B2B-only content.customer.current_companyreturns the company the customer is purchasing for;customer.current_locationreturns the currently selected company location.customer.company_available_locationsreturns every location the customer can buy for, withcustomer.company_available_locations_countalongside it.- The
companyobject exposesname,id,external_id, its available locations, andmetafields, so company-level data can drive theme content. - The
company_locationobject exposesname,shipping_address,tax_registration_id,metafields, acurrent?flag, andurl_to_set_as_current, a URL that switches the buyer's active purchasing location.
Those last two properties are everything you need for a location picker. This snippet is adapted from Shopify's documented reference implementation:
{% if customer.b2b? %}
<div>
<h2>Welcome, {{ customer.name }} from {{ customer.current_company.name }}</h2>
<p>You are purchasing for the {{ customer.current_location.name }} location.</p>
{% if customer.company_available_locations.size > 1 %}
<h3>Select a different location:</h3>
<ul>
{% for location in customer.company_available_locations %}
{% unless location.current? %}
<li>
<a href="{{ location.url_to_set_as_current }}">{{ location.name }}</a>
</li>
{% endunless %}
{% endfor %}
</ul>
{% endif %}
</div>
{% endif %}One Liquid constraint to remember when a buyer has many locations: for loops render at most 50 iterations, so paginate larger location arrays.
How do you build B2B-only content patterns?
The workhorse pattern for wholesale storefronts hides prices and purchase CTAs from anyone who is not a signed-in B2B buyer, and offers sign-in instead. Shopify documents this exact approach:
{%- if customer.b2b? -%}
{{ product.selected_or_first_available_variant.price | money }}
{%- else -%}
<a href="{{ routes.account_login_url }}">Log in to see the price</a>
{%- endif -%}Dedicated B2B stores extend the same conditional to the header cart icon, add-to-cart buttons, and other CTAs. Content can also target a specific company or location:
{% if customer.current_company.name == 'Shopify' %}
<h3>Delivery and installation included.</h3>
{% endif %}Two implementation notes. First, Shopify recommends adding B2B logic through Custom Liquid sections and blocks rather than editing theme files directly, which keeps Theme Store themes eligible for automatic upgrades. Second, on Shopify Plus there is a no-code alternative: the theme editor's Shopify B2B context lets you override section and block settings, visibility, and ordering for B2B buyers without touching Liquid. Overrides break inheritance from the store default until reset, and in contexts with custom section ordering, sections added later to the default are not inherited automatically; configure them per context.
How do you display quantity rules and volume pricing?
Quantity rules and volume pricing are set on B2B catalogs, not in the theme. The theme's job is display. variant.quantity_rule returns the rule for the current buyer with three properties: min (default 1), max (nil if unset), and increment (default 1). Shopify enforces rule integrity at creation: the increment must divide both the minimum and the maximum, and the minimum cannot exceed the maximum.
{% assign rule = product.selected_or_first_available_variant.quantity_rule %}
{% if rule.min > 1 or rule.increment > 1 or rule.max %}
<p class="quantity-rule">
Minimum {{ rule.min }}
{%- if rule.max %} · Maximum {{ rule.max }}{% endif %}
{%- if rule.increment > 1 %} · Sold in increments of {{ rule.increment }}{% endif %}
</p>
{% endif %}Volume pricing renders from variant.quantity_price_breaks, an array of break objects with minimum_quantity and price in the buyer's presentment currency. variant.quantity_price_breaks_configured? tells you whether any breaks exist in the current context, which makes a clean guard for a price-break table:
{% assign v = product.selected_or_first_available_variant %}
{% if v.quantity_price_breaks_configured? %}
<table class="volume-pricing">
<caption>Volume pricing</caption>
<tr><th>Quantity</th><th>Price each</th></tr>
<tr><td>{{ v.quantity_rule.min }}+</td><td>{{ v.price | money }}</td></tr>
{% for break in v.quantity_price_breaks %}
<tr><td>{{ break.minimum_quantity }}+</td><td>{{ break.price | money }}</td></tr>
{% endfor %}
</table>
{% endif %}Because both objects resolve in the current customer context, logged-out visitors and D2C customers never see catalog-specific pricing; no extra gating is required around the price outputs themselves. For bulk ordering surfaces built on these objects, including the quick order list, see quick order lists and bulk buying.
Where do B2B buyers sign in?
B2B requires new customer accounts. Buyers sign in with the email attached to a company location plus a one-time code sent to that email; there are no passwords, and legacy customer accounts cannot be used for B2B customers or orders. After sign-in, a buyer with one location goes straight to the store; a buyer with several must pick a company location before adding to cart.
Themes wire the entry points through the routes object:
routes.account_login_urlsends the customer to sign-in, then to their order index.routes.storefront_login_urlsigns the customer in, then returns them to the storefront page they came from. Use this on gated product pages.routes.account_urllinks directly to the customer account, andshop.customer_accounts_enabledguards the whole block. Thecustomer_login_linkfilter generates a ready-made sign-in anchor.
{%- if shop.customer_accounts_enabled -%}
{% if customer %}
<a href="{{ routes.account_url }}">Account</a>
{% else %}
<a href="{{ routes.account_login_url }}">Sign in</a>
{%- endif %}
{%- endif -%}For custom flows, /customer_authentication/login?return_to=<relative-url> redirects the buyer to any storefront page after sign-in (relative URLs only), and a login_hint parameter prepopulates the email field. The sign-in link itself can live anywhere: header, footer, navigation menu items, or a direct email to the buyer.
Blended or dedicated store: what changes in the theme?
A blended store serves B2B and D2C from one storefront. On free themes v11.0.0+, you customize by context in the theme editor; on custom themes, you branch on customer.b2b?. Third-party locking apps can hide parts of the store from visitors who are not signed in. Note the account-system consequence: switching a blended store to new customer accounts affects your D2C customers too.
A dedicated B2B store flips the defaults: Shopify recommends the specialized themes (Trade, Horizon) and, optionally, a third-party locking app to restrict the whole store to B2B customers. There is no native storefront-wide B2B gate; full-store locking is app territory, not a theme setting.
Headless storefronts follow the same logic without Liquid: contextualize Storefront API queries with a customer access token plus a companyLocationId to get B2B pricing, volume pricing, and quantity rules. Without that contextualization, queries return base pricing and publishing. Headless B2B also works only with new customer accounts.
Where does the theme stop and the portal begin?
Everything above is presentation: the theme shows the right buyer the right prices, rules, and content. What a theme cannot add is workflow. The customer account behind routes.account_url is where B2B buyers actually operate, and its native surface is thin. The split looks like this:
| Capability | Status | Where it lives |
|---|---|---|
| Contextual pricing, quantity rules, volume pricing display | NATIVE | Any theme, via catalog-aware Liquid objects |
| B2B content gating and location switching | NATIVE | Theme Liquid or Plus theme-editor context |
| Quick order list | NATIVE | Free themes v11.0.0+, or manual code |
| Order search by PO, SKU, or location, beyond a basic order list | NOT NATIVE | Portal app: order search & reporting |
| Order approvals and role ceilings | NOT NATIVE | Portal app: approvals |
| Quoting inside the account | NOT NATIVE | Portal app: quoting |
| Paying multiple invoices at once | NOT NATIVE | Portal app: batch invoice payment |
This is why "shopify b2b portal" and "shopify b2b theme" are different searches with different answers. The theme is the storefront skin; the portal is the account workspace. Portal functionality lives inside the customer account, the surface apps extend through Customer Account UI Extensions. That is where B2B Supercharge adds its modules, in the customer account your theme already links to: Account Tools for buyer-managed teams, roles, approvals, and order search; Buying Tools for quotes, fast reorder, saved carts, and CSV upload; Payments for batch-paying invoices. No theme swap, no replatform: it installs as a Shopify app, and buyers stay in the account they already sign into.
Practical sequencing. Pick the theme last. First confirm your catalogs, quantity rules, and companies are modeled correctly, then decide blended versus dedicated, then choose Trade, a v11.0.0+ free theme, or your existing custom theme with the snippets above. If buyers need approvals, quotes, or invoice workflows, that is a portal decision, not a theme decision. The full list of native gaps lives in the Constraints Ledger.
Frequently asked questions
How do I show content only to B2B customers in a Shopify theme?
Wrap it in a customer.b2b? conditional, which returns true only for logged-in, verified B2B customers. On Shopify Plus, the theme editor's Shopify B2B context achieves the same result without code.
Is there a Shopify theme built for B2B?
Yes. Trade is Shopify's B2B-optimized free theme, with a prebuilt quick order list, quantity rules, volume pricing, and customer account requests, and it hides pricing from non-logged-in users. Shopify's docs also name Horizon as a specialized option for dedicated B2B stores.
Do free Shopify themes display quantity rules and volume pricing automatically?
Yes. Free Shopify themes render quantity rules from version 8.0.0 and volume pricing plus the quick order list from version 11.0.0. Older or custom themes need Shopify's manual code tutorial.
Do I need Shopify Plus to build a B2B theme?
No. Volume pricing and quantity rules work in themes on every plan that supports B2B, with a 3-active-catalog limit below Plus. Only the theme editor's B2B customization context is Plus-exclusive.
How do B2B customers log in to a Shopify store?
Through new customer accounts: email plus a one-time code, no passwords. Themes link sign-in via routes.account_login_url or routes.storefront_login_url, and legacy customer accounts cannot be used for B2B.
Can one Shopify store serve both B2B and D2C with different presentation?
Yes, that is Shopify's blended model. Use the theme editor's B2B context on Plus, market contexts on Advanced or higher, or customer.b2b? conditionals in a custom theme; third-party locking apps can hide sections from visitors who are not signed in.
How does a B2B buyer switch company locations on the storefront?
A theme location picker lists customer.company_available_locations and links each one to its url_to_set_as_current. Visiting that URL makes it the buyer's active purchasing location.
Does a B2B theme replace a B2B portal?
No. Themes handle storefront presentation; the account workspace where buyers search orders, approve purchases, accept quotes, and pay invoices is a separate layer. B2B Supercharge modules add those workflows inside the native customer account.
Sources · verified 2026-07-12
Your theme renders the terms. The portal runs the account..
B2B Supercharge adds approvals, order search, quoting, and batch invoice payment inside the customer account your theme already links to. The base platform is free; every module switches on independently.