PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.1
WooCommerce v10.9.1
10.9.3 10.9.2 10.9.1 10.9.0 10.9.0-rc.1 10.9.0-beta.2 10.9.0-beta.1 10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / src / Blocks / BlockTypes / Checkout.php
woocommerce / src / Blocks / BlockTypes Last commit date
Accordion 1 year ago AddToCartWithOptions 1 week ago OrderConfirmation 2 months ago ProductCollection 3 weeks ago Reviews 2 months ago AbstractBlock.php 4 weeks ago AbstractDynamicBlock.php 2 years ago AbstractInnerBlock.php 1 year ago AbstractProductGrid.php 3 months ago ActiveFilters.php 2 years ago AddToCartForm.php 4 weeks ago AddToWishlistButton.php 4 weeks ago AllProducts.php 2 years ago AllReviews.php 2 years ago AtomicBlock.php 2 years ago AttributeFilter.php 1 year ago Breadcrumbs.php 1 year ago Cart.php 2 months ago CartAcceptedPaymentMethodsBlock.php 2 years ago CartCrossSellsBlock.php 2 years ago CartCrossSellsProductsBlock.php 2 years ago CartExpressPaymentBlock.php 1 year ago CartItemsBlock.php 2 years ago CartLineItemsBlock.php 2 years ago CartLink.php 2 months ago CartOrderSummaryBlock.php 2 years ago CartOrderSummaryCouponFormBlock.php 2 years ago CartOrderSummaryDiscountBlock.php 2 years ago CartOrderSummaryFeeBlock.php 2 years ago CartOrderSummaryHeadingBlock.php 2 years ago CartOrderSummaryShippingBlock.php 2 years ago CartOrderSummarySubtotalBlock.php 2 years ago CartOrderSummaryTaxesBlock.php 2 years ago CartOrderSummaryTotalsBlock.php 2 years ago CartTotalsBlock.php 2 years ago CatalogSorting.php 4 weeks ago CategoryDescription.php 2 months ago CategoryTitle.php 2 months ago Checkout.php 2 months ago CheckoutActionsBlock.php 1 year ago CheckoutAdditionalInformationBlock.php 2 years ago CheckoutBillingAddressBlock.php 2 years ago CheckoutContactInformationBlock.php 2 years ago CheckoutExpressPaymentBlock.php 9 months ago CheckoutFieldsBlock.php 2 years ago CheckoutOrderNoteBlock.php 2 years ago CheckoutOrderSummaryBlock.php 2 years ago CheckoutOrderSummaryCartItemsBlock.php 2 years ago CheckoutOrderSummaryCouponFormBlock.php 2 years ago CheckoutOrderSummaryDiscountBlock.php 2 years ago CheckoutOrderSummaryFeeBlock.php 2 years ago CheckoutOrderSummaryShippingBlock.php 2 years ago CheckoutOrderSummarySubtotalBlock.php 2 years ago CheckoutOrderSummaryTaxesBlock.php 2 years ago CheckoutOrderSummaryTotalsBlock.php 2 years ago CheckoutPaymentBlock.php 2 years ago CheckoutPickupOptionsBlock.php 2 years ago CheckoutShippingAddressBlock.php 2 years ago CheckoutShippingMethodBlock.php 2 years ago CheckoutShippingMethodsBlock.php 2 years ago CheckoutTermsBlock.php 2 years ago CheckoutTotalsBlock.php 2 years ago ClassicShortcode.php 1 year ago ClassicTemplate.php 4 months ago ComingSoon.php 1 year ago CouponCode.php 2 months ago CustomerAccount.php 3 months ago Dropdown.php 4 weeks ago EmailContent.php 5 months ago EmptyCartBlock.php 2 years ago EmptyMiniCartContentsBlock.php 11 months ago EnableBlockJsonAssetsTrait.php 1 year ago FeaturedCategory.php 7 months ago FeaturedItem.php 7 months ago FeaturedProduct.php 7 months ago FilledCartBlock.php 2 years ago FilledMiniCartContentsBlock.php 4 months ago FilterWrapper.php 2 years ago HandpickedProducts.php 1 year ago MiniCart.php 4 weeks ago MiniCartCartButtonBlock.php 11 months ago MiniCartCheckoutButtonBlock.php 11 months ago MiniCartContents.php 3 months ago MiniCartFooterBlock.php 4 weeks ago MiniCartItemsBlock.php 11 months ago MiniCartProductsTableBlock.php 4 weeks ago MiniCartShoppingButtonBlock.php 9 months ago MiniCartTitleBlock.php 11 months ago MiniCartTitleItemsCounterBlock.php 11 months ago MiniCartTitleLabelBlock.php 11 months ago NextPreviousButtons.php 5 months ago PageContentWrapper.php 2 years ago PaymentMethodIcons.php 11 months ago PriceFilter.php 1 year ago ProceedToCheckoutBlock.php 2 years ago ProductAverageRating.php 1 year ago ProductBestSellers.php 2 years ago ProductButton.php 2 months ago ProductCategories.php 4 weeks ago ProductCategory.php 2 years ago ProductDescription.php 9 months ago ProductDetails.php 5 months ago ProductFilterActive.php 4 weeks ago ProductFilterAttribute.php 4 weeks ago ProductFilterCheckboxList.php 4 weeks ago ProductFilterChips.php 4 weeks ago ProductFilterClearButton.php 4 weeks ago ProductFilterPrice.php 4 weeks ago ProductFilterPriceSlider.php 4 weeks ago ProductFilterRating.php 4 weeks ago ProductFilterRemovableChips.php 4 weeks ago ProductFilterStatus.php 4 weeks ago ProductFilterTaxonomy.php 4 weeks ago ProductFilters.php 3 weeks ago ProductGallery.php 4 weeks ago ProductGalleryLargeImage.php 4 weeks ago ProductGalleryThumbnails.php 4 weeks ago ProductImage.php 4 weeks ago ProductImageGallery.php 7 months ago ProductMeta.php 1 year ago ProductNew.php 2 years ago ProductOnSale.php 2 years ago ProductPrice.php 2 months ago ProductQuery.php 4 weeks ago ProductRating.php 1 year ago ProductRatingCounter.php 1 year ago ProductRatingStars.php 1 year ago ProductResultsCount.php 2 months ago ProductSKU.php 2 months ago ProductSaleBadge.php 1 year ago ProductSearch.php 10 months ago ProductSpecifications.php 2 months ago ProductStockIndicator.php 2 months ago ProductSummary.php 7 months ago ProductTag.php 2 years ago ProductTemplate.php 2 months ago ProductTitle.php 1 year ago ProductTopRated.php 2 years ago ProductsByAttribute.php 2 years ago RatingFilter.php 2 years ago RelatedProducts.php 3 months ago ReviewsByCategory.php 2 years ago ReviewsByProduct.php 2 years ago SavedForLater.php 4 weeks ago SingleProduct.php 2 months ago StockFilter.php 2 years ago StoreNotices.php 1 year ago Wishlist.php 4 weeks ago
Checkout.php
670 lines
1 <?php
2 declare( strict_types = 1);
3 namespace Automattic\WooCommerce\Blocks\BlockTypes;
4
5 use Automattic\Block_Scanner;
6 use Automattic\WooCommerce\StoreApi\Utilities\LocalPickupUtils;
7 use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
8 use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
9 use Automattic\WooCommerce\Blocks\Package;
10 use Automattic\WooCommerce\StoreApi\Utilities\PaymentUtils;
11 use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldsSchema\Validation;
12 use Automattic\WooCommerce\Internal\AddressProvider\AddressProviderController;
13
14 /**
15 * Checkout class.
16 *
17 * @internal
18 */
19 class Checkout extends AbstractBlock {
20 /**
21 * Block name.
22 *
23 * @var string
24 */
25 protected $block_name = 'checkout';
26
27 /**
28 * Chunks build folder.
29 *
30 * @var string
31 */
32 protected $chunks_folder = 'checkout-blocks';
33
34 /**
35 * Initialize this block type.
36 *
37 * - Hook into WP lifecycle.
38 * - Register the block with WordPress.
39 */
40 protected function initialize() {
41 parent::initialize();
42 add_action( 'rest_api_init', array( $this, 'register_settings' ) );
43 add_action( 'wp_loaded', array( $this, 'register_patterns' ) );
44 add_action( 'wp', array( $this, 'disable_wp_emoji' ) );
45 // This prevents the page redirecting when the cart is empty. This is so the editor still loads the page preview.
46 add_filter(
47 'woocommerce_checkout_redirect_empty_cart',
48 function ( $redirect_empty_cart ) {
49 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
50 return isset( $_GET['_wp-find-template'] ) ? false : $redirect_empty_cart;
51 }
52 );
53
54 add_action( 'save_post', array( $this, 'update_local_pickup_title' ), 10, 2 );
55 }
56
57 /**
58 * Remove WordPress emoji detection script on pages containing this block.
59 *
60 * The wp-emoji MutationObserver converts emoji text nodes to <img> elements
61 * when React hydrates or re-renders, corrupting the DOM tree and crashing the block.
62 * The wp-exclude-emoji class on the wrapper only prevents the initial parse, not the
63 * MutationObserver, so the script must be removed entirely.
64 *
65 * @since 10.8.0
66 *
67 * @return void
68 */
69 public function disable_wp_emoji() {
70 if ( has_block( $this->get_full_block_name() ) ) {
71 remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
72 remove_action( 'wp_print_styles', 'print_emoji_styles' );
73 }
74 }
75
76 /**
77 * Dequeues the scripts added by WC Core to the Checkout page.
78 *
79 * @return void
80 */
81 public function dequeue_woocommerce_core_scripts() {
82 wp_dequeue_script( 'wc-checkout' );
83 wp_dequeue_script( 'wc-address-autocomplete' );
84 wp_dequeue_style( 'wc-address-autocomplete' );
85 wp_dequeue_script( 'wc-password-strength-meter' );
86 wp_dequeue_script( 'selectWoo' );
87 wp_dequeue_style( 'select2' );
88 }
89
90 /**
91 * Exposes settings exposed by the checkout block.
92 */
93 public function register_settings() {
94 register_setting(
95 'options',
96 'woocommerce_checkout_phone_field',
97 array(
98 'type' => 'object',
99 'description' => __( 'Controls the display of the phone field in checkout.', 'woocommerce' ),
100 'label' => __( 'Phone number', 'woocommerce' ),
101 'show_in_rest' => array(
102 'name' => 'woocommerce_checkout_phone_field',
103 'schema' => array(
104 'type' => 'string',
105 'enum' => array( 'optional', 'required', 'hidden' ),
106 ),
107 ),
108 'default' => CartCheckoutUtils::get_phone_field_visibility(),
109 )
110 );
111 register_setting(
112 'options',
113 'woocommerce_checkout_company_field',
114 array(
115 'type' => 'object',
116 'description' => __( 'Controls the display of the company field in checkout.', 'woocommerce' ),
117 'label' => __( 'Company', 'woocommerce' ),
118 'show_in_rest' => array(
119 'name' => 'woocommerce_checkout_company_field',
120 'schema' => array(
121 'type' => 'string',
122 'enum' => array( 'optional', 'required', 'hidden' ),
123 ),
124 ),
125 'default' => CartCheckoutUtils::get_company_field_visibility(),
126 )
127 );
128 register_setting(
129 'options',
130 'woocommerce_checkout_address_2_field',
131 array(
132 'type' => 'object',
133 'description' => __( 'Controls the display of the apartment (address_2) field in checkout.', 'woocommerce' ),
134 'label' => __( 'Address Line 2', 'woocommerce' ),
135 'show_in_rest' => array(
136 'name' => 'woocommerce_checkout_address_2_field',
137 'schema' => array(
138 'type' => 'string',
139 'enum' => array( 'optional', 'required', 'hidden' ),
140 ),
141 ),
142 'default' => CartCheckoutUtils::get_address_2_field_visibility(),
143 )
144 );
145 }
146
147 /**
148 * Register block pattern for Empty Cart Message to make it translatable.
149 */
150 public function register_patterns() {
151 register_block_pattern(
152 'woocommerce/checkout-heading',
153 array(
154 'title' => '',
155 'inserter' => false,
156 'content' => '<!-- wp:heading {"align":"wide", "level":1} --><h1 class="wp-block-heading alignwide">' . esc_html__( 'Checkout', 'woocommerce' ) . '</h1><!-- /wp:heading -->',
157 )
158 );
159 }
160
161 /**
162 * Get the editor script handle for this block type.
163 *
164 * @param string $key Data to get, or default to everything.
165 * @return array|string;
166 */
167 protected function get_block_type_editor_script( $key = null ) {
168 $script = [
169 'handle' => 'wc-' . $this->block_name . '-block',
170 'path' => $this->asset_api->get_block_asset_build_path( $this->block_name ),
171 'dependencies' => [ 'wc-blocks' ],
172 ];
173 return $key ? $script[ $key ] : $script;
174 }
175
176 /**
177 * Get the frontend script handle for this block type.
178 *
179 * @see $this->register_block_type()
180 * @param string $key Data to get, or default to everything.
181 * @return array|string
182 */
183 protected function get_block_type_script( $key = null ) {
184 $dependencies = [];
185
186 // Load password strength meter script asynchronously if needed.
187 if ( ! is_user_logged_in() && 'no' === get_option( 'woocommerce_registration_generate_password' ) ) {
188 $dependencies[] = 'zxcvbn-async';
189 }
190
191 $checkout_fields = Package::container()->get( CheckoutFields::class );
192 // Load schema parser asynchronously if we need it.
193 if ( Validation::has_field_schema( $checkout_fields->get_additional_fields() ) ) {
194 $dependencies[] = 'wc-schema-parser';
195 }
196
197 $script = [
198 'handle' => 'wc-' . $this->block_name . '-block-frontend',
199 'path' => $this->asset_api->get_block_asset_build_path( $this->block_name . '-frontend' ),
200 'dependencies' => $dependencies,
201 ];
202 return $key ? $script[ $key ] : $script;
203 }
204
205 /**
206 * Get the frontend style handle for this block type.
207 *
208 * @return string[]
209 */
210 protected function get_block_type_style() {
211 return array_merge( parent::get_block_type_style(), [ 'wc-blocks-packages-style' ] );
212 }
213
214 /**
215 * Enqueue frontend assets for this block, just in time for rendering.
216 *
217 * @param array $attributes Any attributes that currently are available from the block.
218 * @param string $content The block content.
219 * @param WP_Block $block The block object.
220 */
221 protected function enqueue_assets( array $attributes, $content, $block ) {
222 /**
223 * Fires before checkout block scripts are enqueued.
224 *
225 * @since 4.6.0
226 */
227 do_action( 'woocommerce_blocks_enqueue_checkout_block_scripts_before' );
228 parent::enqueue_assets( $attributes, $content, $block );
229 /**
230 * Fires after checkout block scripts are enqueued.
231 *
232 * @since 4.6.0
233 */
234 do_action( 'woocommerce_blocks_enqueue_checkout_block_scripts_after' );
235 }
236
237 /**
238 * Append frontend scripts when rendering the block.
239 *
240 * @param array $attributes Block attributes.
241 * @param string $content Block content.
242 * @param WP_Block $block Block instance.
243 * @return string Rendered block type output.
244 */
245 protected function render( $attributes, $content, $block ) {
246
247 if ( $this->is_checkout_endpoint() ) {
248 // Note: Currently the block only takes care of the main checkout form -- if an endpoint is set, refer to the
249 // legacy shortcode instead and do not render block.
250 return wp_is_block_theme() ? do_shortcode( '[woocommerce_checkout]' ) : '[woocommerce_checkout]';
251 }
252
253 // Dequeue the core scripts when rendering this block.
254 add_action( 'wp_enqueue_scripts', array( $this, 'dequeue_woocommerce_core_scripts' ), 20 );
255
256 /**
257 * We need to check if $content has any templates from prior iterations of the block, in order to update to the latest iteration.
258 * We test the iteration version by searching for new blocks brought in by it.
259 * The blocks used for testing should be always available in the block (not removable by the user).
260 * Checkout i1's content was returning an empty div, with no data-block-name attribute
261 */
262 $regex_for_empty_block = '/<div class="[a-zA-Z0-9_\- ]*wp-block-woocommerce-checkout[a-zA-Z0-9_\- ]*"><\/div>/mi';
263 $has_i1_template = preg_match( $regex_for_empty_block, $content );
264
265 if ( $has_i1_template ) {
266 // This fallback needs to match the default templates defined in our Blocks.
267 $inner_blocks_html = '
268 <div data-block-name="woocommerce/checkout-fields-block" class="wp-block-woocommerce-checkout-fields-block">
269 <div data-block-name="woocommerce/checkout-express-payment-block" class="wp-block-woocommerce-checkout-express-payment-block"></div>
270 <div data-block-name="woocommerce/checkout-contact-information-block" class="wp-block-woocommerce-checkout-contact-information-block"></div>
271 <div data-block-name="woocommerce/checkout-shipping-address-block" class="wp-block-woocommerce-checkout-shipping-address-block"></div>
272 <div data-block-name="woocommerce/checkout-billing-address-block" class="wp-block-woocommerce-checkout-billing-address-block"></div>
273 <div data-block-name="woocommerce/checkout-shipping-methods-block" class="wp-block-woocommerce-checkout-shipping-methods-block"></div>
274 <div data-block-name="woocommerce/checkout-payment-block" class="wp-block-woocommerce-checkout-payment-block"></div>
275 <div data-block-name="woocommerce/checkout-additional-information-block" class="wp-block-woocommerce-checkout-additional-information-block"></div>' .
276 ( isset( $attributes['showOrderNotes'] ) && false === $attributes['showOrderNotes'] ? '' : '<div data-block-name="woocommerce/checkout-order-note-block" class="wp-block-woocommerce-checkout-order-note-block"></div>' ) .
277 ( isset( $attributes['showPolicyLinks'] ) && false === $attributes['showPolicyLinks'] ? '' : '<div data-block-name="woocommerce/checkout-terms-block" class="wp-block-woocommerce-checkout-terms-block"></div>' ) .
278 '<div data-block-name="woocommerce/checkout-actions-block" class="wp-block-woocommerce-checkout-actions-block"></div>
279 </div>
280 <div data-block-name="woocommerce/checkout-totals-block" class="wp-block-woocommerce-checkout-totals-block">
281 <div data-block-name="woocommerce/checkout-order-summary-block" class="wp-block-woocommerce-checkout-order-summary-block"></div>
282 </div>
283 ';
284
285 $content = str_replace( '</div>', $inner_blocks_html . '</div>', $content );
286 }
287
288 /**
289 * Checkout i3 added inner blocks for Order summary.
290 * We need to add them to Checkout i2 templates.
291 * The order needs to match the order in which these blocks were registered.
292 */
293 $order_summary_with_inner_blocks = '$0
294 <div data-block-name="woocommerce/checkout-order-summary-cart-items-block" class="wp-block-woocommerce-checkout-order-summary-cart-items-block"></div>
295 <div data-block-name="woocommerce/checkout-order-summary-subtotal-block" class="wp-block-woocommerce-checkout-order-summary-subtotal-block"></div>
296 <div data-block-name="woocommerce/checkout-order-summary-fee-block" class="wp-block-woocommerce-checkout-order-summary-fee-block"></div>
297 <div data-block-name="woocommerce/checkout-order-summary-discount-block" class="wp-block-woocommerce-checkout-order-summary-discount-block"></div>
298 <div data-block-name="woocommerce/checkout-order-summary-coupon-form-block" class="wp-block-woocommerce-checkout-order-summary-coupon-form-block"></div>
299 <div data-block-name="woocommerce/checkout-order-summary-shipping-block" class="wp-block-woocommerce-checkout-order-summary-shipping-block"></div>
300 <div data-block-name="woocommerce/checkout-order-summary-taxes-block" class="wp-block-woocommerce-checkout-order-summary-taxes-block"></div>
301 ';
302 // Order summary subtotal block was added in i3, so we search for it to see if we have a Checkout i2 template.
303 $regex_for_order_summary_subtotal = '/<div[^<]*?data-block-name="woocommerce\/checkout-order-summary-subtotal-block"[^>]*?>/mi';
304 $regex_for_order_summary = '/<div[^<]*?data-block-name="woocommerce\/checkout-order-summary-block"[^>]*?>/mi';
305 $has_i2_template = ! preg_match( $regex_for_order_summary_subtotal, $content );
306
307 if ( $has_i2_template ) {
308 $content = preg_replace( $regex_for_order_summary, $order_summary_with_inner_blocks, $content );
309 }
310
311 /**
312 * Add the Local Pickup toggle to checkouts missing this forced template.
313 */
314 $local_pickup_inner_blocks = '<div data-block-name="woocommerce/checkout-shipping-method-block" class="wp-block-woocommerce-checkout-shipping-method-block"></div>' . PHP_EOL . PHP_EOL . '<div data-block-name="woocommerce/checkout-pickup-options-block" class="wp-block-woocommerce-checkout-pickup-options-block"></div>' . PHP_EOL . PHP_EOL . '$0';
315 $has_local_pickup_regex = '/<div[^<]*?data-block-name="woocommerce\/checkout-shipping-method-block"[^>]*?>/mi';
316 $has_local_pickup = preg_match( $has_local_pickup_regex, $content );
317
318 if ( ! $has_local_pickup ) {
319 $shipping_address_block_regex = '/<div[^<]*?data-block-name="woocommerce\/checkout-shipping-address-block" class="wp-block-woocommerce-checkout-shipping-address-block"[^>]*?><\/div>/mi';
320 $content = preg_replace( $shipping_address_block_regex, $local_pickup_inner_blocks, $content );
321 }
322
323 /**
324 * Add the Additional Information block to checkouts missing it.
325 */
326 $additional_information_inner_blocks = '$0' . PHP_EOL . PHP_EOL . '<div data-block-name="woocommerce/checkout-additional-information-block" class="wp-block-woocommerce-checkout-additional-information-block"></div>' . PHP_EOL . PHP_EOL;
327 $has_additional_information_regex = '/<div[^<]*?data-block-name="woocommerce\/checkout-additional-information-block"[^>]*?>/mi';
328 $has_additional_information_block = preg_match( $has_additional_information_regex, $content );
329
330 if ( ! $has_additional_information_block ) {
331 $payment_block_regex = '/<div[^<]*?data-block-name="woocommerce\/checkout-payment-block" class="wp-block-woocommerce-checkout-payment-block"[^>]*?><\/div>/mi';
332 $content = preg_replace( $payment_block_regex, $additional_information_inner_blocks, $content );
333 }
334
335 return $content;
336 }
337
338 /**
339 * Check if we're viewing a checkout page endpoint, rather than the main checkout page itself.
340 *
341 * @return boolean
342 */
343 protected function is_checkout_endpoint() {
344 return is_wc_endpoint_url( 'order-pay' ) || is_wc_endpoint_url( 'order-received' );
345 }
346
347 /**
348 * Update the local pickup title in WooCommerce Settings when the checkout page containing a Checkout block is saved.
349 *
350 * @param int $post_id The post ID.
351 * @param \WP_Post $post The post object.
352 * @return void
353 */
354 public function update_local_pickup_title( $post_id, $post ) {
355
356 // This is not a proper save action, maybe an autosave, so don't continue.
357 if ( empty( $post->post_status ) || 'inherit' === $post->post_status ) {
358 return;
359 }
360
361 // Check if we are editing the checkout page and that it contains a Checkout block.
362 // Cast to string for Checkout page ID comparison because get_option can return it as a string, so better to compare both values as strings.
363 if ( ! empty( $post->post_type ) && 'wp_template' !== $post->post_type && ( false === has_block( 'woocommerce/checkout', $post ) || (string) get_option( 'woocommerce_checkout_page_id' ) !== (string) $post_id ) ) {
364 return;
365 }
366
367 if ( ( ! empty( $post->post_type ) && ! empty( $post->post_name ) && 'page-checkout' !== $post->post_name && 'wp_template' === $post->post_type ) || false === has_block( 'woocommerce/checkout', $post ) ) {
368 return;
369 }
370 $pickup_location_settings = LocalPickupUtils::get_local_pickup_settings( 'edit' );
371
372 if ( ! isset( $pickup_location_settings['title'] ) ) {
373 return;
374 }
375
376 if ( empty( $post->post_content ) ) {
377 return;
378 }
379
380 $title = $this->find_local_pickup_text_in_checkout_block( $post->post_content );
381
382 // Set the title to be an empty string if it isn't a string. This will make it fall back to the default value of "Pickup".
383 if ( ! is_string( $title ) ) {
384 $title = '';
385 }
386
387 $pickup_location_settings['title'] = $title;
388 update_option( 'woocommerce_pickup_location_settings', $pickup_location_settings );
389 }
390
391 /**
392 * Find the shipping methods block, then get the value of the localPickupText attribute from it.
393 *
394 * @param string $post_content The post content to search through.
395 * @return null|string The local pickup text if found, otherwise null.
396 */
397 private function find_local_pickup_text_in_checkout_block( $post_content ) {
398 $scanner = Block_Scanner::create( $post_content );
399
400 while ( $scanner->next_delimiter() ) {
401 if ( $scanner->opens_block( 'woocommerce/checkout-shipping-method-block' ) ) {
402 $attributes = $scanner->allocate_and_return_parsed_attributes();
403 if ( isset( $attributes['localPickupText'] ) ) {
404 return $attributes['localPickupText'];
405 }
406 }
407 }
408
409 return null;
410 }
411
412 /**
413 * Extra data passed through from server to client for block.
414 *
415 * @param array $attributes Any attributes that currently are available from the block.
416 * Note, this will be empty in the editor context when the block is
417 * not in the post content on editor load.
418 */
419 protected function enqueue_data( array $attributes = [] ) {
420 parent::enqueue_data( $attributes );
421
422 $country_data = CartCheckoutUtils::get_country_data();
423 $address_formats = WC()->countries->get_address_formats();
424
425 // Move the address format into the 'countryData' setting.
426 // We need to skip 'default' because that's not a valid country.
427 foreach ( $address_formats as $country_code => $format ) {
428 if ( 'default' === $country_code ) {
429 continue;
430 }
431 $country_data[ $country_code ]['format'] = $format;
432 }
433
434 $providers_payload = [];
435 if ( class_exists( AddressProviderController::class ) && 'no' !== get_option( 'woocommerce_address_autocomplete_enabled', 'no' ) ) {
436 $controller = wc_get_container()->get( AddressProviderController::class );
437 $providers = $controller->get_providers();
438 $providers_payload = array_map(
439 static function ( $provider ) {
440 return array(
441 'id' => (string) $provider->id,
442 'name' => sanitize_text_field( (string) $provider->name ),
443 'branding_html' => wp_kses_post( (string) $provider->branding_html ),
444 );
445 },
446 (array) $providers
447 );
448 }
449 $this->asset_data_registry->add( 'addressAutocompleteProviders', $providers_payload );
450 $this->asset_data_registry->add( 'countryData', $country_data );
451 $this->asset_data_registry->add( 'defaultAddressFormat', $address_formats['default'] );
452
453 // Prime caches to reduce future queries.
454 wp_prime_option_caches(
455 array(
456 'woocommerce_enable_guest_checkout',
457 'woocommerce_enable_signup_and_login_from_checkout',
458 'woocommerce_enable_checkout_login_reminder',
459 'woocommerce_tax_display_cart', // This one is autoloaded, but we add it here for clarity.
460 'woocommerce_tax_total_display',
461 'woocommerce_ship_to_destination',
462 'woocommerce_registration_generate_password',
463 'pickup_location_pickup_locations',
464 )
465 );
466
467 $this->asset_data_registry->add(
468 'checkoutAllowsGuest',
469 false === filter_var(
470 wc()->checkout()->is_registration_required(),
471 FILTER_VALIDATE_BOOLEAN
472 )
473 );
474 $this->asset_data_registry->add(
475 'checkoutAllowsSignup',
476 filter_var(
477 wc()->checkout()->is_registration_enabled(),
478 FILTER_VALIDATE_BOOLEAN
479 )
480 );
481 $this->asset_data_registry->add( 'checkoutShowLoginReminder', filter_var( get_option( 'woocommerce_enable_checkout_login_reminder' ), FILTER_VALIDATE_BOOLEAN ) );
482 $this->asset_data_registry->add( 'displayCartPricesIncludingTax', 'incl' === get_option( 'woocommerce_tax_display_cart' ) );
483 $this->asset_data_registry->add( 'displayItemizedTaxes', 'itemized' === get_option( 'woocommerce_tax_total_display' ) );
484 $this->asset_data_registry->add( 'forcedBillingAddress', 'billing_only' === get_option( 'woocommerce_ship_to_destination' ) );
485 $this->asset_data_registry->add( 'generatePassword', filter_var( get_option( 'woocommerce_registration_generate_password' ), FILTER_VALIDATE_BOOLEAN ) );
486 $this->asset_data_registry->add( 'taxesEnabled', wc_tax_enabled() );
487 $this->asset_data_registry->add( 'couponsEnabled', wc_coupons_enabled() );
488 $this->asset_data_registry->add( 'shippingEnabled', wc_shipping_enabled() );
489 $this->asset_data_registry->add( 'hasDarkEditorStyleSupport', current_theme_supports( 'dark-editor-style' ) );
490 $this->asset_data_registry->register_page_id( isset( $attributes['cartPageId'] ) ? $attributes['cartPageId'] : 0 );
491 $this->asset_data_registry->add( 'isBlockTheme', wp_is_block_theme() );
492 $this->asset_data_registry->add( 'isCheckoutBlock', true );
493
494 $pickup_location_settings = LocalPickupUtils::get_local_pickup_settings();
495 $local_pickup_method_ids = LocalPickupUtils::get_local_pickup_method_ids();
496
497 $this->asset_data_registry->add( 'localPickupEnabled', $pickup_location_settings['enabled'] );
498 $this->asset_data_registry->add( 'localPickupText', $pickup_location_settings['title'] );
499 $this->asset_data_registry->add( 'localPickupCost', $pickup_location_settings['cost'] );
500 $this->asset_data_registry->add( 'collectableMethodIds', $local_pickup_method_ids );
501 $this->asset_data_registry->add( 'shippingMethodsExist', CartCheckoutUtils::shipping_methods_exist() );
502
503 $is_block_editor = $this->is_block_editor();
504
505 if ( $is_block_editor ) {
506 $this->asset_data_registry->add(
507 'localPickupLocations',
508 array_filter(
509 array_map(
510 function ( $location ) {
511 if ( ! wc_string_to_bool( $location['enabled'] ) ) {
512 return null;
513 }
514 $location['formatted_address'] = wc()->countries->get_formatted_address( $location['address'], ', ' );
515 return $location;
516 },
517 LocalPickupUtils::get_local_pickup_method_locations()
518 )
519 ),
520 );
521 }
522
523 if ( $is_block_editor && ! $this->asset_data_registry->exists( 'globalShippingMethods' ) ) {
524 $shipping_methods = WC()->shipping()->get_shipping_methods();
525 $formatted_shipping_methods = array_reduce(
526 $shipping_methods,
527 function ( array $acc, $method ) use ( $local_pickup_method_ids ) {
528 if ( in_array( $method->id, $local_pickup_method_ids, true ) ) {
529 return $acc;
530 }
531 if ( $method->supports( 'settings' ) ) {
532 $acc[] = [
533 'id' => $method->id,
534 'title' => $method->method_title,
535 'description' => $method->method_description,
536 ];
537 }
538 return $acc;
539 },
540 []
541 );
542 $this->asset_data_registry->add( 'globalShippingMethods', $formatted_shipping_methods );
543 }
544
545 if ( $is_block_editor && ! $this->asset_data_registry->exists( 'activeShippingZones' ) && class_exists( '\WC_Shipping_Zones' ) ) {
546 $this->asset_data_registry->add( 'activeShippingZones', CartCheckoutUtils::get_shipping_zones() );
547 }
548
549 if ( $is_block_editor && ! $this->asset_data_registry->exists( 'globalPaymentMethods' ) ) {
550 // These are used to show options in the sidebar. We want to get the full list of enabled payment methods,
551 // not just the ones that are available for the current cart (which may not exist yet).
552 $payment_methods = PaymentUtils::get_enabled_payment_gateways();
553 $formatted_payment_methods = array_reduce(
554 $payment_methods,
555 function ( array $acc, $method ) {
556 $acc[] = [
557 'id' => $method->id,
558 'title' => $method->get_method_title() !== '' ? $method->get_method_title() : $method->get_title(),
559 'description' => $method->get_method_description() !== '' ? $method->get_method_description() : $method->get_description(),
560 ];
561 return $acc;
562 },
563 []
564 );
565 $this->asset_data_registry->add( 'globalPaymentMethods', $formatted_payment_methods );
566 }
567
568 // Check `current_user_can` so we can show notices about incompatible extensions in the front-end to admins too.
569 if ( ( $is_block_editor || current_user_can( 'manage_woocommerce' ) ) && ! $this->asset_data_registry->exists( 'incompatibleExtensions' ) ) {
570 if ( ! class_exists( '\Automattic\WooCommerce\Utilities\FeaturesUtil' ) || ! function_exists( 'get_plugins' ) ) {
571 return;
572 }
573
574 $declared_extensions = \Automattic\WooCommerce\Utilities\FeaturesUtil::get_compatible_plugins_for_feature( 'cart_checkout_blocks' );
575 $all_plugins = \get_plugins(); // Note that `get_compatible_plugins_for_feature` calls `get_plugins` internally, so this is already in cache.
576 $incompatible_extensions = array_reduce(
577 $declared_extensions['incompatible'],
578 function ( array $acc, $item ) use ( $all_plugins ) {
579 $plugin = $all_plugins[ $item ] ?? null;
580 $plugin_id = $plugin['TextDomain'] ?? dirname( $item );
581 $plugin_name = $plugin['Name'] ?? $plugin_id;
582 $acc[] = [
583 'id' => $plugin_id,
584 'title' => $plugin_name,
585 ];
586 return $acc;
587 },
588 []
589 );
590 $this->asset_data_registry->add( 'incompatibleExtensions', $incompatible_extensions );
591 }
592
593 if ( ! is_admin() && ! WC()->is_rest_api_request() ) {
594 $this->asset_data_registry->hydrate_api_request( '/wc/store/v1/cart' );
595 $this->asset_data_registry->hydrate_data_from_api_request( 'checkoutData', '/wc/store/v1/checkout' );
596 $this->hydrate_customer_payment_methods();
597 }
598
599 /**
600 * Fires after checkout block data is registered.
601 *
602 * @since 2.6.0
603 */
604 do_action( 'woocommerce_blocks_checkout_enqueue_data' );
605 }
606
607 /**
608 * Get saved customer payment methods for use in checkout.
609 */
610 protected function hydrate_customer_payment_methods() {
611 $payment_methods = PaymentUtils::get_saved_payment_methods();
612
613 if ( ! $payment_methods || $this->asset_data_registry->exists( 'customerPaymentMethods' ) ) {
614 return;
615 }
616
617 $this->asset_data_registry->add(
618 'customerPaymentMethods',
619 is_array( $payment_methods ) ? $payment_methods['enabled'] : null
620 );
621 }
622
623 /**
624 * Register script and style assets for the block type before it is registered.
625 *
626 * This registers the scripts; it does not enqueue them.
627 */
628 protected function register_block_type_assets() {
629 parent::register_block_type_assets();
630 $chunks = $this->get_chunks_paths( $this->chunks_folder );
631 $vendor_chunks = $this->get_chunks_paths( 'vendors--checkout-blocks' );
632 $shared_chunks = [ 'cart-blocks/cart-express-payment--checkout-blocks/express-payment-frontend' ];
633 $this->register_chunk_translations( array_merge( $chunks, $vendor_chunks, $shared_chunks ) );
634 }
635
636 /**
637 * Get list of Checkout block & its inner-block types.
638 *
639 * @return array;
640 */
641 public static function get_checkout_block_types() {
642 return [
643 'Checkout',
644 'CheckoutActionsBlock',
645 'CheckoutAdditionalInformationBlock',
646 'CheckoutBillingAddressBlock',
647 'CheckoutContactInformationBlock',
648 'CheckoutExpressPaymentBlock',
649 'CheckoutFieldsBlock',
650 'CheckoutOrderNoteBlock',
651 'CheckoutOrderSummaryBlock',
652 'CheckoutOrderSummaryCartItemsBlock',
653 'CheckoutOrderSummaryCouponFormBlock',
654 'CheckoutOrderSummaryDiscountBlock',
655 'CheckoutOrderSummaryFeeBlock',
656 'CheckoutOrderSummaryShippingBlock',
657 'CheckoutOrderSummarySubtotalBlock',
658 'CheckoutOrderSummaryTaxesBlock',
659 'CheckoutOrderSummaryTotalsBlock',
660 'CheckoutPaymentBlock',
661 'CheckoutShippingAddressBlock',
662 'CheckoutShippingMethodsBlock',
663 'CheckoutShippingMethodBlock',
664 'CheckoutPickupOptionsBlock',
665 'CheckoutTermsBlock',
666 'CheckoutTotalsBlock',
667 ];
668 }
669 }
670