Modern B2B digital commerce imposes rigorous architectural requirements on software engineering teams. Business purchasers demand negotiated contract rate tables, minimum order quantities (MOQ), and transparent volume-based discounts. Concurrently, search engines and AI shopping assistants require standardized, machine-readable data detailing unit costs and wholesale thresholds. Any discrepancy between feed prices and checkout cart calculations leads to product disapprovals in Google Merchant Center.
Implementing a scalable volume pricing infrastructure within WooCommerce requires moving beyond legacy post metadata patterns. Engineering teams must introduce dedicated relational tables, deploy memory-safe XML and NDJSON feed generation pipelines, and construct granular Schema.org semantic graphs to guarantee sustained indexing compliance.
Google Merchant Center technical specifications for wholesale and unit pricing
Google Merchant Center enforces strict rules regarding goods distributed by weight, volume, length, or bulk unit packages. In the EU, EFTA countries, the UK, Australia and New Zealand, Google requires unit pricing for products that local regulations say must show it, so that buyers immediately perceive the comparative cost per standardized base unit (such as price per kilogram, liter, or square meter).
The core technical feed attributes comprise:
unit_pricing_measure: The actual physical quantity or dimension contained within the sales unit (such as25kg,500ml, or100ct). This value informs parsing engines of the package contents.unit_pricing_base_measure: The baseline comparative denominator (such as1kg,100ml, or1ct). Google utilizes this metric to generate standardized unit price badges.auto_pricing_min_price: The lowest price to which Google may reduce a product in automated discounts and dynamic promotions.loyalty_program: A group attribute for member prices, member shipping and loyalty points. It is the only place for prices that depend on joining a program; there is no separate wholesale tier attribute.
Submitting malformed dimension units or mismatched currency denominations generates critical rejections during merchant catalog validation. For example, if an industrial chemical lubricant is marketed in a 20-liter container priced at 180 EUR, the feed must designate unit_pricing_measure as 20l and unit_pricing_base_measure as 1l, allowing search engines to calculate and display the corresponding 9 EUR per liter unit metric.
How to submit tiered B2B prices in a Google Merchant Center feed
Google’s product data specification has no attribute for quantity tiers. A feed item carries one price, and Google’s price attribute rules define which number that has to be. If a minimum order quantity applies, the feed price is the price for that minimum quantity: Google tells merchants not to submit a single-item price when customers cannot buy just one. For a retailer-made multipack or bundle, the price is the total for the whole pack.
That leaves three workable ways to expose a volume ladder:
- Separate pack products. Each pack size (single pail, carton, pallet) becomes its own item with its own
id,priceandunit_pricing_measure, and all of them share oneitem_group_id. Google’s unit_pricing_measure documentation shows this pattern with rice sold in 5, 10 and 12 lb bags, each with a 1 lb base measure, so the unit price tells the buyer which pack is cheaper per unit of weight. - The
multipackattribute. According to the multipack page, it is meant for packs the retailer assembled from identical products, and it is required for free listings once you create such a pack. For a manufacturer-defined pack you leavemultipackout and express the count throughunit_pricing_measure. - The tier table stays on the site. Quantity breaks above the minimum live in WooCommerce and on the product page, while the feed carries the entry price. This option does not multiply SKUs, and it stays consistent as long as the landing page shows the same entry price.
For the unit price itself, both attributes must use the same unit type, and unit_pricing_base_measure accepts only specific values: 1, 2, 4, 8, 10 or 100 of a unit, plus 75cl, 750ml, 50kg and 1000kg (unit_pricing_base_measure). The measure takes at most two decimal places. For the UK, Google reads imperial units as US imperial, so metric values are the safe choice. If an item carries both unit_pricing_measure and an energy efficiency class, Google shows only the energy class.
Which landing page and checkout rules disapprove B2B products in Merchant Center
Most B2B disapprovals come from the gap between the feed and what a buyer sees. The price attribute rules contain the constraints that collide with typical wholesale setups:
- The feed price must match the price on the landing page and at checkout, in the target country’s currency, and “view price in cart” is not allowed.
- Any user in the target country must be able to buy at the submitted price. An account requirement is allowed only when signup is free and straightforward, which rules out feeds built from prices that only approved trade accounts can see.
- In countries such as Germany, France and the UK the price includes VAT, and Google applies this to wholesale offers as well. In the US and Canada, tax stays out of the price.
- A minimum order value is not part of the price. It belongs in the shipping settings.
Contract and member prices have their own channel. Google states that member prices must not go into price or sale_price; they go into the loyalty_program group attribute, with sub-attributes such as program_label, tier_label, price, loyalty_points and member_price_effective_date. The program has to be set up in Merchant Center first, member prices must be visible to members on the site, and Google shows member pricing in ads only when the discount reaches at least 5% or 5 currency units. Google’s examples are customer tiers such as silver and gold, not verified business accounts, so a B2B store has to check whether its trade price list fits that model at all.
A time-limited tier promotion belongs in sale_price, which must be lower than price. The full price keeps going into price, the landing page shows both prices, checkout shows only the sale price, and sale_price_effective_date limits the period; without it the sale price applies immediately. auto_pricing_min_price is a different tool: Google’s minimum price attribute is required for automated discounts and dynamic promotions and must sit between the cost of goods sold, if you provide it, and 95% of the regular price.
Database bottlenecks in wp_postmeta and a custom price tier table
The default WordPress content architecture employs an Entity-Attribute-Value (EAV) model, routing product and variant metadata into the monolithic wp_postmeta table. While adequate for basic retail catalogs, this design breaks down when managing complex B2B matrices. When a single industrial component features 6 distinct volume breaks across 8 separate wholesale buyer tiers, metadata storage requirements escalate dramatically.
Representing 48 pricing rules for one product requires 48 independent rows in wp_postmeta. Across an enterprise catalog encompassing 40,000 SKUs and associated variations, the metadata table quickly swells beyond tens of millions of records. Standard catalog queries generate nested LEFT JOIN chains, triggering table locking and severe memory contention in the MySQL InnoDB buffer pool.
High-Performance Order Storage (HPOS) does not solve this on its own. According to the WooCommerce HPOS documentation, it moves orders and order addresses into four dedicated tables (wc_orders, wc_order_addresses, wc_order_operational_data and wc_orders_meta), while products stay in the posts tables. What HPOS offers is the pattern: data with a known shape gets its own table with indexes that match the queries. For price tiers that means a separate, composite-indexed table:
-- Dedicated relational table for high-performance B2B price tiers
CREATE TABLE IF NOT EXISTS wp_wc_b2b_price_tiers (
tier_id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
product_id BIGINT UNSIGNED NOT NULL,
customer_group VARCHAR(32) NOT NULL DEFAULT 'all',
min_quantity INT UNSIGNED NOT NULL DEFAULT 1,
max_quantity INT UNSIGNED DEFAULT NULL,
price_cents BIGINT NOT NULL,
currency CHAR(3) NOT NULL DEFAULT 'EUR',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_product_lookup (product_id, customer_group, min_quantity),
INDEX idx_pricing_search (min_quantity, max_quantity)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;With the composite index (product_id, customer_group, min_quantity), a lookup for one product, customer group and quantity becomes a single index range read instead of a chain of joins on wp_postmeta. Eliminating queries against wp_postmeta keeps response times predictable and frees server memory for checkout concurrency.
To evaluate how enterprise stores integrate complex catalog databases with external corporate ERPs, explore our comprehensive technical review covering woocommerce erp integration.
Streaming XML and NDJSON feed generation pipelines
Transmitting tens of thousands of B2B products alongside multi-tiered price breaks to Google Merchant Center requires memory-efficient export architecture. Attempting to assemble an entire catalog into a single PHP array using standard helpers like wc_get_products() rapidly exhausts server memory limits, causing fatal script terminations.
High-throughput B2B feed systems deploy database chunk cursors paired with PHP streaming generators (yield). This design writes product nodes directly to local disk storage or streams NDJSON payloads to cloud object buckets in controlled micro-batches:
<?php
/**
* Memory-safe streamed product feed generator for Google Merchant Center
*/
declare(strict_types=1);
namespace WPPoland\B2BFeeds;
use Generator;
use wpdb;
class StreamedProductFeedGenerator
{
private wpdb $db;
public function __construct(wpdb $db)
{
$this->db = $db;
}
public function streamCatalogBatch(int $batchSize = 500): Generator
{
$offset = 0;
while (true) {
$query = $this->db->prepare(
"SELECT p.ID, p.post_title, t.min_quantity, t.price_cents, t.currency
FROM {$this->db->posts} p
INNER JOIN wp_wc_b2b_price_tiers t ON p.ID = t.product_id
WHERE p.post_type IN ('product', 'product_variation')
AND p.post_status = 'publish'
AND t.customer_group = 'wholesale_tier_1'
ORDER BY p.ID ASC
LIMIT %d OFFSET %d",
$batchSize,
$offset
);
$rows = $this->db->get_results($query, ARRAY_A);
if (empty($rows)) {
break;
}
foreach ($rows as $row) {
yield $this->formatGoogleXmlNode($row);
}
$offset += $batchSize;
}
}
private function formatGoogleXmlNode(array $product): string
{
$price = number_format($product['price_cents'] / 100, 2, '.', '');
return sprintf(
"<item>\n <g:id>%d</g:id>\n <g:title><![CDATA[%s]]></g:title>\n <g:price>%s %s</g:price>\n <g:min_handling_time>1</g:min_handling_time>\n</item>\n",
$product['ID'],
htmlspecialchars($product['post_title'], ENT_QUOTES, 'UTF-8'),
$price,
$product['currency']
);
}
}Because only one batch of 500 rows sits in memory at a time, memory use depends on the batch size rather than on the size of the catalog. Scheduling feed compilation via WP-CLI workers or system cron jobs ensures that background data processing never impedes real-time buyer transactions.
To protect automated export endpoints and prevent unauthorized access to sensitive wholesale pricing feeds, schedule an in-depth wordpress security audit.
Structured schema.org markup using PriceSpecification and unitCode
Presenting accurate pricing signals to search crawlers and AI retrieval systems requires rigorous semantic markup. Schema.org describes unit prices through UnitPriceSpecification nested in an offer.
Marketers and developers should ground measurements using standard UN/CEFACT international unit codes (such as KGM for kilograms, LTR for liters, MTK for square meters, and C62 for individual units):
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Industrial polyurethane structural adhesive, 5 kg pail",
"sku": "ADH-IND-500",
"offers": {
"@type": "Offer",
"price": "225.00",
"priceCurrency": "EUR",
"availability": "https://schema.org/InStock",
"priceSpecification": {
"@type": "UnitPriceSpecification",
"price": "225.00",
"priceCurrency": "EUR",
"referenceQuantity": {
"@type": "QuantitativeValue",
"value": 5,
"unitCode": "KGM",
"valueReference": {
"@type": "QuantitativeValue",
"value": 1,
"unitCode": "KGM"
}
}
}
}
}Google’s merchant listing documentation narrows what Schema.org allows. Merchant listings need an Offer, because the merchant has to be the seller; AggregateOffer is accepted only for product snippets. Unit pricing goes into priceSpecification as UnitPriceSpecification, where referenceQuantity is the quantity sold for the price and valueReference is the base quantity, the structured data counterparts of unit_pricing_measure and unit_pricing_base_measure. In the example the pail holds 5 kg, so the price of 225 EUR corresponds to 45 EUR per kilogram. The only priceType Google supports is StrikethroughPrice, member prices use validForMemberTier together with a regular price, and a specification that combines both is ignored. The page does not mention eligibleQuantity, so quantity breaks above the entry price should not be expected to appear in Google results; the markup carries the entry price, the same one the feed carries.
Edge caching strategies for authenticated wholesale price tiers
Standard full-page caching configurations (such as Nginx FastCGI cache or Redis page caching) fail in B2B environments where each logged-in company account accesses personalized contracted rates. Disabling page caching for authenticated users overloads web workers, driving Time to First Byte (TTFB) into unacceptable multi-second ranges.
A resilient caching pattern leverages a hybrid edge-rendering model:
- Global product shell caching: Static product assets, descriptions, technical specification documents, and high-resolution galleries are aggressively cached at edge CDN locations.
- Asynchronous client-side hydration: When an authenticated purchaser visits the page, an isolated JavaScript micro-module executes an authenticated REST call to retrieve the user’s specific volume discount matrix.
- DOM pricing injection: The client-side component updates displayed unit costs and cart totals, preserving global cache efficiency for public traffic.
For organizations demanding maximum speed and security isolation, decoupled architectures deliver unmatched advantages. Learn more about our technical approach in headless wordpress.
Real-time ERP inventory synchronization and audit queues
Maintaining pricing parity between the web storefront and Google Merchant Center relies on low-latency synchronization with the central enterprise resource planning system (such as SAP, Microsoft Dynamics 365, or NetSuite). Any price revision initiated in the corporate ERP must propagate immediately to the digital storefront and corresponding marketing feeds.
Deploying asynchronous webhook listeners integrated with Action Scheduler queues ensures atomic processing. When an incoming ERP payload alters a product price break, the worker updates the wp_wc_b2b_price_tiers table and dispatches an immediate update through the Google Merchant API without waiting for the primary daily batch export.
Dual-direction synchronization buffers guard database integrity against write locks during high-volume wholesale checkout windows. Unresolved sync anomalies generate automated operational notifications, maintaining data fidelity across all marketing channels.
What Google for WooCommerce maps and what needs a custom feed
The official Google for WooCommerce extension covers part of this setup. Its attribute mapping supports 15 Google attributes, including Multipack, Is Bundle, GTIN, MPN and Brand. A rule can apply to all categories, to all except selected ones, or to a single category. Rules fill only attributes that are empty, and values set on a product’s Google tab override them. Rules read global attributes only, so attributes created on a single product page have to become global ones first.
Unit pricing measure is not on that mapping list. A store that sells by weight, volume or area therefore needs either per-product values or its own feed or API integration for unit_pricing_measure and unit_pricing_base_measure. The same goes for separate pack products generated from a custom tier table, which the extension does not know about.
The transport layer changed in 2026. Google lists the Content API for Shopping as sunset on 18 August 2026, with requests failing progressively from 1 September 2026, and points to the Merchant API instead. Google for WooCommerce made the switch in version 3.8.1. A custom integration writes products through ProductInput resources with insert, patch and delete, reads the processed Product resources, and can only write into data sources of type API, as the Merchant API products guide explains.
Automated testing and verification of pricing rules
In B2B, calculation errors in tiered prices have financial and legal consequences. Advertising prices in Google Shopping that differ from what ends up on the invoice breaks the price matching rules quoted above and can lead to product disapprovals or account suspension.
Technical verification means running automated tests on every deployment:
<?php
/**
* Integration tests for B2B tiered pricing and unit metrics
*/
declare(strict_types=1);
namespace WPPoland\Tests\Pricing;
use PHPUnit\Framework\TestCase;
class TieredPricingCalculationTest extends TestCase
{
public function testVolumeTierIsApplied(): void
{
$calculator = new \WPPoland\Pricing\TieredPriceCalculator();
// Product with a 45 EUR base price and a 32 EUR tier from 10 units
$singlePrice = $calculator->resolveEffectivePrice(
productId: 5120,
quantity: 3,
customerGroup: 'wholesale_tier_1'
);
$this->assertEquals(4500, $singlePrice, 'Quantities below the tier must use the regular price.');
$tierPrice = $calculator->resolveEffectivePrice(
productId: 5120,
quantity: 14,
customerGroup: 'wholesale_tier_1'
);
$this->assertEquals(3200, $tierPrice, 'Quantities from 10 units must use the tier price.');
}
public function testUnitPricingAttributesAreValidated(): void
{
$validator = new \WPPoland\B2BFeeds\FeedAttributeValidator();
$valid = $validator->validateUnitPricingAttributes(
measure: '25kg',
baseMeasure: '1kg'
);
$this->assertTrue($valid, 'Units from the Google supported list must pass.');
$invalid = $validator->validateUnitPricingAttributes(
measure: '25bags',
baseMeasure: 'container'
);
$this->assertFalse($invalid, 'Free-text labels outside the supported list must be rejected.');
}
}These checks catch currency rounding errors and tax mismatches before the data reaches the advertising networks.
Technical implementation checklist for Google Shopping B2B
Before activating promotional campaigns or publishing wholesale product catalogs to Google Merchant Center, engineering teams must complete this technical verification sequence:
- Metric unit validation: Ensure that
unit_pricing_measureandunit_pricing_base_measureuse only units from Google’s supported list and an allowed base value. - Cart recalculation accuracy: Confirm that adding items in quantities satisfying higher discount tiers immediately reflects correct unit prices in the checkout cart.
- GTIN and MPN identifier integrity: Verify that every product variation and multipack bundle carries a globally unique barcode registered through GS1.
- Database stress benchmarking: Execute concurrent query tests evaluating database performance when 1,000 simultaneous users query the custom tiered pricing tables.
- Rich results schema validation: Test live product URLs in the Google Rich Results Test tool to confirm zero warnings across nested
UnitPriceSpecificationnodes. - Memory-safe feed generation: Verify that peak PHP memory during catalog export stays flat as the catalog grows.
- Automated anomaly logging: Configure error monitoring to capture and report product disapprovals reported by Merchant Center diagnostics or the Merchant API.
- Transport encryption and endpoint security: Enforce TLS 1.3, valid SSL certificates, and authentication tokens across all internal pricing endpoints.
- B2B shipping and return policy configuration: Establish explicit delivery guidelines within Merchant Center accommodating freight shipping, pallet logistics, and minimum order values.
- Contingency kill switch: Implement a fallback that shows default static prices if the ERP connection fails temporarily.
Structuring a scalable B2B architecture requires meticulous coordination between backend database design and search engine feed standards. To review your existing catalog infrastructure or optimize high-volume feeds, reach out directly through our contact page.







