Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Hide payment methods that have missing dependencies and display an error in the admin #3920

Merged
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/extensibility/payment-method-integration.md
Expand Up @@ -136,7 +136,7 @@ In your class:
- 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 (using `wp_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](https://www.npmjs.com/package/@woocommerce/dependency-extraction-webpack-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.
- 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 from `get_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 via `wc.wcSettings.getSetting`. So for instance if you assigned `stripe` as the value of the `name` 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.
Expand Down
52 changes: 52 additions & 0 deletions src/Payments/Api.php
Expand Up @@ -52,6 +52,7 @@ protected function init() {
add_action( 'woocommerce_blocks_cart_enqueue_data', array( $this, 'add_payment_method_script_data' ) );
add_action( 'woocommerce_blocks_payment_method_type_registration', array( $this, 'register_payment_method_integrations' ) );
add_action( 'woocommerce_rest_checkout_process_payment_with_context', array( $this, 'process_legacy_payment' ), 999, 2 );
add_action( 'wp_print_scripts', array( $this, 'verify_payment_methods_dependencies' ), 1 );
}

/**
Expand Down Expand Up @@ -174,4 +175,55 @@ public function process_legacy_payment( PaymentContext $context, PaymentResult &
$result->set_payment_details( array_merge( $result->payment_details, $gateway_result ) );
$result->set_redirect_url( $gateway_result['redirect'] );
}

/**
* Verify all dependencies of registered payment methods have been registered.
* If not, remove that payment method script from the list of dependencies
* of Cart and Checkout block scripts so it doesn't break the blocks and show
* an error in the admin.
*/
public function verify_payment_methods_dependencies() {
$wp_scripts = wp_scripts();
$payment_method_scripts = $this->payment_method_registry->get_all_active_payment_method_script_dependencies();

foreach ( $payment_method_scripts as $payment_method_script ) {
if (
! array_key_exists( $payment_method_script, $wp_scripts->registered ) ||
! property_exists( $wp_scripts->registered[ $payment_method_script ], 'deps' )
) {
continue;
}
$deps = $wp_scripts->registered[ $payment_method_script ]->deps;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this array item guaranteed to exist or do you need a guard?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a guard in 1845b12.

foreach ( $deps as $dep ) {
if ( ! wp_script_is( $dep, 'registered' ) ) {
$error_handle = $dep . '-dependency-error';
$error_message = sprintf(
'Payment gateway with handle \'%1$s\' has been deactivated because its dependency \'%2$s\' is not registered. Read the docs about registering assets for payment methods: https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/docs/extensibility/payment-method-integration.md#registering-assets',
esc_html( $payment_method_script ),
esc_html( $dep )
);

// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
error_log( $error_message );

// phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter,WordPress.WP.EnqueuedResourceParameters.MissingVersion
wp_register_script( $error_handle, '' );
wp_enqueue_script( $error_handle );
wp_add_inline_script(
$error_handle,
sprintf( 'console.error( "%s" );', $error_message )
);

$cart_checkout_scripts = [ 'wc-cart-block', 'wc-cart-block-frontend', 'wc-checkout-block', 'wc-checkout-block-frontend' ];
foreach ( $cart_checkout_scripts as $script_handle ) {
// Remove payment method script from dependencies.
$wp_scripts->registered[ $script_handle ]->deps = array_diff(
$wp_scripts->registered[ $script_handle ]->deps,
[ $payment_method_script ]
);
}
}
}
}
}
}