Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix React error when the Express Checkout's container element is not found. #9420

Merged
merged 7 commits into from
Sep 12, 2024

Conversation

asumaran
Copy link
Contributor

@asumaran asumaran commented Sep 11, 2024

Fixes #9419

Changes proposed in this Pull Request

Since the the_content filter is never triggered when the checkout page is assigned a block-based template, the elements we were printing as containers for the buttons used to check the availability of ApplePay/GooglePay payment methods were not rendered. As a result, React failed to mount the button because the containers didn’t exist.

We’re changing the approach by creating the container dynamically and appending it to the page using JavaScript. This ensures the buttons are rendered in both cases, whether using a standard theme or a block-based theme.

Why is it happening?

When a page uses a block-based template, it includes the template-canvas.php file as base (ref), which prints the HTML generated from the block template. Notably, this file never calls the_content(). (This the block template the site that reported the issue was using). – As side note, @reykjalin' fix works because this file do call wp_footer(), which applies the wp_footer action (ref).

However, when using a regular theme, the checkout block is rendered as part of the page content. In themes, the page content is printed using the_content() (ref), which applies the the_content filter (ref).

Unfortunately, to render the elements that would be used as containers for the buttons used to check the availability of payment methods, this the_content filter was used, which is not always called. We should have used the wp_footer action or perhaps used JS to create the element.

Testing instructions

To reproduce the bug

  • Log in as as admin – The error is shown only for admins.
  • Switch to the develop branch.
  • Install the following theme what-theme.zip
  • Create a shortcode-based checkout page if you don't have one already
    • Add the "Classic Checkout" block or add the [woocommerce_checkout] using the shortcode block.
    • Assign the page-checkout template to it.
  • Go to store and add a product to the cart.
  • Go to the newly created page.
  • ❌ You'll observe the React error.

To confirm the fix

  • Switch to this branch as-fix-react-error-container-not-found
  • Repeat the previous steps.
  • There shouldn't be any error displayed.
  • ✅ Express Checkout buttons should be displayed.
  • Log out from the store.
  • Refresh the Checkout page.
  • ✅ Express Checkout buttons should be displayed.

  • Run npm run changelog to add a changelog file, choose patch to leave it empty if the change is not significant. You can add multiple changelog files in one PR by running this command a few times.
  • Covered with tests (or have a good reason not to test in description ☝️)
  • Tested on mobile (or does not apply)

Post merge

Avoids printing the HTML DIV element using the `the_content` filter as it’s not secure to always be called.

Templated pages don’t run this filter therefore the script to detect the payment method availability will fail.
@botwoo
Copy link
Collaborator

botwoo commented Sep 11, 2024

Test the build

Option 1. Jetpack Beta

  • Install and activate Jetpack Beta.
  • Use this build by searching for PR number 9420 or branch name as-fix-react-error-container-not-found in your-test.site/wp-admin/admin.php?page=jetpack-beta&plugin=woocommerce-payments

Option 2. Jurassic Ninja - available for logged-in A12s

🚀 Launch a JN site with this branch 🚀

ℹ️ Install this Tampermonkey script to get more options.


Build info:

  • Latest commit: b158cc5
  • Build time: 2024-09-12 21:23:09 UTC

Note: the build is updated when a new commit is pushed to this PR.

Copy link
Contributor

github-actions bot commented Sep 11, 2024

Size Change: +15 B (0%)

Total Size: 1.33 MB

