Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions assets/js/blocks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ function BuckarooComponent({ wc, billing, gateway, eventRegistration, emitRespon
const methodName = convertUnderScoreToDash(gateway.paymentMethodId);

useEffect(() => {
// Only methods that actually carry a payment fee need the server-side
// recalculation. Skipping it for fee-less methods avoids a full
// WordPress bootstrap on every payment method switch.
if (!gateway.hasFee) {
return;
}
Expand All @@ -30,9 +27,6 @@ function BuckarooComponent({ wc, billing, gateway, eventRegistration, emitRespon
method: gateway.paymentMethodId,
},
});

// Abort the in-flight request when the selection changes again so
// rapid switching does not pile up redundant requests.
return () => request.abort();
}, [gateway.paymentMethodId, gateway.hasFee]);

Expand Down Expand Up @@ -254,7 +248,9 @@ const createOptions = (wc, gateway) => ({
label: <BuckarooLabel imagePath={gateway.image_path} title={decodeHtmlEntities(gateway.title)} />,
paymentMethodId: gateway.paymentMethodId,
edit: <div />,
canMakePayment: () => true,
canMakePayment: () =>
(typeof window !== 'undefined' && window.location && window.location.pathname.indexOf('/wp-admin/') !== -1) ||
gateway.available !== false,
ariaLabel: gateway.title,
content: <BuckarooComponent gateway={gateway} wc={wc} />,
});
Expand Down
2 changes: 1 addition & 1 deletion assets/js/dist/blocks.asset.php
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<?php return array('dependencies' => array('react', 'react-dom', 'wp-i18n'), 'version' => 'd2d200f154408c1f39fa');
<?php return array('dependencies' => array('react', 'react-dom', 'wp-i18n'), 'version' => '1f44ae87d0069ba1bcd4');
2 changes: 1 addition & 1 deletion assets/js/dist/blocks.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion assets/js/dist/checkout.js.LICENSE.txt

This file was deleted.

22 changes: 22 additions & 0 deletions index.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,25 @@ function () {
},
-1
);

/*
* Declare compatibility with the WooCommerce Cart & Checkout Blocks feature.
*
* Without this declaration WooCommerce lists the plugin under the "incompatible"
* extensions for the `cart_checkout_blocks` feature (see the WooCommerce Checkout
* block "incompatibleExtensions" data), which is what triggers the Site Editor
* notice suggesting merchants switch back to the Classic Checkout. The Buckaroo
* gateways fully support the block checkout, so this declaration is correct.
*/
add_action(
'before_woocommerce_init',
function () {
if (class_exists(\Automattic\WooCommerce\Utilities\FeaturesUtil::class)) {
\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility(
'cart_checkout_blocks',
BK_PLUGIN_FILE,
true
);
}
}
);
13 changes: 3 additions & 10 deletions library/buckaroo_images/creditcards/clicktopay.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
82 changes: 82 additions & 0 deletions src/Gateways/BuckarooBlocks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

namespace Buckaroo\Woocommerce\Gateways;

use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;

/**
* Per-gateway WooCommerce Blocks payment method integration.
*
* WooCommerce determines whether a payment gateway supports the Cart & Checkout
* blocks by matching every enabled gateway id against the names of the payment
* method integrations registered through the
* `woocommerce_blocks_payment_method_type_registration` hook (see
* PaymentMethodRegistry::get_all_registered_script_data() and
* Checkout block "globalPaymentMethods").
*
* Registering a single umbrella integration is therefore not enough: each
* Buckaroo gateway needs its own integration whose get_name() returns the exact
* gateway id, otherwise the Site Editor reports the gateway as
* "Incompatible with block-based checkout".
*
* This class provides one such integration. All Buckaroo gateways share the same
* `buckaroo-blocks` frontend script (which performs the actual client-side
* registerPaymentMethod() calls); this integration only exposes the server-side
* compatibility declaration and the per-gateway data.
*/
class BuckarooBlocks extends AbstractPaymentMethodType
{
/**
* The gateway id this integration represents (e.g. "buckaroo_ideal").
*/
protected $name;

/**
* Data made available to the client for this gateway.
*/
protected array $paymentMethodData;

public function __construct(string $name, array $paymentMethodData = [])
{
$this->name = $name;
$this->paymentMethodData = $paymentMethodData;
}

public function initialize()
{
//
}

/**
* The gateway visibility/availability is still fully controlled by the
* WooCommerce gateway (is_available) and by the client-side canMakePayment;
* declaring the integration active only tells WooCommerce that this gateway
* *supports* the block, which is what removes the incompatibility warning.
*/
public function is_active()
{
return true;
}

/**
* The aggregated gateway list consumed by the shared frontend script is
* exposed once by the umbrella BuckarooExpressBlocks integration, so the
* per-gateway integration only needs to expose its own (optional) data.
*
* @return array
*/
public function get_payment_method_data()
{
return $this->paymentMethodData;
}

/**
* @return array
*/
public function get_payment_method_script_handles()
{
BuckarooBlocksScript::register();

return [BuckarooBlocksScript::HANDLE];
}
}
82 changes: 82 additions & 0 deletions src/Gateways/BuckarooBlocksScript.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

