PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 11.0.0-beta.1
WooCommerce v11.0.0-beta.1
11.0.0-beta.1 10.9.4 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 3 days ago OrderConfirmation 2 months ago ProductCollection 3 days ago Reviews 2 months ago AbstractBlock.php 3 days ago AbstractDynamicBlock.php 2 years ago AbstractInnerBlock.php 1 year ago AbstractProductGrid.php 3 months ago ActiveFilters.php 2 years ago AddToCartForm.php 1 month ago AddToWishlistButton.php 1 month ago AllProducts.php 3 days ago AllReviews.php 2 years ago AtomicBlock.php 2 years ago AttributeFilter.php 1 year ago Breadcrumbs.php 3 days ago Cart.php 3 days 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 1 month ago CategoryDescription.php 2 months ago CategoryTitle.php 2 months ago Checkout.php 3 days 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 3 days 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 3 days ago MiniCartCartButtonBlock.php 11 months ago MiniCartCheckoutButtonBlock.php 11 months ago MiniCartContents.php 3 months ago MiniCartFooterBlock.php 3 days ago MiniCartItemsBlock.php 11 months ago MiniCartProductsTableBlock.php 3 days 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 3 days ago ProductCategories.php 1 month ago ProductCategory.php 2 years ago ProductDescription.php 9 months ago ProductDetails.php 5 months ago ProductFilterActive.php 1 month ago ProductFilterAttribute.php 3 days ago ProductFilterCheckboxList.php 1 month ago ProductFilterChips.php 1 month ago ProductFilterClearButton.php 1 month ago ProductFilterPrice.php 1 month ago ProductFilterPriceSlider.php 1 month ago ProductFilterRating.php 1 month ago ProductFilterRemovableChips.php 1 month ago ProductFilterStatus.php 3 days ago ProductFilterTaxonomy.php 3 days ago ProductFilters.php 3 days ago ProductGallery.php 1 month ago ProductGalleryLargeImage.php 1 month ago ProductGalleryThumbnails.php 1 month ago ProductImage.php 3 days ago ProductImageGallery.php 8 months ago ProductMeta.php 1 year ago ProductNew.php 2 years ago ProductOnSale.php 2 years ago ProductPrice.php 2 months ago ProductQuery.php 3 days 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 3 days 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 1 month ago SingleProduct.php 2 months ago StockFilter.php 2 years ago StoreNotices.php 1 year ago Wishlist.php 1 month ago
Checkout.php
671 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\Enums\TaxDisplayMode;
11 use Automattic\WooCommerce\StoreApi\Utilities\PaymentUtils;
12 use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldsSchema\Validation;
13 use Automattic\WooCommerce\Internal\AddressProvider\AddressProviderController;
14
15 /**
16 * Checkout class.
17 *
18 * @internal
19 */
20 class Checkout extends AbstractBlock {
21 /**
22 * Block name.
23 *
24 * @var string
25 */
26 protected $block_name = 'checkout';
27
28 /**
29 * Chunks build folder.
30 *
31 * @var string
32 */
33 protected $chunks_folder = 'checkout-blocks';
34
35 /**
36 * Initialize this block type.
37 *
38 * - Hook into WP lifecycle.
39 * - Register the block with WordPress.
40 */
41 protected function initialize() {
42 parent::initialize();
43 add_action( 'rest_api_init', array( $this, 'register_settings' ) );
44 add_action( 'wp_loaded', array( $this, 'register_patterns' ) );
45 add_action( 'wp', array( $this, 'disable_wp_emoji' ) );
46 // This prevents the page redirecting when the cart is empty. This is so the editor still loads the page preview.
47 add_filter(
48 'woocommerce_checkout_redirect_empty_cart',
49 function ( $redirect_empty_cart ) {
50 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
51 return isset( $_GET['_wp-find-template'] ) ? false : $redirect_empty_cart;
52 }
53 );
54
55 add_action( 'save_post', array( $this, 'update_local_pickup_title' ), 10, 2 );
56 }
57
58 /**
59 * Remove WordPress emoji detection script on pages containing this block.
60 *
61 * The wp-emoji MutationObserver converts emoji text nodes to <img> elements
62 * when React hydrates or re-renders, corrupting the DOM tree and crashing the block.
63 * The wp-exclude-emoji class on the wrapper only prevents the initial parse, not the
64 * MutationObserver, so the script must be removed entirely.
65 *
66 * @since 10.8.0
67 *
68 * @return void
69 */
70 public function disable_wp_emoji() {
71 if ( has_block( $this->get_full_block_name() ) ) {
72 remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
73 remove_action( 'wp_print_styles', 'print_emoji_styles' );
74 }
75 }
76
77 /**
78 * Dequeues the scripts added by WC Core to the Checkout page.
79 *
80 * @return void
81 */
82 public function dequeue_woocommerce_core_scripts() {
83 wp_dequeue_script( 'wc-checkout' );
84 wp_dequeue_script( 'wc-address-autocomplete' );
85 wp_dequeue_style( 'wc-address-autocomplete' );
86 wp_dequeue_script( 'wc-password-strength-meter' );
87 wp_dequeue_script( 'selectWoo' );
88 wp_dequeue_style( 'select2' );
89 }
90
91 /**
92 * Exposes settings exposed by the checkout block.
93 */
94 public function register_settings() {
95 register_setting(
96 'options',
97 'woocommerce_checkout_phone_field',
98 array(
99 'type' => 'object',
100 'description' => __( 'Controls the display of the phone field in checkout.', 'woocommerce' ),
101 'label' => __( 'Phone number', 'woocommerce' ),
102 'show_in_rest' => array(
103 'name' => 'woocommerce_checkout_phone_field',
104 'schema' => array(
105 'type' => 'string',
106 'enum' => array( 'optional', 'required', 'hidden' ),
107 ),
108 ),
109 'default' => CartCheckoutUtils::get_phone_field_visibility(),
110 )
111 );
112 register_setting(
113 'options',
114 'woocommerce_checkout_company_field',
115 array(
116 'type' => 'object',
117 'description' => __( 'Controls the display of the company field in checkout.', 'woocommerce' ),
118 'label' => __( 'Company', 'woocommerce' ),
119 'show_in_rest' => array(
120 'name' => 'woocommerce_checkout_company_field',
121 'schema' => array(
122 'type' => 'string',
123 'enum' => array( 'optional', 'required', 'hidden' ),
124 ),
125 ),
126 'default' => CartCheckoutUtils::get_company_field_visibility(),
127 )
128 );
129 register_setting(
130 'options',
131 'woocommerce_checkout_address_2_field',
132 array(
133 'type' => 'object',
134 'description' => __( 'Controls the display of the apartment (address_2) field in checkout.', 'woocommerce' ),
135 'label' => __( 'Address Line 2', 'woocommerce' ),
136 'show_in_rest' => array(
137 'name' => 'woocommerce_checkout_address_2_field',
138 'schema' => array(
139 'type' => 'string',
140 'enum' => array( 'optional', 'required', 'hidden' ),
141 ),
142 ),
143 'default' => CartCheckoutUtils::get_address_2_field_visibility(),
144 )
145 );
146 }
147
148 /**
149 * Register block pattern for Empty Cart Message to make it translatable.
150 */
151 public function register_patterns() {
152 register_block_pattern(
153 'woocommerce/checkout-heading',
154 array(
155 'title' => '',
156 'inserter' => false,
157 'content' => '<!-- wp:heading {"align":"wide", "level":1} --><h1 class="wp-block-heading alignwide">' . esc_html__( 'Checkout', 'woocommerce' ) . '</h1><!-- /wp:heading -->',
158 )
159 );
160 }
161
162 /**
163 * Get the editor script handle for this block type.
164 *
165 * @param string $key Data to get, or default to everything.
166 * @return array|string;
167 */
168 protected function get_block_type_editor_script( $key = null ) {
169 $script = [
170 'handle' => 'wc-' . $this->block_name . '-block',
171 'path' => $this->asset_api->get_block_asset_build_path( $this->block_name ),
172 'dependencies' => [ 'wc-blocks' ],
173 ];
174 return $key ? $script[ $key ] : $script;
175 }
176
177 /**
178 * Get the frontend script handle for this block type.
179 *
180 * @see $this->register_block_type()
181 * @param string $key Data to get, or default to everything.
182 * @return array|string
183 */
184 protected function get_block_type_script( $key = null ) {
185 $dependencies = [];
186
187 // Load password strength meter script asynchronously if needed.
188 if ( ! is_user_logged_in() && 'no' === get_option( 'woocommerce_registration_generate_password' ) ) {
189 $dependencies[] = 'zxcvbn-async';
190 }
191
192 $checkout_fields = Package::container()->get( CheckoutFields::class );
193 // Load schema parser asynchronously if we need it.
194 if ( Validation::has_field_schema( $checkout_fields->get_additional_fields() ) ) {
195 $dependencies[] = 'wc-schema-parser';
196 }
197
198 $script = [
199 'handle' => 'wc-' . $this->block_name . '-block-frontend',
200 'path' => $this->asset_api->get_block_asset_build_path( $this->block_name . '-frontend' ),
201 'dependencies' => $dependencies,
202 ];
203 return $key ? $script[ $key ] : $script;
204 }
205
206 /**
207 * Get the frontend style handle for this block type.
208 *
209 * @return string[]
210 */
211 protected function get_block_type_style() {
212 return array_merge( parent::get_block_type_style(), [ 'wc-blocks-packages-style' ] );
213 }
214
215 /**
216 * Enqueue frontend assets for this block, just in time for rendering.
217 *
218 * @param array $attributes Any attributes that currently are available from the block.
219 * @param string $content The block content.
220 * @param WP_Block $block The block object.
221 */
222 protected function enqueue_assets( array $attributes, $content, $block ) {
223 /**
224 * Fires before checkout block scripts are enqueued.
225 *
226 * @since 4.6.0
227 */
228 do_action( 'woocommerce_blocks_enqueue_checkout_block_scripts_before' );
229 parent::enqueue_assets( $attributes, $content, $block );
230 /**
231 * Fires after checkout block scripts are enqueued.
232 *
233 * @since 4.6.0
234 */
235 do_action( 'woocommerce_blocks_enqueue_checkout_block_scripts_after' );
236 }
237
238 /**
239 * Append frontend scripts when rendering the block.
240 *
241 * @param array $attributes Block attributes.
242 * @param string $content Block content.
243 * @param WP_Block $block Block instance.
244 * @return string Rendered block type output.
245 */
246 protected function render( $attributes, $content, $block ) {
247
248 if ( $this->is_checkout_endpoint() ) {
249 // Note: Currently the block only takes care of the main checkout form -- if an endpoint is set, refer to the
250 // legacy shortcode instead and do not render block.
251 return wp_is_block_theme() ? do_shortcode( '[woocommerce_checkout]' ) : '[woocommerce_checkout]';
252 }
253
254 // Dequeue the core scripts when rendering this block.
255 add_action( 'wp_enqueue_scripts', array( $this, 'dequeue_woocommerce_core_scripts' ), 20 );
256
257 /**
258 * We need to check if $content has any templates from prior iterations of the block, in order to update to the latest iteration.
259 * We test the iteration version by searching for new blocks brought in by it.
260 * The blocks used for testing should be always available in the block (not removable by the user).
261 * Checkout i1's content was returning an empty div, with no data-block-name attribute
262 */
263 $regex_for_empty_block = '/<div class="[a-zA-Z0-9_\- ]*wp-block-woocommerce-checkout[a-zA-Z0-9_\- ]*"><\/div>/mi';
264 $has_i1_template = preg_match( $regex_for_empty_block, $content );
265
266 if ( $has_i1_template ) {
267 // This fallback needs to match the default templates defined in our Blocks.
268 $inner_blocks_html = '
269 <div data-block-name="woocommerce/checkout-fields-block" class="wp-block-woocommerce-checkout-fields-block">
270 <div data-block-name="woocommerce/checkout-express-payment-block" class="wp-block-woocommerce-checkout-express-payment-block"></div>
271 <div data-block-name="woocommerce/checkout-contact-information-block" class="wp-block-woocommerce-checkout-contact-information-block"></div>
272 <div data-block-name="woocommerce/checkout-shipping-address-block" class="wp-block-woocommerce-checkout-shipping-address-block"></div>
273 <div data-block-name="woocommerce/checkout-billing-address-block" class="wp-block-woocommerce-checkout-billing-address-block"></div>
274 <div data-block-name="woocommerce/checkout-shipping-methods-block" class="wp-block-woocommerce-checkout-shipping-methods-block"></div>
275 <div data-block-name="woocommerce/checkout-payment-block" class="wp-block-woocommerce-checkout-payment-block"></div>
276 <div data-block-name="woocommerce/checkout-additional-information-block" class="wp-block-woocommerce-checkout-additional-information-block"></div>' .
277 ( isset( $attributes['showOrderNotes'] ) && false === $attributes['showOrderNotes'] ? '' : '<div data-block-name="woocommerce/checkout-order-note-block" class="wp-block-woocommerce-checkout-order-note-block"></div>' ) .
278 ( isset( $attributes['showPolicyLinks'] ) && false === $attributes['showPolicyLinks'] ? '' : '<div data-block-name="woocommerce/checkout-terms-block" class="wp-block-woocommerce-checkout-terms-block"></div>' ) .
279 '<div data-block-name="woocommerce/checkout-actions-block" class="wp-block-woocommerce-checkout-actions-block"></div>
280 </div>
281 <div data-block-name="woocommerce/checkout-totals-block" class="wp-block-woocommerce-checkout-totals-block">
282 <div data-block-name="woocommerce/checkout-order-summary-block" class="wp-block-woocommerce-checkout-order-summary-block"></div>
283 </div>
284 ';
285
286 $content = str_replace( '</div>', $inner_blocks_html . '</div>', $content );
287 }
288
289 /**
290 * Checkout i3 added inner blocks for Order summary.
291 * We need to add them to Checkout i2 templates.
292 * The order needs to match the order in which these blocks were registered.
293 */
294 $order_summary_with_inner_blocks = '$0
295 <div data-block-name="woocommerce/checkout-order-summary-cart-items-block" class="wp-block-woocommerce-checkout-order-summary-cart-items-block"></div>
296 <div data-block-name="woocommerce/checkout-order-summary-subtotal-block" class="wp-block-woocommerce-checkout-order-summary-subtotal-block"></div>
297 <div data-block-name="woocommerce/checkout-order-summary-fee-block" class="wp-block-woocommerce-checkout-order-summary-fee-block"></div>
298 <div data-block-name="woocommerce/checkout-order-summary-discount-block" class="wp-block-woocommerce-checkout-order-summary-discount-block"></div>
299 <div data-block-name="woocommerce/checkout-order-summary-coupon-form-block" class="wp-block-woocommerce-checkout-order-summary-coupon-form-block"></div>
300 <div data-block-name="woocommerce/checkout-order-summary-shipping-block" class="wp-block-woocommerce-checkout-order-summary-shipping-block"></div>
301 <div data-block-name="woocommerce/checkout-order-summary-taxes-block" class="wp-block-woocommerce-checkout-order-summary-taxes-block"></div>
302 ';
303 // Order summary subtotal block was added in i3, so we search for it to see if we have a Checkout i2 template.
304 $regex_for_order_summary_subtotal = '/<div[^<]*?data-block-name="woocommerce\/checkout-order-summary-subtotal-block"[^>]*?>/mi';
305 $regex_for_order_summary = '/<div[^<]*?data-block-name="woocommerce\/checkout-order-summary-block"[^>]*?>/mi';
306 $has_i2_template = ! preg_match( $regex_for_order_summary_subtotal, $content );
307
308 if ( $has_i2_template ) {
309 $content = preg_replace( $regex_for_order_summary, $order_summary_with_inner_blocks, $content );
310 }
311
312 /**
313 * Add the Local Pickup toggle to checkouts missing this forced template.
314 */
315 $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';
316 $has_local_pickup_regex = '/<div[^<]*?data-block-name="woocommerce\/checkout-shipping-method-block"[^>]*?>/mi';
317 $has_local_pickup = preg_match( $has_local_pickup_regex, $content );
318
319 if ( ! $has_local_pickup ) {
320 $shipping_address_block_regex = '/<div[^<]*?data-block-name="woocommerce\/checkout-shipping-address-block" class="wp-block-woocommerce-checkout-shipping-address-block"[^>]*?><\/div>/mi';
321 $content = preg_replace( $shipping_address_block_regex, $local_pickup_inner_blocks, $content );
322 }
323
324 /**
325 * Add the Additional Information block to checkouts missing it.
326 */
327 $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;
328 $has_additional_information_regex = '/<div[^<]*?data-block-name="woocommerce\/checkout-additional-information-block"[^>]*?>/mi';
329 $has_additional_information_block = preg_match( $has_additional_information_regex, $content );
330
331 if ( ! $has_additional_information_block ) {
332 $payment_block_regex = '/<div[^<]*?data-block-name="woocommerce\/checkout-payment-block" class="wp-block-woocommerce-checkout-payment-block"[^>]*?><\/div>/mi';
333 $content = preg_replace( $payment_block_regex, $additional_information_inner_blocks, $content );
334 }
335
336 return $content;
337 }
338
339 /**
340 * Check if we're viewing a checkout page endpoint, rather than the main checkout page itself.
341 *
342 * @return boolean
343 */
344 protected function is_checkout_endpoint() {
345 return is_wc_endpoint_url( 'order-pay' ) || is_wc_endpoint_url( 'order-received' );
346 }
347
348 /**
349 * Update the local pickup title in WooCommerce Settings when the checkout page containing a Checkout block is saved.
350 *
351 * @param int $post_id The post ID.
352 * @param \WP_Post $post The post object.
353 * @return void
354 */
355 public function update_local_pickup_title( $post_id, $post ) {
356
357 // This is not a proper save action, maybe an autosave, so don't continue.
358 if ( empty( $post->post_status ) || 'inherit' === $post->post_status ) {
359 return;
360 }
361
362 // Check if we are editing the checkout page and that it contains a Checkout block.
363 // 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.
364 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 ) ) {
365 return;
366 }
367
368 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 ) ) {
369 return;
370 }
371 $pickup_location_settings = LocalPickupUtils::get_local_pickup_settings( 'edit' );
372
373 if ( ! isset( $pickup_location_settings['title'] ) ) {
374 return;
375 }
376
377 if ( empty( $post->post_content ) ) {
378 return;
379 }
380
381 $title = $this->find_local_pickup_text_in_checkout_block( $post->post_content );
382
383 // 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".
384 if ( ! is_string( $title ) ) {
385 $title = '';
386 }
387
388 $pickup_location_settings['title'] = $title;
389 update_option( 'woocommerce_pickup_location_settings', $pickup_location_settings );
390 }
391
392 /**
393 * Find the shipping methods block, then get the value of the localPickupText attribute from it.
394 *
395 * @param string $post_content The post content to search through.
396 * @return null|string The local pickup text if found, otherwise null.
397 */
398 private function find_local_pickup_text_in_checkout_block( $post_content ) {
399 $scanner = Block_Scanner::create( $post_content );
400
401 while ( $scanner->next_delimiter() ) {
402 if ( $scanner->opens_block( 'woocommerce/checkout-shipping-method-block' ) ) {
403 $attributes = $scanner->allocate_and_return_parsed_attributes();
404 if ( isset( $attributes['localPickupText'] ) ) {
405 return $attributes['localPickupText'];
406 }
407 }
408 }
409
410 return null;
411 }
412
413 /**
414 * Extra data passed through from server to client for block.
415 *
416 * @param array $attributes Any attributes that currently are available from the block.
417 * Note, this will be empty in the editor context when the block is
418 * not in the post content on editor load.
419 */
420 protected function enqueue_data( array $attributes = [] ) {
421 parent::enqueue_data( $attributes );
422
423 $country_data = CartCheckoutUtils::get_country_data();
424 $address_formats = WC()->countries->get_address_formats();
425
426 // Move the address format into the 'countryData' setting.
427 // We need to skip 'default' because that's not a valid country.
428 foreach ( $address_formats as $country_code => $format ) {
429 if ( 'default' === $country_code ) {
430 continue;
431 }
432 $country_data[ $country_code ]['format'] = $format;
433 }
434
435 $providers_payload = [];
436 if ( class_exists( AddressProviderController::class ) && 'no' !== get_option( 'woocommerce_address_autocomplete_enabled', 'no' ) ) {
437 $controller = wc_get_container()->get( AddressProviderController::class );
438 $providers = $controller->get_providers();
439 $providers_payload = array_map(
440 static function ( $provider ) {
441 return array(
442 'id' => (string) $provider->id,
443 'name' => sanitize_text_field( (string) $provider->name ),
444 'branding_html' => wp_kses_post( (string) $provider->branding_html ),
445 );
446 },
447 (array) $providers
448 );
449 }
450 $this->asset_data_registry->add( 'addressAutocompleteProviders', $providers_payload );
451 $this->asset_data_registry->add( 'countryData', $country_data );
452 $this->asset_data_registry->add( 'defaultAddressFormat', $address_formats['default'] );
453
454 // Prime caches to reduce future queries.
455 wp_prime_option_caches(
456 array(
457 'woocommerce_enable_guest_checkout',
458 'woocommerce_enable_signup_and_login_from_checkout',
459 'woocommerce_enable_checkout_login_reminder',
460 'woocommerce_tax_display_cart', // This one is autoloaded, but we add it here for clarity.
461 'woocommerce_tax_total_display',
462 'woocommerce_ship_to_destination',
463 'woocommerce_registration_generate_password',
464 'pickup_location_pickup_locations',
465 )
466 );
467
468 $this->asset_data_registry->add(
469 'checkoutAllowsGuest',
470 false === filter_var(
471 wc()->checkout()->is_registration_required(),
472 FILTER_VALIDATE_BOOLEAN
473 )
474 );
475 $this->asset_data_registry->add(
476 'checkoutAllowsSignup',
477 filter_var(
478 wc()->checkout()->is_registration_enabled(),
479 FILTER_VALIDATE_BOOLEAN
480 )
481 );
482 $this->asset_data_registry->add( 'checkoutShowLoginReminder', filter_var( get_option( 'woocommerce_enable_checkout_login_reminder' ), FILTER_VALIDATE_BOOLEAN ) );
483 $this->asset_data_registry->add( 'displayCartPricesIncludingTax', TaxDisplayMode::INCLUSIVE === get_option( 'woocommerce_tax_display_cart' ) );
484 $this->asset_data_registry->add( 'displayItemizedTaxes', 'itemized' === get_option( 'woocommerce_tax_total_display' ) );
485 $this->asset_data_registry->add( 'forcedBillingAddress', 'billing_only' === get_option( 'woocommerce_ship_to_destination' ) );
486 $this->asset_data_registry->add( 'generatePassword', filter_var( get_option( 'woocommerce_registration_generate_password' ), FILTER_VALIDATE_BOOLEAN ) );
487 $this->asset_data_registry->add( 'taxesEnabled', wc_tax_enabled() );
488 $this->asset_data_registry->add( 'couponsEnabled', wc_coupons_enabled() );
489 $this->asset_data_registry->add( 'shippingEnabled', wc_shipping_enabled() );
490 $this->asset_data_registry->add( 'hasDarkEditorStyleSupport', current_theme_supports( 'dark-editor-style' ) );
491 $this->asset_data_registry->register_page_id( isset( $attributes['cartPageId'] ) ? $attributes['cartPageId'] : 0 );
492 $this->asset_data_registry->add( 'isBlockTheme', wp_is_block_theme() );
493 $this->asset_data_registry->add( 'isCheckoutBlock', true );
494
495 $pickup_location_settings = LocalPickupUtils::get_local_pickup_settings();
496 $local_pickup_method_ids = LocalPickupUtils::get_local_pickup_method_ids();
497
498 $this->asset_data_registry->add( 'localPickupEnabled', $pickup_location_settings['enabled'] );
499 $this->asset_data_registry->add( 'localPickupText', $pickup_location_settings['title'] );
500 $this->asset_data_registry->add( 'localPickupCost', $pickup_location_settings['cost'] );
501 $this->asset_data_registry->add( 'collectableMethodIds', $local_pickup_method_ids );
502 $this->asset_data_registry->add( 'shippingMethodsExist', CartCheckoutUtils::shipping_methods_exist() );
503
504 $is_block_editor = $this->is_block_editor();
505
506 if ( $is_block_editor ) {
507 $this->asset_data_registry->add(
508 'localPickupLocations',
509 array_filter(
510 array_map(
511 function ( $location ) {
512 if ( ! wc_string_to_bool( $location['enabled'] ) ) {
513 return null;
514 }
515 $location['formatted_address'] = wc()->countries->get_formatted_address( $location['address'], ', ' );
516 return $location;
517 },
518 LocalPickupUtils::get_local_pickup_method_locations()
519 )
520 ),
521 );
522 }
523
524 if ( $is_block_editor && ! $this->asset_data_registry->exists( 'globalShippingMethods' ) ) {
525 $shipping_methods = WC()->shipping()->get_shipping_methods();
526 $formatted_shipping_methods = array_reduce(
527 $shipping_methods,
528 function ( array $acc, $method ) use ( $local_pickup_method_ids ) {
529 if ( in_array( $method->id, $local_pickup_method_ids, true ) ) {
530 return $acc;
531 }
532 if ( $method->supports( 'settings' ) ) {
533 $acc[] = [
534 'id' => $method->id,
535 'title' => $method->method_title,
536 'description' => $method->method_description,
537 ];
538 }
539 return $acc;
540 },
541 []
542 );
543 $this->asset_data_registry->add( 'globalShippingMethods', $formatted_shipping_methods );
544 }
545
546 if ( $is_block_editor && ! $this->asset_data_registry->exists( 'activeShippingZones' ) && class_exists( '\WC_Shipping_Zones' ) ) {
547 $this->asset_data_registry->add( 'activeShippingZones', CartCheckoutUtils::get_shipping_zones() );
548 }
549
550 if ( $is_block_editor && ! $this->asset_data_registry->exists( 'globalPaymentMethods' ) ) {
551 // These are used to show options in the sidebar. We want to get the full list of enabled payment methods,
552 // not just the ones that are available for the current cart (which may not exist yet).
553 $payment_methods = PaymentUtils::get_enabled_payment_gateways();
554 $formatted_payment_methods = array_reduce(
555 $payment_methods,
556 function ( array $acc, $method ) {
557 $acc[] = [
558 'id' => $method->id,
559 'title' => $method->get_method_title() !== '' ? $method->get_method_title() : $method->get_title(),
560 'description' => $method->get_method_description() !== '' ? $method->get_method_description() : $method->get_description(),
561 ];
562 return $acc;
563 },
564 []
565 );
566 $this->asset_data_registry->add( 'globalPaymentMethods', $formatted_payment_methods );
567 }
568
569 // Check `current_user_can` so we can show notices about incompatible extensions in the front-end to admins too.
570 if ( ( $is_block_editor || current_user_can( 'manage_woocommerce' ) ) && ! $this->asset_data_registry->exists( 'incompatibleExtensions' ) ) {
571 if ( ! class_exists( '\Automattic\WooCommerce\Utilities\FeaturesUtil' ) || ! function_exists( 'get_plugins' ) ) {
572 return;
573 }
574
575 $declared_extensions = \Automattic\WooCommerce\Utilities\FeaturesUtil::get_compatible_plugins_for_feature( 'cart_checkout_blocks' );
576 $all_plugins = \get_plugins(); // Note that `get_compatible_plugins_for_feature` calls `get_plugins` internally, so this is already in cache.
577 $incompatible_extensions = array_reduce(
578 $declared_extensions['incompatible'],
579 function ( array $acc, $item ) use ( $all_plugins ) {
580 $plugin = $all_plugins[ $item ] ?? null;
581 $plugin_id = $plugin['TextDomain'] ?? dirname( $item );
582 $plugin_name = $plugin['Name'] ?? $plugin_id;
583 $acc[] = [
584 'id' => $plugin_id,
585 'title' => $plugin_name,
586 ];
587 return $acc;
588 },
589 []
590 );
591 $this->asset_data_registry->add( 'incompatibleExtensions', $incompatible_extensions );
592 }
593
594 if ( ! is_admin() && ! WC()->is_rest_api_request() ) {
595 $this->asset_data_registry->hydrate_api_request( '/wc/store/v1/cart' );
596 $this->asset_data_registry->hydrate_data_from_api_request( 'checkoutData', '/wc/store/v1/checkout' );
597 $this->hydrate_customer_payment_methods();
598 }
599
600 /**
601 * Fires after checkout block data is registered.
602 *
603 * @since 2.6.0
604 */
605 do_action( 'woocommerce_blocks_checkout_enqueue_data' );
606 }
607
608 /**
609 * Get saved customer payment methods for use in checkout.
610 */
611 protected function hydrate_customer_payment_methods() {
612 $payment_methods = PaymentUtils::get_saved_payment_methods();
613
614 if ( ! $payment_methods || $this->asset_data_registry->exists( 'customerPaymentMethods' ) ) {
615 return;
616 }
617
618 $this->asset_data_registry->add(
619 'customerPaymentMethods',
620 is_array( $payment_methods ) ? $payment_methods['enabled'] : null
621 );
622 }
623
624 /**
625 * Register script and style assets for the block type before it is registered.
626 *
627 * This registers the scripts; it does not enqueue them.
628 */
629 protected function register_block_type_assets() {
630 parent::register_block_type_assets();
631 $chunks = $this->get_chunks_paths( $this->chunks_folder );
632 $vendor_chunks = $this->get_chunks_paths( 'vendors--checkout-blocks' );
633 $shared_chunks = [ 'cart-blocks/cart-express-payment--checkout-blocks/express-payment-frontend' ];
634 $this->register_chunk_translations( array_merge( $chunks, $vendor_chunks, $shared_chunks ) );
635 }
636
637 /**
638 * Get list of Checkout block & its inner-block types.
639 *
640 * @return array;
641 */
642 public static function get_checkout_block_types() {
643 return [
644 'Checkout',
645 'CheckoutActionsBlock',
646 'CheckoutAdditionalInformationBlock',
647 'CheckoutBillingAddressBlock',
648 'CheckoutContactInformationBlock',
649 'CheckoutExpressPaymentBlock',
650 'CheckoutFieldsBlock',
651 'CheckoutOrderNoteBlock',
652 'CheckoutOrderSummaryBlock',
653 'CheckoutOrderSummaryCartItemsBlock',
654 'CheckoutOrderSummaryCouponFormBlock',
655 'CheckoutOrderSummaryDiscountBlock',
656 'CheckoutOrderSummaryFeeBlock',
657 'CheckoutOrderSummaryShippingBlock',
658 'CheckoutOrderSummarySubtotalBlock',
659 'CheckoutOrderSummaryTaxesBlock',
660 'CheckoutOrderSummaryTotalsBlock',
661 'CheckoutPaymentBlock',
662 'CheckoutShippingAddressBlock',
663 'CheckoutShippingMethodsBlock',
664 'CheckoutShippingMethodBlock',
665 'CheckoutPickupOptionsBlock',
666 'CheckoutTermsBlock',
667 'CheckoutTotalsBlock',
668 ];
669 }
670 }
671