• Resolved awaisaezad

    (@awaisaezad)


    I need to hold a Stripe charge and capture it later (only when a customer keeps the product).

    In WooCommerce shortcodes checkout, Stripe attaches the customer to the Payment Intent, so later capture works.
    But in WooCommerce Blocks checkout, the customer is not attached, so the card is “burned” (not reusable), and later capture fails.

    Here’s the relevant code I use to attach the customer:

    function attach_stripe_customer_to_payment_method( $payment_method_id, $customer_id, $stripe_secret ) {
        $response = wp_remote_post(
            "https://api.stripe.com/v1/payment_methods/$payment_method_id/attach",
            array(
                'method'  => 'POST',
                'headers' => array(
                    'Authorization' => 'Bearer ' . $stripe_secret,
                ),
                'body'    => array(
                    'customer' => $customer_id,
                ),
            )
        );
    
        return wp_remote_retrieve_body( $response );
    }
    

    In shortcodes checkout, I can get $payment_method_id in:

    add_action( 'woocommerce_checkout_order_processed', function( $order_id, $posted_data, $order ) {
        // Works here - we can get payment_method_id and attach the customer.
    }, 10, 3 );
    

    But in Blocks checkout, the only hook available is:

    add_action( 'woocommerce_store_api_checkout_order_processed', function( $order ) {
        // Can't get payment_method_id here, so we can't attach the customer.
    }, 10, 1 );
    

    The payment_method_id is only available much later in woocommerce_thankyou, but by then Stripe marks the card as used, so the Payment Intent can’t be reused for delayed capture.

    How can I access the payment_method_id earlier in the WooCommerce Blocks checkout flow (similar to shortcodes) so that I can attach the customer to the Payment Intent and hold the charge for later capture?

    The page I need help with: [log in to see the link]

Viewing 3 replies - 1 through 3 (of 3 total)
  • Plugin Support shahzeen(woo-hc)

    (@shahzeenfarooq)

    Hi there!

    Thank you for providing such detailed context about your use case with Stripe and WooCommerce Blocks checkout. I understand the challenge you’re facing trying to attach the Stripe customer to the Payment Intent early enough in the Blocks checkout flow so you can perform a delayed capture, similar to how it works in shortcode checkout.

    Please note that, we do not provide support for customization, what you’re trying to do involves custom code and integration with the Stripe API, which falls outside the scope of support we’re able to provide.

    If you need more in-depth support or want to consider professional assistance for customization, I can recommend WooExperts and Codeable.io as options for getting professional help. Alternatively, you can also ask your development questions in the  WooCommerce Community Slack as custom code falls outside our usual scope of support.

    Thread Starter awaisaezad

    (@awaisaezad)

    Working Solution: Attach Stripe Customer to Card Before Capture

    Here’s how I made it work:
    Force Delayed Capture in Stripe Plugin

    In your functions.php or custom plugin:

    add_filter('wc_stripe_payment_request_capture', '__return_false');
    add_filter('wc_stripe_force_save_payment_method', '__return_true');
    add_filter('wc_stripe_payment_intent_params', function ($params, $order) {
    $params['capture_method'] = 'manual'; // Prevent auto-capture
    return $params;
    }, 10, 2);

    Hook into Stripe Blocks Payment Complete (JS)

    Stripe’s Blocks JS emits an event when the payment is completed (but not captured). Use it to grab the payment_method_id and send it to your backend to attach the customer.

    document.addEventListener('wc_stripe_block_payment_complete', async (e) => {
      const intent = e.detail.paymentIntent;
    
      if (intent && intent.payment_method && window.stripe_customer_id) {
        const res = await fetch('/wp-json/custom-stripe/v1/attach-method', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            payment_method_id: intent.payment_method,
            customer_id: window.stripe_customer_id,
          }),
        });
    
        const json = await res.json();
        if (json.success) {
          console.log('Payment method attached to customer');
        }
      }
    });
    

    REST API Endpoint to Attach Payment Method to Customer

    Add this to your custom plugin:

    add_action('rest_api_init', function () {
        register_rest_route('custom-stripe/v1', '/attach-method', array(
            'methods' => 'POST',
            'callback' => 'custom_attach_payment_method',
            'permission_callback' => '__return_true', // Secure this in production
        ));
    });
    
    function custom_attach_payment_method($request) {
        $params = $request->get_json_params();
        $payment_method_id = sanitize_text_field($params['payment_method_id'] ?? '');
        $customer_id = sanitize_text_field($params['customer_id'] ?? '');
    
        require_once __DIR__ . '/vendor/autoload.php'; //load stripe sdk file
    
        \Stripe\Stripe::setApiKey('sk_test_YOUR_SECRET_KEY');
    
        try {
            $payment_method = \Stripe\PaymentMethod::retrieve($payment_method_id);
            $payment_method->attach(['customer' => $customer_id]);
    
            return ['success' => true];
        } catch (\Exception $e) {
            return new WP_REST_Response([
                'success' => false,
                'message' => $e->getMessage()
            ], 500);
        }
    }
    

    And then where you like you can capture it later without any issue.
    This solution worked for me if anyone else has the same issue.

    Superb @awaisaezad,

    Thank you for sharing the solution that worked for you. I’m sure others looking for a similar feature or facing the same issue will find this really useful. We appreciate your contribution.

    If you’re enjoying the features offered by this plugin, we’d be grateful if you could leave us your honest feedback here: https://wordpress.org/support/plugin/woocommerce-gateway-stripe/reviews/#new-post

Viewing 3 replies - 1 through 3 (of 3 total)

The topic ‘How to attach Stripe customer to Payment Intent in Checkout for delayed Capture.’ is closed to new replies.