namespace Buckaroo\Woocommerce\Gateways;

use Buckaroo\Woocommerce\Core\Plugin;

/**
* Central, idempotent registration of the shared Buckaroo Blocks frontend script.
*
* IMPORTANT (hydration): WooCommerce injects every active payment method script
* handle into the dependency list of the Cart and Checkout block frontend
* scripts (see Automattic\WooCommerce\Blocks\Payments\Api::add_payment_method_script_dependencies).
* If `buckaroo-blocks` declares a dependency on a script that is not registered
* on the current request, WordPress cannot resolve the dependency chain and
* silently drops `wc-cart-block-frontend` / `wc-checkout-block-frontend`,
* leaving the Cart/Checkout blocks stuck in their server-rendered loading state
* (Store API hydration never completes).
*
* The Apple Pay / Google Pay button scripts (`buckaroo_apple_pay`,
* `buckaroo_google_pay`) are only enqueued conditionally by PaymentSetupScripts
* (Apple Pay only when enabled; neither on the Cart block page when no express
* method is active for the cart). They therefore MUST NOT be hard dependencies
* of `buckaroo-blocks`. The express block components already guard their use of
* `window.BuckarooInitApplePay` / `window.BuckarooInitGooglePay`, so the express
* buttons still initialise when those scripts are present and degrade gracefully
* when they are not.
*/
class BuckarooBlocksScript
{
public const HANDLE = 'buckaroo-blocks';

public static function register(): void
{
if (wp_script_is(self::HANDLE, 'registered')) {
return;
}

wp_register_script(
self::HANDLE,
plugins_url('/assets/js/dist/blocks.js', BK_PLUGIN_FILE),
['wc-blocks-registry', 'wp-blocks', 'wp-element', 'wp-i18n', 'wp-data'],
self::assetVersion(),
true
);

if (function_exists('wp_set_script_translations')) {
wp_set_script_translations(
self::HANDLE,
'wc-buckaroo-bpe-gateway',
plugin_dir_path(BK_PLUGIN_FILE) . 'languages'
);
}
}

/**
* Content-derived cache-busting version for the bundle.
*
* The compiled bundle is enqueued with a version that changes whenever the
* bundle content changes, so a rebuild is never masked by a stale browser or
* CDN cache (which was the case while the version was pinned to the plugin
* version). Prefers the hash generated by the WooCommerce dependency
* extraction plugin, then the file mtime, then the plugin version.
*/
private static function assetVersion(): string
{
$assetFile = plugin_dir_path(BK_PLUGIN_FILE) . 'assets/js/dist/blocks.asset.php';

if (is_readable($assetFile)) {
$asset = include $assetFile;
if (is_array($asset) && ! empty($asset['version'])) {
return (string) $asset['version'];
}
}

$bundle = plugin_dir_path(BK_PLUGIN_FILE) . 'assets/js/dist/blocks.js';
if (is_readable($bundle)) {
return (string) filemtime($bundle);
}

return Plugin::VERSION;
}
}
24 changes: 9 additions & 15 deletions src/Gateways/BuckarooExpressBlocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
namespace Buckaroo\Woocommerce\Gateways;

use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
use Buckaroo\Woocommerce\Core\Plugin;

