Admin Change Payment Method Integration Guide

You are here:
This document is written for WooCommerce developers who want to extend or integrate with the WooCommerce Subscriptions plugin. To follow this documentation, you will need an advanced understanding of PHP and WordPress development. If you are looking for a guide to creating and managing subscriptions in your store, refer to the Store Manager Guide.

This article provides developer documentation for adding support to a payment gateway extension for Subscription v2.0’s new Change Payment Method section of the Edit Subscription administration screen.

 

If you are a developer of a payment gateway and have not yet provided support for processing subscriptions, please read the Subscriptions Payment Gateway Integration Guide.

Need to upgrade a payment gateway for version 2.0? Check out the Payment Gateway Upgrade Guide.

Background

A new feature added in Subscriptions v2.0 provides a way for payment gateways to allow store managers to add or edit a subscription’s payment method and meta data on the new Edit Subscription administration screen.

Change Recurring Payment Method
Change Recurring Payment Method Fields

Adding support for this feature can be achieved with any payment gateway that uses customer or credit card tokens with the following steps:

  1. Add the support flag to your gateway to declare support for store managers to change the payment methods
  2. Allow store managers to change the payment meta data
  3. Validate the new meta data before saving the subscription.

Step 1. Declare Support for Changing Payment Methods

By default, Subscriptions will not allow store managers to change or modify the payment gateway on the Edit Subscription screen to anything other than the built-in Manual Renewals gateway.

To add the support for this feature, you will need to declare support by adding 'subscription_payment_method_change_admin' to your gateway’s $this->supports property.

For example, if Stripe wanted to allow administrators to change the payment method, they could achieve this by adding the 'subscription_payment_method_change_admin' to their WC_Payment_Gateway->supports array as follows:

$this->supports = array(
    // Other support flags here
    'subscription_payment_method_change_admin',
    // Other support flags here
);

Once your gateway declares support, it will be included as an option on the Edit Subscription page.

Choose Payment Method for Subscription
Choose Payment Method for Subscription

Step 2: Declare your Payment Gateway’s Meta Data

To allow store managers to correctly configure automatic payments with your payment gateway via the Edit Subscription screen, you also need to tell Subscriptions about the meta data required by your payment gateway in order to process automatic payments. This is done using the filter: 'woocommerce_subscription_payment_meta'.

Callbacks on this hook are passed an array of meta data for all payment gateways in the store and an instance of the subscription (a WC_Subscription) to which the meta data relates.

To use this filter correctly, you need to insert information about your payment details using your payment gateway’s ID as the key on the array, i.e. payment_meta[ YOUR_GATEWAY_ID ]. You should also populate the meta data with the current or default value for the given subscription, which is passed to your callback as the 2nd parameter.

The full structure needs to meet the following format:

$payment_meta[ YOUR_GATEWAY_ID ]  = array (
    'table_name' => array (
        'meta_key_1' => array (
            'value' => get_post_meta( $subscription->id, ..., true ),
            'label' => 'Front-end Label to display',
        ),
        'meta_key_2' => array (
            'value' => get_user_meta( $subscription->customer_user, ..., true ),
            'label' => 'Front-end Label to display',
        )
    ),
);

Subscriptions uses this information in two ways:

  • to display the appropriate fields on the Edit Subscription screen, which is why a 'label' field is required; and
  • to save the meta data in the database when the Edit Subscription screen is saved, which is why the meta key and table name fields are required.

The 'table_name' string tells Subscriptions where to store and retrieve the meta data. If the value is either 'post_meta''user_meta' or 'options', subscriptions will automatically save the new data to those respective tables with the site’s database prefix (i.e. wpdb->prefix). If the default table names are not suitable for storing your data, please read the FAQ section for details of alternatives.

