Интеграция платежного шлюза с WooCommerce Checkout Block — часть 1 «Простой вариант»

25 декабря 2023
2 минуты

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. Во второй части статьи разберем примеры интеграций более сложных шлюзов.

Показать ещё