Filename Size Change
release/woocommerce-payments/dist/blocks-checkout.js 66.4 kB +15 B (0%)
ℹ️ View Unchanged
Filename Size
release/woocommerce-payments/assets/css/admin.css 1.08 kB
release/woocommerce-payments/assets/css/admin.rtl.css 1.08 kB
release/woocommerce-payments/assets/css/success.css 173 B
release/woocommerce-payments/assets/css/success.rtl.css 173 B
release/woocommerce-payments/dist/blocks-checkout-rtl.css 2.52 kB
release/woocommerce-payments/dist/blocks-checkout.css 2.52 kB
release/woocommerce-payments/dist/cart-block.js 16.3 kB
release/woocommerce-payments/dist/cart.js 5.73 kB
release/woocommerce-payments/dist/checkout-rtl.css 927 B
release/woocommerce-payments/dist/checkout.css 927 B
release/woocommerce-payments/dist/checkout.js 32.5 kB
release/woocommerce-payments/dist/express-checkout-rtl.css 230 B
release/woocommerce-payments/dist/express-checkout.css 230 B
release/woocommerce-payments/dist/express-checkout.js 14.3 kB
release/woocommerce-payments/dist/frontend-tracks.js 858 B
release/woocommerce-payments/dist/index-rtl.css 39.2 kB
release/woocommerce-payments/dist/index.css 39.2 kB
release/woocommerce-payments/dist/index.js 302 kB
release/woocommerce-payments/dist/multi-currency-analytics.js 1.08 kB
release/woocommerce-payments/dist/multi-currency-rtl.css 3.41 kB
release/woocommerce-payments/dist/multi-currency-switcher-block.js 60.5 kB
release/woocommerce-payments/dist/multi-currency.css 3.41 kB
release/woocommerce-payments/dist/multi-currency.js 55.5 kB
release/woocommerce-payments/dist/order-rtl.css 730 B
release/woocommerce-payments/dist/order.css 730 B
release/woocommerce-payments/dist/order.js 42.7 kB
release/woocommerce-payments/dist/payment-gateways-rtl.css 1.35 kB
release/woocommerce-payments/dist/payment-gateways.css 1.35 kB
release/woocommerce-payments/dist/payment-gateways.js 39.2 kB
release/woocommerce-payments/dist/payment-request-rtl.css 230 B
release/woocommerce-payments/dist/payment-request.css 230 B
release/woocommerce-payments/dist/payment-request.js 13.7 kB
release/woocommerce-payments/dist/plugins-page-rtl.css 386 B
release/woocommerce-payments/dist/plugins-page.css 386 B
release/woocommerce-payments/dist/plugins-page.js 20.1 kB
release/woocommerce-payments/dist/product-details-rtl.css 433 B
release/woocommerce-payments/dist/product-details.css 436 B
release/woocommerce-payments/dist/product-details.js 11.6 kB
release/woocommerce-payments/dist/settings-rtl.css 11.6 kB
release/woocommerce-payments/dist/settings.css 11.5 kB
release/woocommerce-payments/dist/settings.js 224 kB
release/woocommerce-payments/dist/subscription-edit-page.js 703 B
release/woocommerce-payments/dist/subscription-product-onboarding-modal-rtl.css 524 B
release/woocommerce-payments/dist/subscription-product-onboarding-modal.css 524 B
release/woocommerce-payments/dist/subscription-product-onboarding-modal.js 20.2 kB
release/woocommerce-payments/dist/subscription-product-onboarding-toast.js 730 B
release/woocommerce-payments/dist/subscriptions-empty-state-rtl.css 120 B
release/woocommerce-payments/dist/subscriptions-empty-state.css 120 B
release/woocommerce-payments/dist/subscriptions-empty-state.js 19.3 kB
release/woocommerce-payments/dist/tokenized-payment-request-rtl.css 230 B
release/woocommerce-payments/dist/tokenized-payment-request.css 230 B
release/woocommerce-payments/dist/tokenized-payment-request.js 14.5 kB
release/woocommerce-payments/dist/tos-rtl.css 235 B
release/woocommerce-payments/dist/tos.css 235 B
release/woocommerce-payments/dist/tos.js 21.8 kB
release/woocommerce-payments/dist/woopay-direct-checkout.js 6.14 kB
release/woocommerce-payments/dist/woopay-express-button.js 24.1 kB
release/woocommerce-payments/dist/woopay-rtl.css 4.54 kB
release/woocommerce-payments/dist/woopay.css 4.51 kB
release/woocommerce-payments/dist/woopay.js 71.3 kB
release/woocommerce-payments/includes/subscriptions/assets/css/plugin-page.css 625 B
release/woocommerce-payments/includes/subscriptions/assets/js/plugin-page.js 814 B
release/woocommerce-payments/vendor/automattic/jetpack-assets/build/i18n-loader.js 2.46 kB
release/woocommerce-payments/vendor/automattic/jetpack-assets/build/jetpack-script-data.js 735 B
release/woocommerce-payments/vendor/automattic/jetpack-assets/build/react-jsx-runtime.js 553 B
release/woocommerce-payments/vendor/automattic/jetpack-assets/src/js/i18n-loader.js 1.02 kB
release/woocommerce-payments/vendor/automattic/jetpack-assets/src/js/script-data.js 69 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/babel.config.js 163 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/identity-crisis.css 2.45 kB
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/identity-crisis.js 14.2 kB
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/identity-crisis.rtl.css 2.45 kB
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-admin-create-user.css 198 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-admin-create-user.js 280 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-admin-create-user.rtl.css 198 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-login.css 625 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-login.js 333 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-login.rtl.css 626 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/jetpack-sso-users.js 417 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/tracks-ajax.js 521 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/tracks-callables.js 584 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-admin-create-user.css 215 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-admin-create-user.js 521 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-login.css 721 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-login.js 412 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/src/sso/jetpack-sso-users.js 621 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/about.css 1.04 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/admin-empty-state.css 294 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/admin-order-statuses.css 408 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/admin.css 3.59 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/checkout.css 301 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/modal.css 746 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/view-subscription.css 574 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/wcs-upgrade.css 414 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/admin-pointers.js 543 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/admin.js 9.4 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/jstz.js 6.78 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/jstz.min.js 3.84 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-coupon.js 545 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-subscription.js 2.52 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/moment.js 22.2 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/moment.min.js 11.7 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/payment-method-restrictions.js 1.29 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/wcs-meta-boxes-order.js 507 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/payment-methods.js 358 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/single-product.js 428 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/view-subscription.js 1.38 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/wcs-cart.js 782 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/modal.js 1.09 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/wcs-upgrade.js 1.26 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/build/index.css 391 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/build/index.js 3.04 kB

compressed-size-action