Specifically:

  • Any data found in payment_meta[ YOUR_GATEWAY_ID ]['post_meta'] will be stored in the post meta table using update_post_meta( $subscription, 'meta_key', $new_data);
  • Data found in payment_meta[ YOUR_GATEWAY_ID ]['user_meta'] will be saved as update_user_meta( $subscription->customer_user, 'meta_key', $new_data );;
  • The data listed under payment_meta[ YOUR_GATEWAY_ID ]['options'] will be saved to options table using update_option( 'meta_key', $new_data ).

Example: Stripe

Here’s an example of how the Stripe payment gateway uses this filter to allow administrators to change the '_stripe_customer_id' meta data found in the post meta table and similarly the '_stripe_card_id' meta data.

class WC_Gateway_Stripe_Addons extends WC_Gateway_Stripe {

    ...

    /**
     * Include the payment meta data required to process automatic recurring payments so that store managers can
     * manually set up automatic recurring payments for a customer via the Edit Subscriptions screen in 2.0+.
     *
     * @since 2.5
     * @param array $payment_meta associative array of meta data required for automatic payments
     * @param WC_Subscription $subscription An instance of a subscription object
     * @return array
     */
    public function add_subscription_payment_meta( $payment_meta, $subscription ) {

        $payment_meta[ $this->id ] = array(
            'post_meta' => array(
                '_stripe_customer_id' => array(
                    'value' => get_post_meta( $subscription->id, '_stripe_customer_id', true ),
                    'label' => 'Stripe Customer ID',
                ),
                '_stripe_card_id' => array(
                    'value' => get_post_meta( $subscription->id, '_stripe_card_id', true ),
                    'label' => 'Stripe Card ID',
                ),
            ),
        );

        return $payment_meta;
    }

    ...
}

Step 3: Validate Meta Data

To ensure store managers are inputting correct data, an optional but highly recommended feature you can implement is validation of the data before it is saved to the subscription.

The 'woocommerce_subscription_validate_payment_meta' filter is available for this purpose. This filter passes payment_method_id and payment_meta array parameters to callbacks. The payment_meta contains all the user’s inputted data in the same format as described in Step 2. Attach a validation function to this filter to validate meta data entered by the store manager.

Any exceptions thrown in your validation function will be caught and the exception message will be displayed on the Edit Subscription in an administration notices section (see below). If an exception is caught, all new modifications before saving the subscription will be ignored.

function my_validation_function( $payment_method_id, $payment_meta ) {

    if ( 'YOUR_GATEWAY_ID' === $payment_method_id ) {
        if ( 'example_throw' == $payment_meta['YOUR_GATEWAY_ID']['post_meta']['example_meta_key'] ) {
            throw new Exception( 'Error to appear on Edit Subscription in the case of an invalid input' );
        }   
    }
}
add_action( 'woocommerce_subscription_validate_payment_meta', 'my_validation_function', 10, 2 );

Example: Stripe

The following codes demonstrate the validation function used by the Stripe Payment Gateway to validate its data.

class WC_Gateway_Stripe_Addons extends WC_Gateway_Stripe {

    ...

    /**
     * Validate the payment meta data required to process automatic recurring payments so that store managers can
     * manually set up automatic recurring payments for a customer via the Edit Subscriptions screen in 2.0+.
     *
     * @since 2.5
     * @param string $payment_method_id The ID of the payment method to validate
     * @param array $payment_meta associative array of meta data required for automatic payments
     * @return array
     */
    public function validate_subscription_payment_meta( $payment_method_id, $payment_meta ) {

        if ( $this->id === $payment_method_id ) {

            if ( ! isset( $payment_meta['post_meta']['_stripe_customer_id']['value'] ) || empty( $payment_meta['post_meta']['_stripe_customer_id']['value'] ) ) {
                throw new Exception( 'A "_stripe_customer_id" value is required.' );
            } elseif ( 0 !== strpos( $payment_meta['post_meta']['_stripe_customer_id']['value'], 'cus_' ) ) {
                throw new Exception( 'Invalid customer ID. A valid "_stripe_customer_id" must begin with "cus_".' );
            }

            if ( ! isset( $payment_meta['post_meta']['_stripe_card_id']['value'] ) || empty( $payment_meta['post_meta']['_stripe_card_id']['value'] ) ) {
                throw new Exception( 'A "_stripe_card_id" value is required.' );
            } elseif ( 0 !== strpos( $payment_meta['post_meta']['_stripe_card_id']['value'], 'card_' ) ) {
                throw new Exception( 'Invalid card ID. A valid "_stripe_card_id" must begin with "card_".' );
            }
        }
    }

