Интеграция платежного шлюза с WooCommerce Checkout Block — часть 1 «Простой вариант»
WooCommerce – одна из самых востребованных и гибких платформ электронной коммерции в мире, продолжает завоевывать сердца онлайн-предпринимателей и многомиллионных сообществ пользователей. Ее успех не случаен, и одной из важнейших составляющих этого успеха является способность интегрировать различные инструменты и сервисы, обеспечивая таким образом беспрепятственное функционирование онлайн-магазинов.
Одним из важнейших типов интеграции является добавление платежных шлюзов для простой оплаты заказов. Эта тема подробно раскрыта, но с недавних пор WooCommerce активно развивает поддержку редактора Gutenberg, и появился отдельный блок для создания страницы оплаты
Для этого блока нельзя просто использовать уже созданный платежный шлюз. Требуются доработки связанные с тем, что Checkout Block написан при помощи JS библиотеки React, а значит и нам нужно написать прослойку на React для работы платежного шлюза и правильно её подключить в PHP
Оглавление
Простой вариант подразумевает, что в плагине есть только один платежный шлюз и его надо быстро и просто зарегистрировать в WooCommerce Checkout block.
Для начала поймем как проверить, что шлюз интегрирован с Checkout block. Это можно увидеть в блоке Checkout. При выборе блока справа будет выводиться предупреждение о неподдерживаемых шлюзах. В нашем случае это шлюз «Example Gateway»:
Теперь рассмотрим как это исправить.
Backend
Сначала разберем интеграцию на стороне Backend’а. Для этого нужно создать класс, наследующийся от класса AbstractPaymentMethodType
и зарегистрировать его во время события woocommerce_blocks_payment_method_type_registration
:
Вот пример минимального класса
/**
* Payment method integration
*/
final class ExampleGatewayBlocksIntegration extends AbstractPaymentMethodType {
/**
* Payment method name/id/slug.
*
* @var string
*/
protected $name = 'example_gateway';
/**
* Returns an array of script handles to enqueue for this payment method in
* the frontend context
*
* @return string[]
*/
public function get_payment_method_script_handles(): array {
$handle = 'script-handle';
wp_register_script(
$handle,
'path_to_js'
);
return array( $handle );
}
/**
* Initializes the payment method type.
*/
public function initialize() {
$this->settings = get_option( "woocommerce_{$this->name}_settings", array() );
}
/**
* Returns if this payment method should be active. If false, the scripts will not be enqueued.
*
* @return boolean
*/
public function is_active(): bool {
return filter_var( $this->get_setting( 'enabled', false ), FILTER_VALIDATE_BOOLEAN );
}
/**
* Returns an array of key=>value pairs of data made available to the payment methods script.
*
* @return array
*/
public function get_payment_method_data(): array {
return array(
'title' => $this->get_setting( 'title' ),
'description' => $this->get_setting( 'description' ),
'supports' => $this->get_supported_features(),
);
}
}
Здесь наиболее интересен метод get_payment_method_script_handles
. Он должен зарегистрировать JS скрипт и вернуть его handle в виде массива. Раз возвращается массив, то можно зарегистрировать и больше одного скрипта, но нам это не понадобится. Остальные методы:
initialize
— вызывается при инициализации WooCommerce интеграций. В случае со шлюзом он должен установить настройки шлюзаis_active
— проверяет активирован или нет шлюз. В нашем случае работает на основе настроек шлюза полученных в методеinitialize
get_payment_method_data
— возвращает настройки для js скрипта. Нам потребуются title, description и supports.
Теперь осталось только зарегистрировать этот класс в WooCommerce интеграциях:
add_action( 'woocommerce_blocks_payment_method_type_registration', function ( PaymentMethodRegistry $payment_method_registry ) {
$payment_method_registry->register( new ExampleGatewayBlocksIntegration() );
} );
На этом Backend настройку можно считать завершенной
Frontend
Теперь создадим JS скрипт для работы со шлюзом. Этот скрипт должен вызывать функцию registerPaymentMethod
из пакета @woocommerce/blocks-registry
, в которую нужно передать информацию о шлюзе и React компоненты для отображения шлюза в списке. Так как мы идем по быстрому и простому пути, то упростим пару моментов:
- Без JSX —для использования библиотеки React воспользуемся ее методом createElement, вместо настройки JSX
- Без установки библиотек — все требуемые инструменты для работы интеграции шлюза находятся в глобальной области видимости страницы оплаты, то есть мы можем их легко получить в JS скрипте
Здесь рассмотрим сначала составляющие скрипта, а потом соберем всё в единое целое. В первую очередь проверим, что все требуемые библиотеки существуют в глобальной области видимости:
if (window.wc && window.wc.wcBlocksRegistry && window.React) {...}
Если существует функция wc.wcBlocksRegistry
и библиотека React, то и все остальное точно подключено.
Далее импортируем все нужные функции. В примере используется деструктуризация, но можно использовать и обычное присвоение переменным или вообще использовать функции по полному пути:
const {registerPaymentMethod} = wc.wcBlocksRegistry; // const registerPaymentMethod = wc.wcBlocksRegistry.registerPaymentMethod;
const {createElement} = React; // const createElement = React.createElement;
const {__} = wp.i18n; // const __ = wp.i18n.__;
const {getSetting} = wc.wcSettings; // const getSetting = wc.wcSettings.getSetting;
const {decodeEntities} = wp.htmlEntities; // const decodeEntities = wc.htmlEntities.decodeEntities;
Теперь получим нужные настройки:
const PAYMENT_METHOD_NAME = 'example_gateway' // Строка указанная в свойстве name класса интеграции
const settings = getSetting(PAYMENT_METHOD_NAME, {}); // Получение всех настроек
const label = decodeEntities(settings.title); // Получение названия шлюза для отображения
const description = decodeEntities(settings.description); // Получение описания шлюза для отображения
Перейдем к созданию React компонентов для отображения. Их понадобится два и создадим мы их с помощью функции createElement, импортированной ранее. Первый Content
— контент отображаемый при выборе шлюза. В нашем случае будет отображаться описание шлюза:
const Content = createElement(() => {
return description;
}, null);
Второй Label — элемент, который выводится в списке доступных методов оплате.
const Label = createElement(props => {
const {PaymentMethodLabel} = props.components; //Стандартный элемент для отображения заголовка
return createElement(PaymentMethodLabel, {text: label}) //Передача заголовка шлюза в элемент
}, null)
Осталось только вызвать функцию registerPaymentMethod
, передав в нее объект с конфигурацией:
registerPaymentMethod({
name: PAYMENT_METHOD_NAME, // id шлюза
label: Label, // Ранее созданный компонент для заголовка шлюа
content: Content, // Ранее созданный компонент для содержания шлюза
edit: Content, // Используем его же во время редактирования страницы
canMakePayment: () => true, // Заглушка для проверки доступности шлюза
ariaLabel: label, // Значение aria-label атрибута
supports: {
features: settings?.supports ?? [], // Массив переданный с бекенда, по умолчанию пустой
},
})
Теперь если все классы и функции правильно подключены и запущены, то предупреждение при редактировании Checkout block пропадет и шлюз появится в списке Methods:
Так же шлюз теперь доступен во frontend части сайта и с его помощью можно провести оплату:
Для шлюза, который работает на основе редиректа покупателя на внешнюю страницы оплаты, этого будет вполне достаточно. При нажатии на кнопку «Place Order» данные попадут в метод process_payment
шлюза и далее могут обрабатываться как обычно.
Данной реализации поддержки Checkout block недостаточно для поддержки нескольких шлюзов в одном плагине и для более комплексной логики шлюза во frontend части. К сожалению WooCommerce не обладает полным набор требуемых функций для поддержки сложных шлюзов в блоке Checkout, но есть способы обойти эти недостатки.
В итоге в данной статье описан способ простой и быстрой интеграции шлюзов с Checkout block. С помощью описанного выше кода, можно добавить поддержку данного блока в любой WooCommerce шлюз. Также, несмотря на то, что блоки Gutenberg требуют написание кода на React, мы обошлись без подключения JSX. Во второй части статьи разберем примеры интеграций более сложных шлюзов.