/**
* Buckaroo Express payment methods integration for WooCommerce Blocks
* Buckaroo Express payment methods integration for WooCommerce Blocks.
*
* This umbrella integration exposes the aggregated list of Buckaroo gateways to
* the shared `buckaroo-blocks` frontend script, which performs the client-side
* registration of both the regular and express payment methods. Per-gateway
* block compatibility is declared separately by {@see BuckarooBlocks}.
*/
class BuckarooExpressBlocks extends AbstractPaymentMethodType
{
Expand Down Expand Up @@ -36,18 +40,8 @@ public function get_payment_method_data()
*/
public function get_payment_method_script_handles()
{
wp_register_script(
'buckaroo-blocks',
plugins_url('/assets/js/dist/blocks.js', BK_PLUGIN_FILE),
['wc-blocks-registry', 'wp-blocks', 'wp-element', 'wp-i18n', 'wp-data', 'buckaroo_apple_pay', 'buckaroo_google_pay'],
Plugin::VERSION,
true
);

if (function_exists('wp_set_script_translations')) {
wp_set_script_translations('buckaroo-blocks', 'wc-buckaroo-bpe-gateway', plugin_dir_path(BK_PLUGIN_FILE) . 'languages');
}

return ['buckaroo-blocks'];
BuckarooBlocksScript::register();

return [BuckarooBlocksScript::HANDLE];
}
}
73 changes: 69 additions & 4 deletions src/Hooks/InitGateways.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Buckaroo\Woocommerce\Gateways\Idin\IdinController;
use Buckaroo\Woocommerce\Gateways\Idin\IdinProcessor;
use Buckaroo\Woocommerce\Gateways\PayByBank\PayByBankProcessor;
use Buckaroo\Woocommerce\Gateways\BuckarooBlocks;
use Buckaroo\Woocommerce\Gateways\BuckarooExpressBlocks;
use Buckaroo\Woocommerce\Gateways\PaypalExpress\PaypalExpressController;
use Buckaroo\Woocommerce\PaymentProcessors\PushProcessor;
Expand Down Expand Up @@ -98,7 +99,14 @@ public function initGatewaysOnCheckout()
$payment_methods = [];

foreach ($gateways as $gateway_id => $gateway) {
if ($this->isBuckarooPayment($gateway_id) && $gateway->isVisibleInCheckout()) {
// Register every enabled Buckaroo gateway so it is declared block-
// compatible in the Site Editor. Runtime availability (e.g. store
// currency vs the gateway's supported currencies) is carried by the
// "available" flag and enforced client-side via canMakePayment in
// blocks.js, so currency-restricted methods (Swish/Twint/Blik) are
// recognised as compatible but never offered at an incompatible
// checkout.
if ($this->isBuckarooPayment($gateway_id) && $gateway->enabled === 'yes') {
$payment_method = [
'paymentMethodId' => $gateway_id,
'title' => $gateway->get_title(),
Expand All @@ -108,6 +116,7 @@ public function initGatewaysOnCheckout()
'genders' => Helper::getAllGendersForPaymentMethods(),
'displayMode' => $gateway->get_option('displaymode'),
'hasFee' => $this->gatewayHasFee($gateway),
'available' => $gateway->isVisibleInCheckout(),
];

if ($gateway_id === 'buckaroo_paybybank') {
Expand Down Expand Up @@ -210,7 +219,18 @@ private function getCredtCardIsSecure()
}

/**
* Register Buckaroo Express payment methods blocks support
* Register Buckaroo blocks support with WooCommerce Blocks.
*
* Two things are registered here:
*
* 1. One integration per enabled Buckaroo gateway, whose get_name() matches
* the gateway id. WooCommerce matches these names against the list of
* enabled gateways to decide block compatibility, so this is what removes
* the "Incompatible with block-based checkout" warning in the Site Editor.
*
* 2. The umbrella BuckarooExpressBlocks integration, which continues to
* expose the aggregated gateway list consumed by the shared frontend
* script for both regular and express payment method registration.
*
* @param object $payment_method_registry Payment method registry from WooCommerce Blocks
*/
Expand All @@ -220,7 +240,52 @@ public function registerBuckarooExpressBlocks($payment_method_registry)
return;
}

// Register universal blocks support for all Buckaroo express payment methods
$payment_method_registry->register(new BuckarooExpressBlocks($this->initGatewaysOnCheckout()));
$paymentMethods = $this->initGatewaysOnCheckout();

// Declare per-gateway block compatibility for every enabled Buckaroo gateway.
foreach ($this->getEnabledBuckarooGatewayIds() as $gatewayId) {
if ($payment_method_registry->is_registered($gatewayId)) {
continue;
}

$payment_method_registry->register(
new BuckarooBlocks($gatewayId)
);
}

// Register universal blocks support for all Buckaroo express payment methods.
if (! $payment_method_registry->is_registered('buckaroo_express_blocks')) {
$payment_method_registry->register(new BuckarooExpressBlocks($paymentMethods));
}
}

/**
* Return the ids of every enabled Buckaroo payment gateway.
*
* Uses the full enabled-gateway list (not only the checkout-visible ones)
* because the Site Editor evaluates block compatibility against every
* enabled gateway.
*
* @return string[]
*/
private function getEnabledBuckarooGatewayIds(): array
{
if (! class_exists('WC_Payment_Gateways')) {
return [];
}

$ids = [];

foreach (WC()->payment_gateways()->payment_gateways() as $gatewayId => $gateway) {
if (! $this->isBuckarooPayment($gatewayId)) {
continue;
}

if (filter_var($gateway->enabled, FILTER_VALIDATE_BOOLEAN)) {
$ids[] = $gatewayId;
}
}

return $ids;
}
}
Loading