This article provides developer documentation for adding support to a payment gateway extension for changing a subscription’s payment method via the Edit Subscription screen.
Note: We are unable to provide support for customizations under our Support Policy. If you need to customize a snippet or extend its functionality, we recommend working with a Woo Agency Partner or finding a WooCommerce developer on Codeable.
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.
Payment Method Change Overview
↑ Back to topThis feature 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.
Adding support for this feature can be achieved with any payment gateway that uses customer or credit card tokens with the following steps:
- Add the support flag to your gateway to declare support for store managers to change the payment methods.
- Allow store managers to change the payment meta data.
- Validate the new meta data before saving the subscription.
Step 1. Declare Support for Changing Payment Methods
↑ Back to topBy default, Subscriptions does 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 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 is included as an option on the Edit Subscription page.
Step 2: Declare your Payment Gateway’s Meta Data
↑ Back to topTo 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 for processing automatic payments. This is done using the filter: 'woocommerce_subscription_payment_meta'
.
Callbacks on this hook receive an array of meta data for all payment gateways in the store and an instance of the subscription ( 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 usingupdate_post_meta( $subscription, 'meta_key', $new_data)
; - Data found in
payment_meta[ YOUR_GATEWAY_ID ]['user_meta']
will be saved asupdate_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 usingupdate_option( 'meta_key', $new_data )
.
Meta Data Declaration Example: Stripe
↑ Back to topHere’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
↑ Back to topTo 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 );
Validation Example: Stripe
↑ Back to topThe 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
↑ Back to topFor 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
↑ Back to topOnce you have completed the steps above, your gateway should:
- Be presented as a payment method option on the Edit Subscription screen.
- Display and save meta data required for processing automatic payments with your gateway.
- Check that the meta data entered by the store manager is valid.
To ensure that automatic recurring payments work with the new meta data:
- Visit the WooCommerce > Subscriptions screen.
- Click the ID of a subscription to open the Edit Subscription screen.
- Click the pencil icon next to the Billing Details section.
- Verify that all the fields required for processing automatic payment are displayed.
- If they are, enter _invalid_ meta data for each field.
- Save the subscription.
- Ensure that correct admin notices are displayed (i.e. your validation function’s exception messages).
- Repeat the above 3 steps for each field your gateway requires.
- Enter valid meta data for each field.
- Save the subscription.
- Trigger an early renewal payment for the subscription.
- Verify that the renewal payment was processed correctly (i.e. the renewal order’s status is processing or complete).
- Verify with your payment gateway that the renewal payment used the new customer or card.
FAQ
↑ Back to topI haven’t added support but my gateway is still showing as an option on the Edit Subscription screen?
↑ Back to topIf 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 data for the subscription using my own custom method?
↑ Back to topWe 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', 10, 4 );