    ...

}

Full Example: Simplify Commerce

For a full example, see the code required to add support to Simplify Commerce in WooCommerce core in this commit. This was submitted as part of the Simplify Commerce Subscriptions v2.0 compatibility pull request.

Testing

Once you have completed the steps above, your gateway should:

  1. be presented as a payment method option on the Edit Subscription screen;
  2. display and save meta data required for processing automatic payments with your gateway; and
  3. check that the meta data entered by the store manager is valid.

To ensure that automatic recurring payments work with the new meta data:

  1. Visit the WooCommerce > Subscriptions screen
  2. Click the ID of a subscription to open the Edit Subscription screen
  3. Click the pencil icon next to the Billing Details section
  4. Verify that all the fields required for processing automatic payment are displayed
  5. If they are, enter _invalid_ meta data for each field
  6. Save the subscription
  7. Ensure that correct admin notices are displayed (i.e. your validation function’s exception messages)
  8. Repeat the above 3 steps for each field your gateway requires
  9. Enter valid meta data for each field
  10. Save the subscription
  11. trigger an early renewal payment for the subscription
  12. verify that the renewal payment was processed correctly (i.e. the renewal order’s status is processing or complete)
  13. verify with your payment gateway that the renewal payment used the new customer or card

FAQ

I haven’t added support but my gateway is still showing as an option on the Edit Subscription screen?

If a subscription is purchased via the normal checkout process, the payment method used during checkout will be shown on the Edit Subscription screen because the meta data required for automatic payment should have been collected during checkout.

If the store manager changes the payment method for the subscription from your payment gateway to another, it will no longer be displayed as an option.

How can I save the payment meta for the subscription using my own custom method?

We have provided an action hook that will allow you to save the payment meta data wherever you like, but to ensure you stop us from saving the data, you will need to make sure the table_name does not equal post_meta, postmeta, user_meta, usermeta or options. Then, you should make sure your plugin catches the 'wcs_save_other_payment_meta' action.

The following code example demonstrates how you would go about either storing data in the comments table or attaching some extra information to a value before it is stored in the post meta table.

function my_gateway_meta( $payment_details, $subscription ) {
    $payment_details[ YOUR_GATEWAY_ID ]  = array (
            'wc_comments' => array (
                '_gateway_comments' => array (
                    'value' => get_comments_meta( ..., ..., true ),
                    'label' => 'Front-end Label to display',
                )
            ),
            'wc_post_meta' => array (
                'meta_key_1' => array (
                    'value' => get_post_meta( $subscription->id, 'meta_key_1', true ),
                    'label' => 'Front-end Label to display',
                )
            ),
    );
    return $payment_details;
}
add_filter( 'woocommerce_subscription_payment_meta', 'my_gateway_meta', 10, 2 );

function save_meta_in_comments( $subscription, $table, $meta_key, $meta_value ) {
    switch( $table ) {
        case 'wc_comments':
            update_comments_meta( ..., $meta_key, $meta_value );
            break;
        case 'wc_post_meta':
            update_post_meta( $subscription->id, $meta_key, $meta_value . '_edited' );
            break;
    }
}
add_action( 'wcs_save_other_payment_meta', 'save_meta_in_comments',
Was this article helpful?
Dislike 0
Views: 10