PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 11.1.0-beta.2
WooCommerce v11.1.0-beta.2
11.1.0 11.1.0-rc.2 11.1.0-rc.1 11.1.0-beta.2 11.1.0-beta.1 11.0.1 11.0.0 11.0.0-rc.3 11.0.0-rc.2 11.0.0-rc.1 11.0.0-beta.2 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 2 weeks ago OrderConfirmation 2 weeks ago ProductCollection 2 weeks ago Reviews 2 weeks ago AbstractBlock.php 2 weeks ago AbstractDynamicBlock.php 2 years ago AbstractInnerBlock.php 1 year ago AbstractProductGrid.php 5 months ago ActiveFilters.php 2 years ago AddToCartForm.php 2 weeks ago AddToWishlistButton.php 2 months ago AllProducts.php 1 month ago AllReviews.php 2 years ago AtomicBlock.php 2 years ago AttributeFilter.php 1 year ago Breadcrumbs.php 1 month ago Cart.php 2 weeks 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 3 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 2 months ago CategoryDescription.php 3 months ago CategoryTitle.php 3 months ago Checkout.php 2 weeks ago CheckoutActionsBlock.php 1 year ago CheckoutAdditionalInformationBlock.php 2 years ago CheckoutBillingAddressBlock.php 2 years ago CheckoutContactInformationBlock.php 2 years ago CheckoutExpressPaymentBlock.php 10 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 6 months ago ComingSoon.php 1 year ago CouponCode.php 2 weeks ago CustomerAccount.php 2 weeks ago Dropdown.php 1 month ago EmailContent.php 2 weeks ago EmptyCartBlock.php 2 years ago EmptyMiniCartContentsBlock.php 2 weeks ago EnableBlockJsonAssetsTrait.php 1 year ago FeaturedCategory.php 2 weeks ago FeaturedItem.php 2 weeks ago FeaturedProduct.php 2 weeks ago FilledCartBlock.php 2 years ago FilledMiniCartContentsBlock.php 2 weeks ago FilterWrapper.php 2 years ago HandpickedProducts.php 1 year ago MiniCart.php 2 weeks ago MiniCartCartButtonBlock.php 2 weeks ago MiniCartCheckoutButtonBlock.php 2 weeks ago MiniCartContents.php 2 weeks ago MiniCartFooterBlock.php 2 weeks ago MiniCartItemsBlock.php 2 weeks ago MiniCartProductsTableBlock.php 2 weeks ago MiniCartShoppingButtonBlock.php 2 weeks ago MiniCartTitleBlock.php 2 weeks ago MiniCartTitleItemsCounterBlock.php 2 weeks ago MiniCartTitleLabelBlock.php 2 weeks ago NextPreviousButtons.php 7 months ago PageContentWrapper.php 2 years ago PaymentMethodIcons.php 1 year ago PriceFilter.php 1 year ago ProceedToCheckoutBlock.php 2 years ago ProductAverageRating.php 1 year ago ProductBestSellers.php 2 years ago ProductButton.php 2 weeks ago ProductCategories.php 2 months ago ProductCategory.php 2 years ago ProductDescription.php 10 months ago ProductDetails.php 7 months ago ProductFilterActive.php 2 months ago ProductFilterAttribute.php 1 month ago ProductFilterCheckboxList.php 2 months ago ProductFilterChips.php 2 months ago ProductFilterClearButton.php 2 months ago ProductFilterPrice.php 2 months ago ProductFilterPriceSlider.php 2 months ago ProductFilterRating.php 2 months ago ProductFilterRemovableChips.php 2 months ago ProductFilterStatus.php 1 month ago ProductFilterTaxonomy.php 1 month ago ProductFilters.php 1 month ago ProductGallery.php 2 weeks ago ProductGalleryLargeImage.php 2 weeks ago ProductGalleryThumbnails.php 2 weeks ago ProductImage.php 2 weeks ago ProductImageGallery.php 9 months ago ProductMeta.php 2 years ago ProductNew.php 2 years ago ProductOnSale.php 2 years ago ProductPrice.php 2 weeks ago ProductQuery.php 1 month ago ProductRating.php 1 year ago ProductRatingCounter.php 1 year ago ProductRatingStars.php 1 year ago ProductResultsCount.php 3 months ago ProductSKU.php 3 months ago ProductSaleBadge.php 1 year ago ProductSearch.php 1 year ago ProductSpecifications.php 3 months ago ProductStockIndicator.php 3 months ago ProductSummary.php 3 weeks ago ProductTag.php 2 years ago ProductTemplate.php 1 month ago ProductTitle.php 1 year ago ProductTopRated.php 2 years ago ProductsByAttribute.php 2 years ago RatingFilter.php 2 years ago RelatedProducts.php 5 months ago ReviewsByCategory.php 2 years ago ReviewsByProduct.php 2 years ago SavedForLater.php 2 months ago SingleProduct.php 2 weeks ago StockFilter.php 2 weeks ago StoreNotices.php 1 year ago Wishlist.php 2 months ago
Checkout.php
656 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 frontend script handle for this block type.
164 *
165 * @see $this->register_block_type()
166 * @param string $key Data to get, or default to everything.
167 * @return array|string
168 */
169 protected function get_block_type_script( $key = null ) {
170 $dependencies = [];
171
172 // Load password strength meter script asynchronously if needed.
173 if ( ! is_user_logged_in() && 'no' === get_option( 'woocommerce_registration_generate_password' ) ) {
174 $dependencies[] = 'zxcvbn-async';
175 }
176
177 $checkout_fields = Package::container()->get( CheckoutFields::class );
178 // Load schema parser asynchronously if we need it.
179 if ( Validation::has_field_schema( $checkout_fields->get_additional_fields() ) ) {
180 $dependencies[] = 'wc-schema-parser';
181 }
182
183 $script = [
184 'handle' => 'wc-' . $this->block_name . '-block-frontend',
185 'path' => $this->asset_api->get_block_asset_build_path( $this->block_name . '-frontend' ),
186 'dependencies' => $dependencies,
187 ];
188 return $key ? $script[ $key ] : $script;
189 }
190
191 /**
192 * Get the frontend style handle for this block type.
193 *
194 * @return string[]
195 */
196 protected function get_block_type_style() {
197 return array_merge( parent::get_block_type_style(), [ 'wc-blocks-packages-style' ] );
198 }
199
200 /**
201 * Enqueue frontend assets for this block, just in time for rendering.
202 *
203 * @param array $attributes Any attributes that currently are available from the block.
204 * @param string $content The block content.
205 * @param WP_Block $block The block object.
206 */
207 protected function enqueue_assets( array $attributes, $content, $block ) {
208 /**
209 * Fires before checkout block scripts are enqueued.
210 *
211 * @since 4.6.0
212 */
213 do_action( 'woocommerce_blocks_enqueue_checkout_block_scripts_before' );
214 parent::enqueue_assets( $attributes, $content, $block );
215 /**
216 * Fires after checkout block scripts are enqueued.
217 *
218 * @since 4.6.0
219 */
220 do_action( 'woocommerce_blocks_enqueue_checkout_block_scripts_after' );
221 }
222
223 /**
224 * Append frontend scripts when rendering the block.
225 *
226 * @param array $attributes Block attributes.
227 * @param string $content Block content.
228 * @param WP_Block $block Block instance.
229 * @return string Rendered block type output.
230 */
231 protected function render( $attributes, $content, $block ) {
232
233 if ( $this->is_checkout_endpoint() ) {
234 // Note: Currently the block only takes care of the main checkout form -- if an endpoint is set, refer to the
235 // legacy shortcode instead and do not render block.
236 return wp_is_block_theme() ? do_shortcode( '[woocommerce_checkout]' ) : '[woocommerce_checkout]';
237 }
238
239 // Dequeue the core scripts when rendering this block.
240 add_action( 'wp_enqueue_scripts', array( $this, 'dequeue_woocommerce_core_scripts' ), 20 );
241
242 /**
243 * We need to check if $content has any templates from prior iterations of the block, in order to update to the latest iteration.
244 * We test the iteration version by searching for new blocks brought in by it.
245 * The blocks used for testing should be always available in the block (not removable by the user).
246 * Checkout i1's content was returning an empty div, with no data-block-name attribute
247 */
248 $regex_for_empty_block = '/<div class="[a-zA-Z0-9_\- ]*wp-block-woocommerce-checkout[a-zA-Z0-9_\- ]*"><\/div>/mi';
249 $has_i1_template = preg_match( $regex_for_empty_block, $content );
250
251 if ( $has_i1_template ) {
252 // This fallback needs to match the default templates defined in our Blocks.
253 $inner_blocks_html = '
254 <div data-block-name="woocommerce/checkout-fields-block" class="wp-block-woocommerce-checkout-fields-block">
255 <div data-block-name="woocommerce/checkout-express-payment-block" class="wp-block-woocommerce-checkout-express-payment-block"></div>
256 <div data-block-name="woocommerce/checkout-contact-information-block" class="wp-block-woocommerce-checkout-contact-information-block"></div>
257 <div data-block-name="woocommerce/checkout-shipping-address-block" class="wp-block-woocommerce-checkout-shipping-address-block"></div>
258 <div data-block-name="woocommerce/checkout-billing-address-block" class="wp-block-woocommerce-checkout-billing-address-block"></div>
259 <div data-block-name="woocommerce/checkout-shipping-methods-block" class="wp-block-woocommerce-checkout-shipping-methods-block"></div>
260 <div data-block-name="woocommerce/checkout-payment-block" class="wp-block-woocommerce-checkout-payment-block"></div>
261 <div data-block-name="woocommerce/checkout-additional-information-block" class="wp-block-woocommerce-checkout-additional-information-block"></div>' .
262 ( isset( $attributes['showOrderNotes'] ) && false === $attributes['showOrderNotes'] ? '' : '<div data-block-name="woocommerce/checkout-order-note-block" class="wp-block-woocommerce-checkout-order-note-block"></div>' ) .
263 ( isset( $attributes['showPolicyLinks'] ) && false === $attributes['showPolicyLinks'] ? '' : '<div data-block-name="woocommerce/checkout-terms-block" class="wp-block-woocommerce-checkout-terms-block"></div>' ) .
264 '<div data-block-name="woocommerce/checkout-actions-block" class="wp-block-woocommerce-checkout-actions-block"></div>
265 </div>
266 <div data-block-name="woocommerce/checkout-totals-block" class="wp-block-woocommerce-checkout-totals-block">
267 <div data-block-name="woocommerce/checkout-order-summary-block" class="wp-block-woocommerce-checkout-order-summary-block"></div>
268 </div>
269 ';
270
271 $content = str_replace( '</div>', $inner_blocks_html . '</div>', $content );
272 }
273
274 /**
275 * Checkout i3 added inner blocks for Order summary.
276 * We need to add them to Checkout i2 templates.
277 * The order needs to match the order in which these blocks were registered.
278 */
279 $order_summary_with_inner_blocks = '$0
280 <div data-block-name="woocommerce/checkout-order-summary-cart-items-block" class="wp-block-woocommerce-checkout-order-summary-cart-items-block"></div>
281 <div data-block-name="woocommerce/checkout-order-summary-subtotal-block" class="wp-block-woocommerce-checkout-order-summary-subtotal-block"></div>
282 <div data-block-name="woocommerce/checkout-order-summary-fee-block" class="wp-block-woocommerce-checkout-order-summary-fee-block"></div>
283 <div data-block-name="woocommerce/checkout-order-summary-discount-block" class="wp-block-woocommerce-checkout-order-summary-discount-block"></div>
284 <div data-block-name="woocommerce/checkout-order-summary-coupon-form-block" class="wp-block-woocommerce-checkout-order-summary-coupon-form-block"></div>
285 <div data-block-name="woocommerce/checkout-order-summary-shipping-block" class="wp-block-woocommerce-checkout-order-summary-shipping-block"></div>
286 <div data-block-name="woocommerce/checkout-order-summary-taxes-block" class="wp-block-woocommerce-checkout-order-summary-taxes-block"></div>
287 ';
288 // Order summary subtotal block was added in i3, so we search for it to see if we have a Checkout i2 template.
289 $regex_for_order_summary_subtotal = '/<div[^<]*?data-block-name="woocommerce\/checkout-order-summary-subtotal-block"[^>]*?>/mi';
290 $regex_for_order_summary = '/<div[^<]*?data-block-name="woocommerce\/checkout-order-summary-block"[^>]*?>/mi';
291 $has_i2_template = ! preg_match( $regex_for_order_summary_subtotal, $content );
292
293 if ( $has_i2_template ) {
294 $content = preg_replace( $regex_for_order_summary, $order_summary_with_inner_blocks, $content );
295 }
296
297 /**
298 * Add the Local Pickup toggle to checkouts missing this forced template.
299 */
300 $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';
301 $has_local_pickup_regex = '/<div[^<]*?data-block-name="woocommerce\/checkout-shipping-method-block"[^>]*?>/mi';
302 $has_local_pickup = preg_match( $has_local_pickup_regex, $content );
303
304 if ( ! $has_local_pickup ) {
305 $shipping_address_block_regex = '/<div[^<]*?data-block-name="woocommerce\/checkout-shipping-address-block" class="wp-block-woocommerce-checkout-shipping-address-block"[^>]*?><\/div>/mi';
306 $content = preg_replace( $shipping_address_block_regex, $local_pickup_inner_blocks, $content );
307 }
308
309 /**
310 * Add the Additional Information block to checkouts missing it.
311 */
312 $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;
313 $has_additional_information_regex = '/<div[^<]*?data-block-name="woocommerce\/checkout-additional-information-block"[^>]*?>/mi';
314 $has_additional_information_block = preg_match( $has_additional_information_regex, $content );
315
316 if ( ! $has_additional_information_block ) {
317 $payment_block_regex = '/<div[^<]*?data-block-name="woocommerce\/checkout-payment-block" class="wp-block-woocommerce-checkout-payment-block"[^>]*?><\/div>/mi';
318 $content = preg_replace( $payment_block_regex, $additional_information_inner_blocks, $content );
319 }
320
321 return $content;
322 }
323
324 /**
325 * Check if we're viewing a checkout page endpoint, rather than the main checkout page itself.
326 *
327 * @return boolean
328 */
329 protected function is_checkout_endpoint() {
330 return is_wc_endpoint_url( 'order-pay' ) || is_wc_endpoint_url( 'order-received' );
331 }
332
333 /**
334 * Update the local pickup title in WooCommerce Settings when the checkout page containing a Checkout block is saved.
335 *
336 * @param int $post_id The post ID.
337 * @param \WP_Post $post The post object.
338 * @return void
339 */
340 public function update_local_pickup_title( $post_id, $post ) {
341
342 // This is not a proper save action, maybe an autosave, so don't continue.
343 if ( empty( $post->post_status ) || 'inherit' === $post->post_status ) {
344 return;
345 }
346
347 // Check if we are editing the checkout page and that it contains a Checkout block.
348 // 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.
349 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 ) ) {
350 return;
351 }
352
353 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 ) ) {
354 return;
355 }
356 $pickup_location_settings = LocalPickupUtils::get_local_pickup_settings( 'edit' );
357
358 if ( ! isset( $pickup_location_settings['title'] ) ) {
359 return;
360 }
361
362 if ( empty( $post->post_content ) ) {
363 return;
364 }
365
366 $title = $this->find_local_pickup_text_in_checkout_block( $post->post_content );
367
368 // 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".
369 if ( ! is_string( $title ) ) {
370 $title = '';
371 }
372
373 $pickup_location_settings['title'] = $title;
374 update_option( 'woocommerce_pickup_location_settings', $pickup_location_settings );
375 }
376
377 /**
378 * Find the shipping methods block, then get the value of the localPickupText attribute from it.
379 *
380 * @param string $post_content The post content to search through.
381 * @return null|string The local pickup text if found, otherwise null.
382 */
383 private function find_local_pickup_text_in_checkout_block( $post_content ) {
384 $scanner = Block_Scanner::create( $post_content );
385
386 while ( $scanner->next_delimiter() ) {
387 if ( $scanner->opens_block( 'woocommerce/checkout-shipping-method-block' ) ) {
388 $attributes = $scanner->allocate_and_return_parsed_attributes();
389 if ( isset( $attributes['localPickupText'] ) ) {
390 return $attributes['localPickupText'];
391 }
392 }
393 }
394
395 return null;
396 }
397
398 /**
399 * Extra data passed through from server to client for block.
400 *
401 * @param array $attributes Any attributes that currently are available from the block.
402 * Note, this will be empty in the editor context when the block is
403 * not in the post content on editor load.
404 */
405 protected function enqueue_data( array $attributes = [] ) {
406 parent::enqueue_data( $attributes );
407
408 $country_data = CartCheckoutUtils::get_country_data();
409 $address_formats = WC()->countries->get_address_formats();
410
411 // Move the address format into the 'countryData' setting.
412 // We need to skip 'default' because that's not a valid country.
413 foreach ( $address_formats as $country_code => $format ) {
414 if ( 'default' === $country_code ) {
415 continue;
416 }
417 $country_data[ $country_code ]['format'] = $format;
418 }
419
420 $providers_payload = [];
421 if ( class_exists( AddressProviderController::class ) && 'no' !== get_option( 'woocommerce_address_autocomplete_enabled', 'no' ) ) {
422 $controller = wc_get_container()->get( AddressProviderController::class );
423 $providers = $controller->get_providers();
424 $providers_payload = array_map(
425 static function ( $provider ) {
426 return array(
427 'id' => (string) $provider->id,
428 'name' => sanitize_text_field( (string) $provider->name ),
429 'branding_html' => wp_kses_post( (string) $provider->branding_html ),
430 );
431 },
432 (array) $providers
433 );
434 }
435 $this->asset_data_registry->add( 'addressAutocompleteProviders', $providers_payload );
436 $this->asset_data_registry->add( 'countryData', $country_data );
437 $this->asset_data_registry->add( 'defaultAddressFormat', $address_formats['default'] );
438
439 // Prime caches to reduce future queries.
440 wp_prime_option_caches(
441 array(
442 'woocommerce_enable_guest_checkout',
443 'woocommerce_enable_signup_and_login_from_checkout',
444 'woocommerce_enable_checkout_login_reminder',
445 'woocommerce_tax_display_cart', // This one is autoloaded, but we add it here for clarity.
446 'woocommerce_tax_total_display',
447 'woocommerce_ship_to_destination',
448 'woocommerce_registration_generate_password',
449 'pickup_location_pickup_locations',
450 )
451 );
452
453 $this->asset_data_registry->add(
454 'checkoutAllowsGuest',
455 false === filter_var(
456 wc()->checkout()->is_registration_required(),
457 FILTER_VALIDATE_BOOLEAN
458 )
459 );
460 $this->asset_data_registry->add(
461 'checkoutAllowsSignup',
462 filter_var(
463 wc()->checkout()->is_registration_enabled(),
464 FILTER_VALIDATE_BOOLEAN
465 )
466 );
467 $this->asset_data_registry->add( 'checkoutShowLoginReminder', filter_var( get_option( 'woocommerce_enable_checkout_login_reminder' ), FILTER_VALIDATE_BOOLEAN ) );
468 $this->asset_data_registry->add( 'displayCartPricesIncludingTax', TaxDisplayMode::INCLUSIVE === get_option( 'woocommerce_tax_display_cart' ) );
469 $this->asset_data_registry->add( 'displayItemizedTaxes', 'itemized' === get_option( 'woocommerce_tax_total_display' ) );
470 $this->asset_data_registry->add( 'forcedBillingAddress', 'billing_only' === get_option( 'woocommerce_ship_to_destination' ) );
471 $this->asset_data_registry->add( 'generatePassword', filter_var( get_option( 'woocommerce_registration_generate_password' ), FILTER_VALIDATE_BOOLEAN ) );
472 $this->asset_data_registry->add( 'taxesEnabled', wc_tax_enabled() );
473 $this->asset_data_registry->add( 'couponsEnabled', wc_coupons_enabled() );
474 $this->asset_data_registry->add( 'shippingEnabled', wc_shipping_enabled() );
475 $this->asset_data_registry->add( 'hasDarkEditorStyleSupport', current_theme_supports( 'dark-editor-style' ) );
476 $this->asset_data_registry->register_page_id( isset( $attributes['cartPageId'] ) ? $attributes['cartPageId'] : 0 );
477 $this->asset_data_registry->add( 'isBlockTheme', wp_is_block_theme() );
478 $this->asset_data_registry->add( 'isCheckoutBlock', true );
479
480 $pickup_location_settings = LocalPickupUtils::get_local_pickup_settings();
481 $local_pickup_method_ids = LocalPickupUtils::get_local_pickup_method_ids();
482
483 $this->asset_data_registry->add( 'localPickupEnabled', $pickup_location_settings['enabled'] );
484 $this->asset_data_registry->add( 'localPickupText', $pickup_location_settings['title'] );
485 $this->asset_data_registry->add( 'localPickupCost', $pickup_location_settings['cost'] );
486 $this->asset_data_registry->add( 'collectableMethodIds', $local_pickup_method_ids );
487 $this->asset_data_registry->add( 'shippingMethodsExist', CartCheckoutUtils::shipping_methods_exist() );
488
489 $is_block_editor = $this->is_block_editor();
490
491 if ( $is_block_editor ) {
492 $this->asset_data_registry->add(
493 'localPickupLocations',
494 array_filter(
495 array_map(
496 function ( $location ) {
497 if ( ! wc_string_to_bool( $location['enabled'] ) ) {
498 return null;
499 }
500 $location['formatted_address'] = wc()->countries->get_formatted_address( $location['address'], ', ' );
501 return $location;
502 },
503 LocalPickupUtils::get_local_pickup_method_locations()
504 )
505 ),
506 );
507 }
508
509 if ( $is_block_editor && ! $this->asset_data_registry->exists( 'globalShippingMethods' ) ) {
510 $shipping_methods = WC()->shipping()->get_shipping_methods();
511 $formatted_shipping_methods = array_reduce(
512 $shipping_methods,
513 function ( array $acc, $method ) use ( $local_pickup_method_ids ) {
514 if ( in_array( $method->id, $local_pickup_method_ids, true ) ) {
515 return $acc;
516 }
517 if ( $method->supports( 'settings' ) ) {
518 $acc[] = [
519 'id' => $method->id,
520 'title' => $method->method_title,
521 'description' => $method->method_description,
522 ];
523 }
524 return $acc;
525 },
526 []
527 );
528 $this->asset_data_registry->add( 'globalShippingMethods', $formatted_shipping_methods );
529 }
530
531 if ( $is_block_editor && ! $this->asset_data_registry->exists( 'activeShippingZones' ) && class_exists( '\WC_Shipping_Zones' ) ) {
532 $this->asset_data_registry->add( 'activeShippingZones', CartCheckoutUtils::get_shipping_zones() );
533 }
534
535 if ( $is_block_editor && ! $this->asset_data_registry->exists( 'globalPaymentMethods' ) ) {
536 // These are used to show options in the sidebar. We want to get the full list of enabled payment methods,
537 // not just the ones that are available for the current cart (which may not exist yet).
538 $payment_methods = PaymentUtils::get_enabled_payment_gateways();
539 $formatted_payment_methods = array_reduce(
540 $payment_methods,
541 function ( array $acc, $method ) {
542 $acc[] = [
543 'id' => $method->id,
544 'title' => $method->get_method_title() !== '' ? $method->get_method_title() : $method->get_title(),
545 'description' => $method->get_method_description() !== '' ? $method->get_method_description() : $method->get_description(),
546 ];
547 return $acc;
548 },
549 []
550 );
551 $this->asset_data_registry->add( 'globalPaymentMethods', $formatted_payment_methods );
552 }
553
554 // Check `current_user_can` so we can show notices about incompatible extensions in the front-end to admins too.
555 if ( ( $is_block_editor || current_user_can( 'manage_woocommerce' ) ) && ! $this->asset_data_registry->exists( 'incompatibleExtensions' ) ) {
556 if ( ! class_exists( '\Automattic\WooCommerce\Utilities\FeaturesUtil' ) || ! function_exists( 'get_plugins' ) ) {
557 return;
558 }
559
560 $declared_extensions = \Automattic\WooCommerce\Utilities\FeaturesUtil::get_compatible_plugins_for_feature( 'cart_checkout_blocks' );
561 $all_plugins = \get_plugins(); // Note that `get_compatible_plugins_for_feature` calls `get_plugins` internally, so this is already in cache.
562 $incompatible_extensions = array_reduce(
563 $declared_extensions['incompatible'],
564 function ( array $acc, $item ) use ( $all_plugins ) {
565 $plugin = $all_plugins[ $item ] ?? null;
566 $plugin_id = $plugin['TextDomain'] ?? dirname( $item );
567 $plugin_name = $plugin['Name'] ?? $plugin_id;
568 $acc[] = [
569 'id' => $plugin_id,
570 'title' => $plugin_name,
571 ];
572 return $acc;
573 },
574 []
575 );
576 $this->asset_data_registry->add( 'incompatibleExtensions', $incompatible_extensions );
577 }
578
579 if ( ! is_admin() && ! WC()->is_rest_api_request() ) {
580 $this->asset_data_registry->hydrate_api_request( '/wc/store/v1/cart' );
581 $this->asset_data_registry->hydrate_data_from_api_request( 'checkoutData', '/wc/store/v1/checkout' );
582 $this->hydrate_customer_payment_methods();
583 }
584
585 /**
586 * Fires after checkout block data is registered.
587 *
588 * @since 2.6.0
589 */
590 do_action( 'woocommerce_blocks_checkout_enqueue_data' );
591 }
592
593 /**
594 * Get saved customer payment methods for use in checkout.
595 */
596 protected function hydrate_customer_payment_methods() {
597 $payment_methods = PaymentUtils::get_saved_payment_methods();
598
599 if ( ! $payment_methods || $this->asset_data_registry->exists( 'customerPaymentMethods' ) ) {
600 return;
601 }
602
603 $this->asset_data_registry->add(
604 'customerPaymentMethods',
605 is_array( $payment_methods ) ? $payment_methods['enabled'] : null
606 );
607 }
608
609 /**
610 * Register script and style assets for the block type before it is registered.
611 *
612 * This registers the scripts; it does not enqueue them.
613 */
614 protected function register_block_type_assets() {
615 parent::register_block_type_assets();
616 $chunks = $this->get_chunks_paths( $this->chunks_folder );
617 $vendor_chunks = $this->get_chunks_paths( 'vendors--checkout-blocks' );
618 $shared_chunks = [ 'cart-blocks/cart-express-payment--checkout-blocks/express-payment-frontend' ];
619 $this->register_chunk_translations( array_merge( $chunks, $vendor_chunks, $shared_chunks ) );
620 }
621
622 /**
623 * Get list of Checkout block & its inner-block types.
624 *
625 * @return array;
626 */
627 public static function get_checkout_block_types() {
628 return [
629 'Checkout',
630 'CheckoutActionsBlock',
631 'CheckoutAdditionalInformationBlock',
632 'CheckoutBillingAddressBlock',
633 'CheckoutContactInformationBlock',
634 'CheckoutExpressPaymentBlock',
635 'CheckoutFieldsBlock',
636 'CheckoutOrderNoteBlock',
637 'CheckoutOrderSummaryBlock',
638 'CheckoutOrderSummaryCartItemsBlock',
639 'CheckoutOrderSummaryCouponFormBlock',
640 'CheckoutOrderSummaryDiscountBlock',
641 'CheckoutOrderSummaryFeeBlock',
642 'CheckoutOrderSummaryShippingBlock',
643 'CheckoutOrderSummarySubtotalBlock',
644 'CheckoutOrderSummaryTaxesBlock',
645 'CheckoutOrderSummaryTotalsBlock',
646 'CheckoutPaymentBlock',
647 'CheckoutShippingAddressBlock',
648 'CheckoutShippingMethodsBlock',
649 'CheckoutShippingMethodBlock',
650 'CheckoutPickupOptionsBlock',
651 'CheckoutTermsBlock',
652 'CheckoutTotalsBlock',
653 ];
654 }
655 }
656