DEV Community

Amanur Rahman
Amanur Rahman

Posted on Originally published at amanurrahman.com

How WooCommerce Decides Which Payment Methods to Show (and Why One Goes Missing)

When a payment method vanishes from WooCommerce checkout, the usual reaction is to toggle settings at random. It is faster to understand how the list is built, then test each stage in order.

The five stages

A gateway has to pass all of these before a customer sees it:

  1. Enabled and set up. The toggle is on and the gateway's own fields (keys, merchant ID, connected account) are complete.
  2. Available for this order. The gateway reports itself available based on currency, customer country, cart total and its own rules.
  3. Supported by the checkout type. The block-based checkout only displays gateways that registered block support. The classic shortcode checkout shows gateways built for it.
  4. The page loads cleanly. Caching, delayed or combined JavaScript, and template overrides can all break the payment section.
  5. It renders. Only then does the customer see it.

If a method is missing, one of those stages failed. The symptom is identical for all of them, which is why guessing wastes time.

Triage before opening settings

  • Open checkout in a private window while logged out. If methods appear there, suspect caching.
  • Change the billing country. If methods appear for some countries only, it is a location restriction.
  • Check the cart total after coupons. A zero total correctly skips payment.
  • Open the browser console and look for red JavaScript errors.

Separate "unavailable" from "not rendered"

This snippet, run on staging, tells you which side of the line you are on. Load checkout as an administrator and view the page source.

add_action( 'wp_footer', function () {
    if ( is_checkout() && current_user_can( 'manage_options' ) ) {
        $gateways = WC()->payment_gateways()->get_available_payment_gateways();
        echo '<!-- Available gateways: ' . esc_html( implode( ', ', array_keys( $gateways ) ) ) . ' -->';
    }
} );
Enter fullscreen mode Exit fullscreen mode
  • Gateway ID is in the list but not visible: a display problem. Look at block support, scripts, caching or a template override.
  • Gateway ID is not in the list: the gateway reported itself unavailable for this order. Look at currency, country, totals, shipping rules and its own settings.

Remove the snippet when you are done.

The block checkout gap

Recent WooCommerce versions use the block-based checkout by default on new setups. A gateway built only for the older shortcode checkout may not appear there until its developer adds block support. As a stopgap, replace the checkout block with a Shortcode block containing [woocommerce_checkout], then test a full order, including any express payment buttons on the cart and product pages.

Common non-obvious causes

  • Cash on Delivery rules. It can be limited to specific shipping methods and may reject virtual orders unless you allow them.
  • Currency switchers. Some multi-currency plugins filter gateways per currency.
  • Caching. Cart, checkout and account pages should be excluded from page caching, and gateway scripts excluded from delay, defer and combine options.
  • Outdated template overrides. WooCommerce's system status report lists overridden templates.

FAQ

Why does WooCommerce say no payment methods are available?
No enabled gateway reported itself available for that order. Check currency, country, amount limits, the cart total and the gateway's own settings.

Why do methods show in test mode but not live?
Usually the live keys are missing or wrong, or the site is not loading cleanly over HTTPS.

Will the classic checkout fix a missing gateway?
If the gateway lacks block support, often yes. Treat it as a bridge until the gateway is updated.

Can caching hide payment methods?
Yes. A cached checkout page, or scripts that are delayed or combined, can stop the payment section from loading for visitors.

Full guide

I wrote up all nine fixes, a causes-at-a-glance table and a prevention checklist here: Payment Methods Not Showing in WooCommerce.

If you want a second pair of eyes on a specific store, you can reach me through Aman Web Solution.

Top comments (1)

Collapse
 
alhiane profile image
Alhiane Lahcen •

The five-stage model is a nice way to stop guessing. One addition for stage 2: when a gateway ID is missing from your list, it's often not the gateway deciding it's unavailable. Another plugin (multi-currency, COD or B2B rules, country restrictions) is removing it on the woocommerce_available_payment_gateways filter. Same idea as your snippet, but it lists every callback on that filter with the file and line it lives in:

add_action( 'wp_footer', function () {
    if ( ! is_checkout() || ! current_user_can( 'manage_options' ) ) {
        return;
    }
    global $wp_filter;
    echo "<!-- woocommerce_available_payment_gateways callbacks:\n";
    foreach ( $wp_filter['woocommerce_available_payment_gateways']->callbacks ?? [] as $priority => $cbs ) {
        foreach ( $cbs as $cb ) {
            $f = $cb['function'];
            try {
                if ( is_array( $f ) ) {
                    $r = new ReflectionMethod( $f[0], $f[1] );
                } elseif ( is_string( $f ) && strpos( $f, '::' ) ) {
                    $r = new ReflectionMethod( ...explode( '::', $f, 2 ) );
                } elseif ( is_object( $f ) && ! $f instanceof Closure ) {
                    $r = new ReflectionMethod( $f, '__invoke' );
                } else {
                    $r = new ReflectionFunction( $f );
                }
                echo esc_html( $priority . '  ' . $r->getFileName() . ':' . $r->getStartLine() ) . "\n";
            } catch ( Throwable $e ) {
                echo esc_html( $priority ) . "  (could not resolve)\n";
            }
        }
    }
    echo "-->\n";
}, 999 );
Enter fullscreen mode Exit fullscreen mode

Same rules as yours: staging, admin only, remove it afterwards. The plugin folder in each path usually tells you who is hiding the method. With block checkout the list is built in a REST request instead of the page, but the same plugins are usually hooked there too, so this still narrows it down.