@asumaran asumaran requested a review from bborman22 September 12, 2024 03:15
@asumaran asumaran self-assigned this Sep 12, 2024
@asumaran asumaran marked this pull request as ready for review September 12, 2024 03:15
@asumaran asumaran changed the title Fix React error when the Express Checkouts container element is not found. Fix React error when the Express Checkout's container element is not found. Sep 12, 2024
@bborman22 bborman22 changed the base branch from develop to release/8.2.1 September 12, 2024 16:16
@bborman22 bborman22 changed the base branch from release/8.2.1 to develop September 12, 2024 16:17
Copy link
Contributor

@bborman22 bborman22 left a comment

Choose a reason for hiding this comment

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

I've tested this fix with the original Blocks Canvas theme provided over Slack, the Tsubaki theme, the provided What Theme, and Storefront. I tested these on Chrome, Safari, and Firefox (to confirm that the Express Checkout box gets properly hidden still). And I checked on product, cart, and checkout pages. I didn't see any issues in my testing and confirmed both CC, GPay, and Apple Pay all worked to complete the checkout. I'll note that all this testing happened on a JN site as well.

I had one small note about spelling and I'd like to get at least one other approval and review on both this approach and confirmation of it working as expected across different environments.

@ricardo ricardo self-requested a review September 12, 2024 17:01
@pierorocca
Copy link
Contributor

@senadir @alexflorisca @ralucaStan tagging you all for awareness in case this scenario comes up with other 3P gateways that are implementing express checkout buttons. Please feel free to sanity check this solution. Thank you.

Copy link
Member

@ricardo ricardo left a comment

Choose a reason for hiding this comment

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

@asumaran we should probably rebase this PR from trunk so it's easier for the release DRI to include in the patch release.

Review: Tested this in Safari and Chrome with Storefront, What Theme and Block Canvas.

  • ✅ Reproduced the bug:
Bug
  • ✅ Confirmed the fix:
Fix Fix

Comment on lines 18 to 35
// Create the DIV container on the fly
const containerEl = document.createElement( 'div' );

// Ensure the element is hidden and doesn’t interfere with the page layout.
containerEl.style.border = 0;
containerEl.style.height = '0';
containerEl.style.margin = '0';
containerEl.style.overflow = 'hidden';
containerEl.style.padding = '0';
containerEl.style.position = 'absolute';
containerEl.style.width = '0';
containerEl.style.float = 'left';
containerEl.style.opacity = '0';
containerEl.style.pointerEvents = 'none';

document.querySelector( 'body' ).appendChild( containerEl );

const root = ReactDOM.createRoot( containerEl );
Copy link
Member

Choose a reason for hiding this comment

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

I also tested this with only:

containerEl.style.display = 'none';

And it worked as expected. With display: none, the element shouldn't have any pointer events and shouldn't take up any space.

We might not need to keep the element technically visible by setting other properties to 0, but perhaps I could be missing something?

The current approach also LGTM, the only downside is that it's slightly more complex and the element is still "visible" in the DOM, including for assistive technologies, although temporarily.

cc @bborman22

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess it doesn't matter if the button doesn't end up rendering as long as we have the onReady event to be called with the info we need.

Copy link
Contributor

Choose a reason for hiding this comment

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

the only downside is that it's slightly more complex and the element is still "visible" in the DOM, including for assistive technologies

Great catch! I missed the ariaHidden not being set. I think at a minimum that should be set. Display none is certainly simpler, just wondering if there are some gotchas there as we don't use it in other places we create a hidden div? ref1 ref2 with the second ref using an iframe as one possible explanation.

Copy link
Member

@ricardo ricardo Sep 12, 2024

Choose a reason for hiding this comment

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

I believe it would depend mostly on Stripe, e.g. if it checks for any layout measurements of the root element, or if the contents are technically visible.

Both approaches seem to work though, so I don't have a strong preference, but I agree with @bborman22 we should probably set containerEl.setAttribute( 'aria-hidden', 'true' ); if not using display: none.

Copy link
Contributor Author

@asumaran asumaran Sep 12, 2024

Choose a reason for hiding this comment

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

I've updated the PR with the suggestion. 70191f7 – I've tested with regular and block-based theme. With Safari, Google Chrome, and Firefox.

Copy link
Contributor

@bborman22 bborman22 left a comment

Choose a reason for hiding this comment

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

I ran through a similar set of tests as before and found no issues with the display none approach! I also gave some additional testing to the shortcode checkout as well with no issues.

LGTM! Again just want to get two approvals on this with the new approach as well.

Copy link
Member

@ricardo ricardo left a comment

Choose a reason for hiding this comment

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

LGTM and tests well.

I also ran through a similar set of tests and the button worked as expected.

@asumaran asumaran enabled auto-merge September 12, 2024 21:20
@asumaran asumaran added this pull request to the merge queue Sep 12, 2024
Merged via the queue into develop with commit cb5460d Sep 12, 2024
25 checks passed
@asumaran asumaran deleted the as-fix-react-error-container-not-found branch September 12, 2024 21:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Express Checkout Block not working with WooPayments 8.2.0
6 participants