WooCommerce PayPal Buttons Not Showing? Missing form.cart
Scrolling down to the payment area on a WooCommerce variable product page, the PayPal button spot is completely blank β the container is there, the button is gone, and the browser console shows no error at all.
Ran into this while building CCLEE B2B, a WooCommerce B2B enhancement plugin covering customer group management, tiered pricing, and bulk ordering β and stepped on an undocumented behavior of PayPal Complete Payments (PPCP).
TL;DRβ
The first thing PPCP's button script does in init() is document.querySelector("form.cart") β if nothing matches, it returns silently with no log. Customizations like a B2B variation matrix remove the standard add-to-cart form with remove_action, form.cart disappears with it, and PayPal buttons never render again. The fix: wrap the PayPal container in a minimal form.cart, with onsubmit="return false" to block real submissions.
Symptom: Empty PayPal Button Spot, Clean Consoleβ
Everything else on the product page works; the standard add-to-cart button is gone by design, but the PayPal buttons that should appear simply don't render. Searches for "PayPal button not showing" or "PayPal button not rendering" all describe this same situation.
DevTools shows three facts:
- The page HTML contains PPCP's button container
#ppc-button-ppcp-gateway; - The container is empty β not half-rendered, an empty div;
- The console has no errors or warnings, and the ppcp-button script itself loads fine.
"Script loaded, container present, button missing, zero logs" means the problem is not in the network or error layer β it is inside the script's own logic branch.
Root Cause: PPCP's form.cart Precondition Check and Silent Skipβ
The ppcp-button script (ppcp-button-js-button.js) starts its init() with document.querySelector("form.cart") β no match, no render, no message. This behavior is absent from PPCP's official documentation; you confirm it by reading the source or comparing against a working product page.
Why would form.cart disappear? WooCommerce's standard add-to-cart form is output by woocommerce_template_single_add_to_cart. B2B variation matrices, quote flows, and price-hiding customizations commonly remove it outright:
remove_action(
'woocommerce_single_product_summary',
'woocommerce_template_single_add_to_cart',
10
);
That one cut removes more than the add-to-cart button β it also removes the form.cart that PPCP requires before rendering. The custom purchase UI works flawlessly, the page logs nothing β only the PayPal button vanishes.
The silence is what makes this expensive to diagnose: the script reasons "no form, no render target" and quietly exits. You can watch ppcp-button JS download and execute in the Network panel, you can see the button container in the DOM, and not a single line tells you why it chose to do nothing.
Fix: Wrap the PayPal Container in a Minimal form.cartβ
Wrap the PayPal container in a minimal form.cart at the spot where it renders, and PPCP's precondition check passes β buttons come back.
add_action( 'woocommerce_single_product_summary', function () {
echo '<form class="cart" onsubmit="return false;">';
echo '<div id="ppc-button-ppcp-gateway" class="ppc-button-wrapper"></div>';
echo '</form>';
}, 25 );
Each part has one job:
class="cart"β PPCP checks this class, not an id; keep it verbatim;onsubmit="return false;"β the form is real in the DOM, so a submit triggered by the Enter key or other scripts would reload the page and lose the selected variation; this blocks them all;- The container div's id
ppc-button-ppcp-gatewayis PPCP's convention β match the actual container id on your page.
The full version in CCLEE B2B also fires PPCP's own render action, for reference:
do_action( 'woocommerce_paypal_payments_single_product_button_render' );
If you are deep into customizing WooCommerce templates and purchase flows, the block theme troubleshooting guide covers other common pitfalls at the template layer.
Caution
PPCP is not the only component watching form.cart β third-party add-to-cart enhancers and tracking plugins may listen to it too. After adding the form, walk through a full order in a private window and confirm no script double-fires because of it; do not omit onsubmit="return false", or the Enter key alone will reload the page.
FAQβ
Why does removing the standard add-to-cart form make PayPal buttons disappear?β
The standard form is output by woocommerce_template_single_add_to_cart on the woocommerce_single_product_summary hook at default priority 10. Once remove_action takes it away, the PPCP button script finds no form.cart at init and skips rendering entirely.
How do I quickly confirm the missing form.cart is the cause?β
Check two things: a clean console, and a ppc-button-ppcp-gateway container in the DOM that exists but stays empty. Then temporarily insert an empty <form class="cart"></form> on the product page and reload β if buttons appear, that is the cause.
Can I inject the form.cart with JavaScript on the frontend?β
No. PPCP's init() runs its check once during script initialization; a form inserted afterwards never triggers a re-check. The form.cart must be rendered server-side so it exists before the script runs.
Is onsubmit="return false" required?β
Yes. The wrapper form.cart is a real form β a submit triggered by the Enter key or other scripts reloads the page and loses the selected variation. PPCP's dependency on the form actually submitting is zero; return false blocks every submission path.
CCLEE
Independent developer, 24 years in e-commerce, focused on grounding AI in real business scenarios.
Work with me