WooCommerce Request a Quote: Replacing the Price With a Quote
Hiding a price and swapping the button for a form takes two filters. Turning a quote into an order the customer can pay for is the part WooCommerce only does by hand, and it decides whether the setup is worth building.
Some links on this page are affiliate links: if you buy through one, we may earn a commission at no extra cost to you. It does not change what we recommend; see the editorial policy.
A "request a quote" store is two separate jobs: hiding the price, and turning a negotiated price into an order. WooCommerce can do the first with two filters in a few lines. It does not do the second — there is no quote object; the closest core gets is creating an order by hand in the admin and emailing the customer its payment link. Decide which job you actually need before writing code or buying anything.
When a quote flow makes sense
- Prices depend on the order — volume, configuration, delivery distance, or a contract.
- B2B buyers need paperwork before they can commit: a formal quote for a purchase order.
- Some products are quote-only while the rest of the catalogue sells normally.
If every customer pays the list price, a quote flow only adds friction. Wholesale pricing for known accounts is a different problem, covered in WooCommerce B2B and wholesale.
The core: hiding price and button
Two filters do the presentation. The first hides the price; the second makes the product unpurchasable. On a simple product that removes the add-to-cart form; on a variable product the dropdowns stay but every variation shows as unavailable. In the shop loop, both turn the button into "Read more":
add_filter( 'woocommerce_get_price_html', 'ti_quote_hide_price', 10, 2 );
function ti_quote_hide_price( $price, $product ) {
return ti_is_quote_product( $product ) ? '' : $price;
}
add_filter( 'woocommerce_is_purchasable', 'ti_quote_not_purchasable', 10, 2 );
function ti_quote_not_purchasable( $purchasable, $product ) {
return ti_is_quote_product( $product ) ? false : $purchasable;
}
function ti_is_quote_product( $product ) {
$id = $product->get_parent_id() ?: $product->get_id();
return has_term( 'quote-only', 'product_tag', $id );
}
Tag the products quote-only, then add a contact form below the summary with the product name prefilled. The tag check uses the parent ID so variations of a quote-only product inherit the rule.
The second filter matters more than it looks. Hiding the price or the button alone does not stop a purchase. Any visitor can still add the product with ?add-to-cart=123, and it lands in the cart at its stored price. The cart checks is_purchasable() before accepting a product and refuses with "Sorry, this product cannot be purchased." — but only if your filter makes it false. Themes that "hide prices" with CSS leave this door open. The same filter-based approach to the price string is covered in more depth in woocommerce_get_price_html.
Leaving the price field empty has a similar effect without code: an empty price makes the product unpurchasable by default. The catch is that the price is then genuinely missing, so anything that sorts, filters or exports by price treats the product as having none.
Where the core stops
After the form is submitted, everything happens in your inbox. That is fine for ten quotes a month and painful for a hundred:
| Step | Core WooCommerce | What a quote system adds |
|---|---|---|
| Collect several products in one request | No — one form per product | A quote basket, like a cart without prices |
| Track requests and their status | Email only | Requests stored in the admin with accept, decline and expiry |
| Send the agreed price | Manual email | The quote sent from the admin |
| Customer pays | Create an order by hand, then send a payment link | Approved quote converted into an order the customer pays |
| Rules per product, category or role | Your own code | Settings |
The jump from "form" to "order" is the expensive part to build yourself: a draft order with custom prices, sent to the customer, payable only by them, that expires. This is where a plugin earns its place. WebToffee's WooCommerce Request a Quote hides prices and add-to-cart buttons by product, category, tag or user role, collects several products in a quote basket, accepts requests from guests, and lets you accept, decline or expire quotes in the admin and convert approved ones into orders the customer can pay.
Decisions that shape the setup
Quote-only or quote-also. Some stores hide the price entirely; others show it and add "Request a quote for bulk orders" next to the normal button. Relabelling the existing button is a separate, smaller job, covered in the add to cart text filter. The second keeps impulse sales and still catches large orders. Pick per product, not for the whole store.
Who sees prices. A common B2B pattern is prices for logged-in trade accounts, quotes for everyone else. That is a role rule — check that whatever you build or buy applies it to variations and to search results, not just the product page.
What the form collects. Quantity, delivery location and company are the minimum for a useful first reply. Long forms reduce requests; missing fields add an email round-trip. Spam protection is not optional on a public form.
Payment and expiry. Agreed prices should expire, and payment should go through the normal checkout so taxes, shipping and emails work. A quote converted into an order keeps all of that.
Common mistakes
- Hiding prices with CSS. The price is still in the page source and the add-to-cart URL still works.
- Making products unpurchasable and forgetting variations. Check a variable product's variations, not only the parent.
- No structured data decision. Products without a price cannot show price-rich results in search; that is expected, but do not leave a stale price in your SEO plugin's schema output.
- Quotes that never expire, so a customer pays last year's price.
- Sending quotes from personal inboxes, which loses the history when someone leaves.
Verify
- Visit a quote-only product logged out: no price, no working add-to-cart button.
- Request
/?add-to-cart=IDfor that product and confirm the cart refuses it. - Log in with a role that should see prices and confirm it does.
- Submit a quote request as a guest and check it reaches the right place with all the fields.
- Take one request through to a paid order and check the order email, tax and shipping lines.
Frequently asked
- Yes. Returning an empty string from woocommerce_get_price_html hides the price, and returning false from woocommerce_is_purchasable removes the add-to-cart button and blocks adding the product to the cart. What you do not get is a way to turn the enquiry into an order.
- Because hiding the price or the button is presentation only. WooCommerce still accepts ?add-to-cart=ID requests for any purchasable product. Make the product non-purchasable with the woocommerce_is_purchasable filter and the cart rejects it with "Sorry, this product cannot be purchased."
- Usually yes, since many quote buyers are first-time business customers who will not create an account to ask a question. Protect the form against spam instead, and collect the company details the sales team needs to answer.