47 KiB
post_title | menu_title | tags |
---|---|---|
Cart and Checkout - Payment method integration for the Checkout block | Payment Method Integration | reference |
Client Side integration
The client side integration consists of an API for registering both express payment methods (those that consist of a one-button payment process initiated by the shopper such as Stripe, ApplePay, or GooglePay), and payment methods such as cheque, PayPal Standard, or Stripe Credit Card.
In both cases, the client side integration is done using registration methods exposed on the blocks-registry
API. You can access this via the wc
global in a WooCommerce environment (wc.wcBlocksRegistry
).
Note: In your build process, you could do something similar to what is done in the blocks repository which aliases this API as an external on
@woocommerce/blocks-registry
.
Express payment methods - registerExpressPaymentMethod( options )
To register an express payment method, you use the registerExpressPaymentMethod
function from the blocks registry. An example of importing this for use in your JavaScript file is:
registerExpressPaymentMethod
Aliased import
import { registerExpressPaymentMethod } from '@woocommerce/blocks-registry';
registerExpressPaymentMethod
on the wc
global
const { registerExpressPaymentMethod } = window.wc.wcBlocksRegistry;
The registerExpressPaymentMethod
registration options
The registry function expects a JavaScript object with options specific to the payment method:
registerExpressPaymentMethod( options );
The options you feed the configuration instance should be an object in this shape (see ExpressPaymentMethodConfiguration
typedef):
const options = {
name: 'my_payment_method',
title: 'My Mayment Method',
description: 'A setence or two about your payment method',
gatewayId: 'gateway-id',
content: <ReactNode />,
edit: <ReactNode />,
canMakePayment: () => true,
paymentMethodId: 'new_payment_method',
supports: {
features: [],
style: [],
},
};
Here's some more details on the configuration options:
name
(required)
This should be a unique string (wise to try to pick something unique for your gateway that wouldn't be used by another implementation) that is used as the identifier for the gateway client side. If paymentMethodId
is not provided, name
is used for paymentMethodId
as well.
title
(optional)
This should be a human readable string with the name of your payment method. It should be sentence capitalised. It is displayed to the merchant in the editor when viewing the Checkout block to indicate which express payment methods are active. If it is not provided, the name
will be used as the title.
description
(optional)
This is one or two sentences maximum describing your payment gateway. It should be sentence capitalised. It is displayed to the merchant in the editor when viewing the Checkout block to indicate which express payment methods are active.
gatewayId
(optional)
This is the ID of the Payment Gateway that your plugin registers server side, and which registers the express payment method. It is used to link your express payment method on the clinet, to a payment gateway defined on the server. It is used to direct the merchant to the right settings page within the editor. If this is not provided, the merchant will be redirected to the general Woo payment settings page.
content
(required)
This should be a React node that will output in the express payment method area when the block is rendered in the frontend. It will be cloned in the rendering process. When cloned, this React node will receive props passed in from the checkout payment method interface that will allow your component to interact with checkout data (more on these props later).
edit
(required)
This should be a React node that will be output in the express payment method area when the block is rendered in the editor. It will be cloned in the rendering process. When cloned, this React node will receive props from the payment method interface to checkout (but they will contain preview data).
canMakePayment
(required)
A callback to determine whether the payment method should be available as an option for the shopper. The function will be passed an object containing data about the current order.
canMakePayment( {
cart: Cart,
cartTotals: CartTotals,
cartNeedsShipping: boolean,
shippingAddress: CartShippingAddress,
billingAddress: CartBillingAddress,
selectedShippingMethods: Record<string,unknown>,
paymentRequirements: string[],
} )
Returns a boolean value - true if payment method is available for use. If your gateway needs to perform async initialization to determine availability, you can return a promise (resolving to boolean). This allows a payment method to be hidden based on the cart, e.g. if the cart has physical/shippable products (example: Cash on delivery
); or for payment methods to control whether they are available depending on other conditions.
canMakePayment
only runs on the frontend of the Store. In editor context, rather than use canMakePayment
, the editor will assume the payment method is available (true) so that the defined edit
component is shown to the merchant.
Keep in mind this function could be invoked multiple times in the lifecycle of the checkout and thus any expensive logic in the callback provided on this property should be memoized.
paymentMethodId
This is the only optional configuration object. The value of this property is what will accompany the checkout processing request to the server and is used to identify what payment method gateway class to load for processing the payment (if the shopper selected the gateway). So for instance if this is stripe
, then WC_Gateway_Stripe::process_payment
will be invoked for processing the payment.
supports:features
This is an array of payment features supported by the gateway. It is used to crosscheck if the payment method can be used for the content of the cart. By default payment methods should support at least products
feature. If no value is provided then this assumes that ['products']
are supported.
supports:style
This is an array of style variations supported by the express payment method. These are styles that are applied across all the active express payment buttons and can be controlled from the express payment block in the editor. Supported values for these are one of ['height', 'borderRadius']
.
Payment Methods - registerPaymentMethod( options )
To register a payment method, you use the registerPaymentMethod
function from the blocks registry. An example of importing this for use in your JavaScript file is:
registerPaymentMethod
Aliased import
import { registerPaymentMethod } from '@woocommerce/blocks-registry';
registerPaymentMethod
on the wc
global
const { registerPaymentMethod } = window.wc.wcBlocksRegistry;
The registerPaymentMethod
registration options
The registry function expects a JavaScript object with options specific to the payment method (see PaymentMethodRegistrationOptions
typedef):
registerPaymentMethod( options );
The options you feed the configuration instance are the same as those for express payment methods with the following additions:
savedTokenComponent
: This should be a React node that contains logic handling any processing your payment method has to do with saved payment methods if your payment method supports them. This component will be rendered whenever a customer's saved token using your payment method for processing is selected for making the purchase.label
: This should be a React node that will be used to output the label for the option where the payment methods are. For example it might be<strong>Credit/Debit Cart</strong>
or you might output images.ariaLabel
: This is the label that will be read out via screen-readers when the payment method is selected.placeOrderButtonLabel
: This is an optional label which will change the default "Place Order" button text to something else when the payment method is selected. As an example, the PayPal Standard payment method changes the text of the button to "Proceed to PayPal" when it is selected as the payment method for checkout because the payment method takes the shopper offsite to PayPal for completing the payment.supports
: This is an object containing information about what features your payment method supports. The following keys are valid here:showSavedCards
: This value will determine whether saved cards associated with your payment method are shown to the customer.showSaveOption
: This value will control whether to show the checkbox which allows customers to save their payment method for future payments.
Props Fed to Payment Method Nodes
A big part of the payment method integration is the interface that is exposed for payment methods to use via props when the node provided is cloned and rendered on block mount. While all the props are listed below, you can find more details about what the props reference, their types etc via the typedefs described in this file.
Property | Type | Description | Values |
---|---|---|---|
activePaymentMethod |
String | The slug of the current active payment method in the checkout. | - |
billing |
Object | Contains everything related to billing. | billingAddress , cartTotal , currency , cartTotalItems , displayPricesIncludingTax , appliedCoupons , customerId |
cartData |
Object | Data exposed from the cart including items, fees, and any registered extension data. Note that this data should be treated as immutable (should not be modified/mutated) or it will result in errors in your application. | cartItems , cartFees , extensions |
checkoutStatus |
Object | The current checkout status exposed as various boolean state. | isCalculating , isComplete , isIdle , isProcessing |
components |
Object | It exposes React components that can be implemented by your payment method for various common interface elements used by payment methods. |
|
emitResponse |
Object | Contains some constants that can be helpful when using the event emitter. Read the Emitting Events section for more details. |
|
eventRegistration |
object | Contains all the checkout event emitter registration functions. These are functions the payment method can register observers on to interact with various points in the checkout flow (see this doc for more info). | onCheckoutValidation , onCheckoutSuccess , onCheckoutFail , onPaymentSetup , onShippingRateSuccess , onShippingRateFail , onShippingRateSelectSuccess , onShippingRateSelectFail |
onClick |
Function | Provided to express payment methods that should be triggered when the payment method button is clicked (which will signal to checkout the payment method has taken over payment processing) | - |
onClose |
Function | Provided to express payment methods that should be triggered when the express payment method modal closes and control is returned to checkout. | - |
onSubmit |
Function | Submits the checkout and begins processing | - |
buttonAttributes |
Object | Styles set by the merchant that should be respected by all express payment buttons | height, borderRadius |
paymentStatus |
Object | Various payment status helpers. Note, your payment method does not have to handle setting this status client side. Checkout will handle this via the responses your payment method gives from observers registered to checkout event emitters. | isPristine , isStarted , isProcessing , isFinished , hasError , hasFailed , isSuccessful (see below for explanation) |
setExpressPaymentError |
Function | Receives a string and allows express payment methods to set an error notice for the express payment area on demand. This can be necessary because some express payment method processing might happen outside of checkout events. | - |
shippingData |
Object | Contains all shipping related data (outside of the shipping status). | shippingRates , shippingRatesLoading , selectedRates , setSelectedRates , isSelectingRate , shippingAddress , setShippingAddress , and needsShipping |
shippingStatus |
Object | Various shipping status helpers. |
|
shouldSavePayment |
Boolean | Indicates whether or not the shopper has selected to save their payment method details (for payment methods that support saved payments). True if selected, false otherwise. Defaults to false. | - |
isPristine
: This is true when the current payment status isPRISTINE
.isStarted
: This is true when the current payment status isEXPRESS_STARTED
.isProcessing
: This is true when the current payment status isPROCESSING
.isFinished
: This is true when the current payment status is one ofERROR
,FAILED
, orSUCCESS
.hasError
: This is true when the current payment status isERROR
.hasFailed
: This is true when the current payment status isFAILED
.isSuccessful
: This is true when the current payment status isSUCCESS
Any registered savedTokenComponent
node will also receive a token
prop which includes the id for the selected saved token in case your payment method needs to use it for some internal logic. However, keep in mind, this is just the id representing this token in the database (and the value of the radio input the shopper checked), not the actual customer payment token (since processing using that usually happens on the server for security).
Button Attributes for Express Payment Methods
This API provides a way to synchronise the look and feel of the express payment buttons for a coherent shopper experience. Express Payment Methods must prefer the values provided in the buttonAttributes
, and use it's own configuration settings as backup when the buttons are rendered somewhere other than the Cart or Checkout block.
For example, in your button component, you would do something like this:
// Get your extension specific settings and set defaults if not available
let {
borderRadius = '4',
height = '48',
} = getButtonSettingsFromConfig();
// In a cart & checkout block context, we receive `buttonAttributes` as a prop which overwrite the extension specific settings
if ( typeof buttonAttributes !== 'undefined' ) {
height = buttonAttributes.height;
borderRadius = buttonAttributes.borderRadius;
}
...
return <button style={height: `${height}px`, borderRadius: `${borderRadius}px`} />
Server Side Integration
Processing Payment
The checkout block currently has legacy handling for payment processing. It converts incoming payment_data
provided by the client-side payment method to $_POST
and calls the payment gateway's process_payment
function. If you already have a WooCommerce Payment method extension integrated with the existing shortcode checkout flow, the checkout block's legacy handling will take care of processing your payment for you on the server side. However, If your payment method hooks into the core checkout process_checkout
function in any way, you will need to account for this behavior and make appropriate adjustments. (See the section below about hooking into the checkout process via the Store API.)
See an example of Passing a value from the client through to server side payment processing
Registering Assets
Implementing the correct loading of your client side asset registration is tricky for the blocks integration. This is because there are some dependencies on the loading order of dependent assets in the request. To remove the complexity of this for extension consumers here, the server side API interface helps with ensuring you can register any assets and data to pass along to your client side payment method from the server and handles the correct loading order of those assets.
First, you create a class that extends Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType
(or you can implement the Automattic\WooCommerce\Blocks\Payments\PaymentMethodTypeInterface
, but you get some functionality for free via the abstract class).
In your class:
- Define a
name
property (This property is a string used to reference your payment method. It is important to use the same name as in your client-side JavaScript payment method registration, seename: 'my_payment_method'
in the options object above). - Define an
initialize
function. This function will get called during the server side initialization process and is a good place to put any settings population etc. Basically anything you need to do to initialize your gateway. Note, this will be called on every request so don't put anything expensive here. - Define an
is_active
function. This should return whether the payment method is active or not. - Define a
get_payment_method_script_handles
function. In this function you should register your payment method scripts (usingwp_register_script
) and then return the script handles you registered with. This will be used to add your payment method as a dependency of the checkout script and thus take sure of loading it correctly. Note: You should still make sure any other asset dependencies your script has are registered properly here, if you're using Webpack to build your assets, you may want to use the WooCommerce Webpack Dependency Extraction Plugin to make this easier for you. - Define a
get_payment_method_script_handles_for_admin
function. Include this if your payment method has a script you only want to load in the editor context for the checkout block. Include here any script fromget_payment_method_script_handles
that is also needed in the admin. - Define a
get_payment_method_data
function. You can return from this function an associative array of data you want to be exposed for your payment method client side. This data will be available client side viawc.wcSettings.getSetting
. So for instance if you assignedstripe
as the value of thename
property for this class, client side you can access any data via:wc.wcSettings.getSetting( 'stripe_data' )
. That would return an object matching the shape of the associative array you returned from this function.
Hooking into the Checkout processing by the Store API
There may be some cases where the fallback legacy processing of Checkout requests from the StoreAPI mentioned earlier doesn't work for your existing payment method integration. For these cases, there is also an action hook you can implement to hook into the server side processing of the order. Note: a good place to register your callback on this hook is in the initialize
method of the payment method class you created from the above instructions.
This hook is the preferred place to hook in your payment processing and if you set a status on the provided PaymentResult
object, then the legacy processing will be ignored for your payment method. Hook callbacks will receive:
Automattic\WooCommerce\StoreApi\Payments\PaymentContext
This contains various details about the payment extracted from the checkout processing request. Notably is the payment_data
property that will contain an associative array of data your payment method client side provided to checkout. It also contains a string value for payment_method
which contains the paymentMethodId
value for the active payment method used during checkout processing. So you can use this to determine whether your payment method processes this data or not.
Automattic\WooCommerce\StoreApi\Payments\PaymentResult
This contains various details about the payment result returned to the client and exposed on the onAfterCheckoutProcessingWithSucces/WithError
event. Server side, your payment method can use this to:
- set the status to return for the payment method (one of
success
,failure
,pending
,error
). - set a redirect url.
- set any additional payment details (in case you need to return something for your client to further process with).
Putting it all together
So you've created a class extending Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType
, but you still need to register this with the server side handling of payment methods. In order to do this you need to register a callback on the woocommerce_blocks_payment_method_type_registration
action. Your callback will receive an instance of Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry
which has a register
method for registering an instance of the class you created. It's also recommended that you register your callback on this action within the context of a callback on the woocommerce_blocks_loaded
action.
Note: With Cart and Checkout Blocks currently only available in the WooCommerce Blocks Feature plugin, you will want to make sure you check for the availability of the
Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType
class before registering your payment method integration server side.
So for example, assuming your class that extends Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType
is named MyPaymentMethod
. You would have this somewhere in your extension's bootstrap:
use MyPlugin\MyPaymentMethod;
use Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry;
add_action( 'woocommerce_blocks_loaded', 'my_extension_woocommerce_blocks_support' );
function my_extension_woocommerce_blocks_support() {
if ( class_exists( 'Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType' ) ) {
add_action(
'woocommerce_blocks_payment_method_type_registration',
function( PaymentMethodRegistry $payment_method_registry ) {
$payment_method_registry->register( new MyPaymentMethod );
}
);
}
}
As an example, you can see how the Stripe extension adds it's integration in this pull request.