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

Introduce Additional Fields extensibility API. #12073

Open
wants to merge 46 commits into
base: trunk
Choose a base branch
from

Conversation

senadir
Copy link
Member

@senadir senadir commented Dec 6, 2023

Introduction

This PR introduces the ability to register additional fields in Checkout for developers. This is a step up from how it was done in the old Checkout, and a major improvement to how it's done currently in Checkout.

This API handles the following:

  • Rendering a field in Checkout block and other external Checkouts that use Store API, like WooPay.
  • Adds your field to the Checkout schema so it's statically validated and consumed.
  • Handles collecting data, validating it, and sending it to server, where it's sanitized and validated.
  • Persists that value to the order and customer session if applicable.
  • Return that value for future checkouts for that customer.
    To be handled in the follow up issues
  • Ability to specify where the field is going to render, Contact, Address (shipping and billing), and additional fields.
  • Show the field value in all the customer life journey, including order received page, emails, and my-account page.
  • Show the field in the admin area for order management.
  • Offer the ability to edit the field for customers and merchants.
  • Surface the field in the Woo App.
  • Support adding a Select and Checkbox inputs.
  • Ability to render a custom component to render your input, while still letting Checkout handle the rest of stuff like sending it and saving it and showing it.
    As such, this API takes off a lot of work that was being done manually and offers you seamless experience.

FAQ

- Can I change the position of my field relative to others? No, that's currently not supported but something in our roadmap.
- Can I remove/edit core fields (first name, last name...)? No, that's not part of the project, and will follow up in a future one.
- Can I add fields in the editor via UI? No, that's going to be the next project after this one, which will leverage the same APIs under the hood.
- I want to render a hidden field? That's not the goal of this project and therefore not possible, to pass values from Checkout to Store API, use setExtensionData.
- I want to render a field only in billing, but not shipping (or vice versa): Fragmenting fields between Shipping and Billing would result in a confusing customer experience, so it's not supported. If you feel strongly that your field is only applicable to one use case but not the other, consider adding it to a different location, like Contact Information step or Additional Fields step.
- I don't want my address field to be saved to the customer session: That's not possible, as fields are one of 2, they're either relevant for the customer and order (think address, contact), or only relevant of the order (think order note, or delivery instructions). Therefore, address fields are always going to be saved to the customer.

Technical implementation

Store API

Values are passed from a Checkout to Store API in some places.

  1. For address fields, values need to be passed in the billing_address and shipping_address arguments for both POST /wc/store/cart/update-customer and POST /wc/store/checkout.
  2. All /cart endpoints as well as /checkout endpoints will return saved address values in billing_address and shipping_address.
  3. Fields keys would be the ids they're registered with, so it would be a namespace/name, this ensures it never conflicts with core fields.
  4. Other additional fields (not address ones), would be passed to POST /wc/store/checkout in a additional_fields key, in which each key => value is the namespace/name => value.
  5. Given additional fields are per order things, they won't be hydrated yet, but we're looking at ways to save them during the Checkout.

Under the hood, fields are saved in customer metadata and order metadata. The keys names and where they're saved is considered implementation detail. Fields are saved under billing group, shipping group, or additional fields group. Both customer and orders get those groups.
Fetching the fields directly is discouraged as the fields name is not stable, helpers functions will be provided to fetch and set fields values programmatically.

Testing Instructions

Please consider any edge cases this change may have, and also other areas of the product this may impact.

Before testing

  1. Add this snippet to your site somewhere:
add_action(
	'woocommerce_blocks_loaded',
	function() {
		woocommerce_blocks_register_checkout_field(
			array(
				'id'             => 'plugin-namespace/vat-number',
				'label'          => __( 'VAT Number', 'woo-gutenberg-products-block' ),
				'optionalLabel'  => __( 'VAT Number (optional)', 'woo-gutenberg-products-block' ),
				'required'       => true,
				'autocomplete'   => 'vat-number',
				'autocapitalize' => 'characters',
				'location'       => 'address',
			)
		);

	}
);

Testing feature gating

  1. Change your phase to 2 (in blocks.ini) this will ensure your site is not in experimental mode.
  2. Ensure your site crashes due to an undefined function (woocommerce_blocks_register_checkout_field).
  3. Change your phase to 3 (in blocks.ini) this will ensure your site is in experimental mode.
  4. Reload and ensure your site does not crash.

Testing the schema

  1. Using a POST client, call OPTIONS /wp-json/wc/store/cart, and then OPTIONS /wp-json/wc/store/cart/update-customer, and then OPTIONS /wp-json/wc/store/checkout
  2. Under schema.properties.shipping_address.properties, you can see plugin-namespace/vat-number.
  3. Under schema.properties.billing_address.properties, you can see plugin-namespace/vat-number.
  4. Call OPTIONS /wp-json/wc/store/cart/update-customer and OPTIONS /wp-json/wc/store/checkout
  5. Under endpoints[0].args.billing_address, you can see plugin-namespace/vat-number.

Test Store API.

  1. Using a REST client, GET /wc/store/cart, get the nonce from it, add a product using POST /wc/store/cart/add-item, get the nonce and cart token from it.
  2. POST /wc/store/cart/update-customer a full shipping and billing address, without providing the custom field value and key, you should not get an error.
{
	"shipping_address": {
		"first_name": "Name",
		"last_name": "Last Name",
		"company": "",
		"address_1": "Address",
		"address_2": "",
		"city": "SF",
		"state": "CA",
		"postcode": "94000",
		"country": "US",
		"phone": "055334432"
	},
	"billing_address": {
		"first_name": "nadir",
		"last_name": "Seghir",
		"company": "",
		"address_1": "Address",
		"address_2": "",
		"city": "SF",
		"state": "CA",
		"postcode": "94000",
		"country": "US",
		"email": "[email protected]",
		"phone": "055334432"
	}
}

3 POST /wc/store/checkout with a full address and payment method, without the plugin vat

{
	"shipping_address": {
		"first_name": "Name",
		"last_name": "Last Name",
		"company": "",
		"address_1": "Address",
		"address_2": "",
		"city": "SF",
		"state": "CA",
		"postcode": "94000",
		"country": "US",
		"phone": "055334432"
	},
	"billing_address": {
		"first_name": "nadir",
		"last_name": "Seghir",
		"company": "",
		"address_1": "Address",
		"address_2": "",
		"city": "SF",
		"state": "CA",
		"postcode": "94000",
		"country": "US",
		"email": "[email protected]",
		"phone": "055334432"
	},
	"payment_method": "cod"
}
  1. You should get an error that VAT is required.
  2. Add VAT to billing and shipping.
  3. You should be able to place the order.

Testing registering fields.

  1. As a guest user add an item to your cart and open the Checkout block. By default your address will be expanded.
  2. Ensure the VAT field is there at the bottom of the form.
  3. Uncheck "Use same address for billing" and ensure the VAT field is there at the bottom of the billing form.
  4. Ensure the label you added is shown (not the optional one).

Testing field options

  1. In the snippet you added change required to false.
  2. Check the optional label is shown for the VAT (Optional) field in both the billing and shipping addresses.

Store API

  1. Using a REST client, GET /wc/store/cart, get the nonce from it, add a product using POST /wc/store/cart/add-item, get the nonce and cart token from it.
  2. POST /wc/store/checkout with a full address and payment method, without the plugin vat
{
	"shipping_address": {
		"first_name": "Name",
		"last_name": "Last Name",
		"company": "",
		"address_1": "Address",
		"address_2": "",
		"city": "SF",
		"state": "CA",
		"postcode": "94000",
		"country": "US",
		"phone": "055334432"
	},
	"billing_address": {
		"first_name": "nadir",
		"last_name": "Seghir",
		"company": "",
		"address_1": "Address",
		"address_2": "",
		"city": "SF",
		"state": "CA",
		"postcode": "94000",
		"country": "US",
		"email": "[email protected]",
		"phone": "055334432"
	},
	"payment_method": "cod"
}
  1. You should be able to place the order fine without problems.

Testing error handling and invalid configs

  1. In the snippet you added, remove id. Reload your site and expect to see an error message describing the issue. Replace id.
  2. In the snippet you added, remove label. Reload your site and expect to see an error message describing the issue. Replace label.
  3. In the snippet you added, remove location. Reload your site and expect to see an error message describing the issue. Replace location.
  4. In the snippet, change the id so that it no longer has a namespace, e.g. it will become 'id' => 'vat-number'. Reload your site and expect to see an error message describing the issue. Replace the namespace.
  5. Add the snippet again so there are two. Reload your site and expect to see an error message describing the issue. Remove the duplicate snippet.
  6. In the snippet you added, add a new entry 'hidden' => true. Reload your site and expect to see the field. Expect a PHP warning explaining the use of hidden is not supported.

Testing fields

  1. As a guest customer:
  2. Add an item to your cart and go to the Checkout block.
  3. Fill in the checkout form and add a value for your custom field.
  4. After filling the form, reload the page. Ensure the values you entered are still there.
  5. Check out and ensure your order is placed 🥳 For now, you won't be able to see those values.
  6. Add an item to your cart, navigate to the Checkout block again and ensure your information is saved, including the custom field.
  7. Repeat the steps again but as a logged-in customer and.
  8. Change the required value to true in the registration snippet.
  9. Try checking out as logged in and logged out customers without filling in the custom field.
  10. Add another custom field by copying the snippet. Change the ID and labels.
  11. Repeat these steps ensuring neither fields work, and both fields required-ness is working OK.

Testing function availability

  1. Change the snippet you added to this (note the different hook):
add_action(
	'woocommerce_loaded',
	function() {
		woocommerce_blocks_register_checkout_field(
			array(
				'id'             => 'plugin-namespace/vat-number',
				'label'          => __( 'VAT Number', 'woo-gutenberg-products-block' ),
				'optionalLabel'  => __( 'VAT Number (optional)', 'woo-gutenberg-products-block' ),
				'required'       => true,
				'autocomplete'   => 'vat-number',
				'autocapitalize' => 'characters',
				'location'       => 'address',
			)
		);

	}
);
  1. Load the Checkout block and expect your field to be there.

Testing locale customisation

  1. Add the following snippet to your site:
add_filter(
	'woocommerce_get_country_locale',
	function( $locale ) {
		$locale['DE']['plugin-namespace/vat-number']['label'] = 'my vat';
		return $locale;
	}
);
  1. Load the Checkout block and change country to Germany.
  2. Ensure your VAT field is labeled: my vat (or my-vat (Optional))
  3. Change country to USA.
  4. Ensure your VAT field is labeled VAT Number (or VAT Number (Optional) );
  • Do not include in the Testing Notes
  • Should be tested by the development team exclusively

Screenshots or screencast

image

WooCommerce Visibility

Required:

  • WooCommerce Core
  • Feature plugin
  • Experimental
  • N/A

Checklist

Required:

  • This PR has either a [type] label or a [skip-changelog] label.
  • This PR is assigned to a milestone.

Conditional:

  • This PR has a UI change and has been cross-browser tested at different viewport sizes on both the frontend and in the editor.
  • This PR has a changelog description (if [skip-changelog] label is not present).
  • This PR adds/removes a feature flag & I've updated this doc.
  • This PR adds/removes an experimental interfaces, and I've updated this doc.
  • This PR has been accessibility tested.
  • This PR has had any necessary documentation added/updated.

Copy link
Contributor

github-actions bot commented Dec 6, 2023

The release ZIP for this PR is accessible via:

https://wcblocks.wpcomstaging.com/wp-content/uploads/woocommerce-gutenberg-products-block-12073.zip

Script Dependencies Report

There is no changed script dependency between this branch and trunk.

This comment was automatically generated by the ./github/compare-assets action.

TypeScript Errors Report

  • Files with errors: 508
  • Total errors: 1879

⚠️ ⚠️ This PR introduces new TS errors on 3 files:

assets/js/base/components/cart-checkout/totals/shipping/index.tsx

assets/js/base/context/hooks/payment-methods/use-payment-method-interface.ts

assets/js/data/cart/selectors.ts

comments-aggregator

Copy link
Contributor

github-actions bot commented Dec 6, 2023

Size Change: +4.18 kB (0%)

Total Size: 1.62 MB

Filename Size Change
build/active-filters-frontend.js 6.82 kB +107 B (+2%)
build/all-products-frontend.js 9.79 kB +128 B (+1%)
build/all-products.js 39.8 kB +115 B (0%)
build/all-reviews.js 7.91 kB +113 B (+1%)
build/attribute-filter-frontend.js 20.1 kB +109 B (+1%)
build/attribute-filter.js 11.4 kB +110 B (+1%)
build/breadcrumbs.js 2.24 kB +108 B (+5%) 🔍
build/cart-blocks/cart-express-payment-frontend.js 5.48 kB +100 B (+2%)
build/cart-blocks/cart-order-summary-frontend.js 20.6 kB -22 B (0%)
build/cart-blocks/order-summary-coupon-form-frontend.js 20.9 kB -22 B (0%)
build/cart-blocks/order-summary-discount-frontend.js 21 kB -22 B (0%)
build/cart-blocks/order-summary-shipping-frontend.js 20.6 kB -22 B (0%)
build/cart-frontend.js 29.3 kB +198 B (+1%)
build/cart.js 40 kB +151 B (0%)
build/checkout-blocks/billing-address-frontend.js 9.84 kB -19 B (0%)
build/checkout-blocks/contact-information-frontend.js 1.66 kB -2 B (0%)
build/checkout-blocks/express-payment-frontend.js 5.92 kB +108 B (+2%)
build/checkout-blocks/order-summary-coupon-form-frontend.js 21 kB -21 B (0%)
build/checkout-blocks/order-summary-discount-frontend.js 21 kB -26 B (0%)
build/checkout-blocks/order-summary-frontend.js 20.6 kB -23 B (0%)
build/checkout-blocks/order-summary-shipping-frontend.js 20.6 kB -24 B (0%)
build/checkout-blocks/payment-frontend.js 14.6 kB +86 B (+1%)
build/checkout-blocks/shipping-address-frontend.js 9.76 kB -26 B (0%)
build/checkout-blocks/shipping-methods-frontend.js 19 kB -2 B (0%)
build/checkout-frontend.js 30.9 kB +200 B (+1%)
build/checkout.js 42.7 kB +171 B (0%)
build/collection-attribute-filter.js 7.75 kB +4 B (0%)
build/collection-filters.js 2.09 kB +114 B (+6%) 🔍
build/collection-stock-filter.js 4.29 kB +113 B (+3%)
build/featured-category.js 13.9 kB +110 B (+1%)
build/featured-product.js 14 kB +107 B (+1%)
build/filter-wrapper-frontend.js 14.7 kB +110 B (+1%)
build/handpicked-products.js 7.45 kB +113 B (+2%)
build/legacy-template.js 7.96 kB +109 B (+1%)
build/mini-cart-component-frontend.js 30.9 kB +104 B (0%)
build/mini-cart-contents.js 16.1 kB +96 B (+1%)
build/mini-cart.js 6.21 kB +108 B (+2%)
build/page-content-wrapper.js 2.08 kB +112 B (+6%) 🔍
build/price-filter-frontend.js 8.05 kB +110 B (+1%)
build/price-filter.js 7.64 kB +112 B (+1%)
build/product-add-to-cart-frontend.js 8.11 kB -7 B (0%)
build/product-add-to-cart.js 8.36 kB -6 B (0%)
build/product-best-sellers.js 7.14 kB +4 B (0%)
build/product-button-frontend.js 4.93 kB -16 B (0%)
build/product-button.js 4.64 kB -17 B (0%)
build/product-category.js 8.07 kB +6 B (0%)
build/product-collection.js 13.9 kB +98 B (+1%)
build/product-gallery-large-image-next-previous.js 4.38 kB +115 B (+3%)
build/product-gallery-large-image.js 2.58 kB +110 B (+4%)
build/product-gallery-pager.js 3.6 kB +117 B (+3%)
build/product-gallery-thumbnails.js 4.09 kB +112 B (+3%)
build/product-gallery.js 9.78 kB +112 B (+1%)
build/product-new.js 8.01 kB +4 B (0%)
build/product-on-sale.js 7.39 kB +3 B (0%)
build/product-query.js 11.8 kB +108 B (+1%)
build/product-tag.js 7.53 kB +3 B (0%)
build/product-top-rated.js 7.67 kB +3 B (0%)
build/products-by-attribute.js 8.06 kB +2 B (0%)
build/rating-filter-frontend.js 18.9 kB +113 B (+1%)
build/reviews-by-category.js 11.7 kB +118 B (+1%)
build/reviews-by-product.js 12.8 kB +119 B (+1%)
build/reviews-frontend.js 6.55 kB +111 B (+2%)
build/single-product.js 11.2 kB +125 B (+1%)
build/stock-filter-frontend.js 19.1 kB +102 B (+1%)
build/wc-blocks-data.js 19.7 kB +41 B (0%)
build/wc-settings.js 2.02 kB -399 B (-16%) 👏
build/wc-shipping-method-pickup-location.js 29.5 kB +101 B (0%)
ℹ️ View Unchanged
Filename Size
build/3810-frontend.js 18.3 kB
build/4124-frontend.js 23.9 kB
build/8280-frontend.js 8.47 kB
build/active-filters-rtl.css 1.68 kB
build/active-filters-wrapper-frontend.js 6.91 kB
build/active-filters-wrapper-rtl.css 1.53 kB
build/active-filters-wrapper.css 1.53 kB
build/active-filters.css 1.68 kB
build/active-filters.js 6.06 kB
build/add-to-cart-form-rtl.css 443 B
build/add-to-cart-form.css 443 B
build/all-products-rtl.css 4.54 kB
build/all-products.css 4.54 kB
build/all-reviews-rtl.css 1.75 kB
build/all-reviews.css 1.75 kB
build/attribute-filter-rtl.css 4.03 kB
build/attribute-filter-wrapper-frontend.js 21.1 kB
build/attribute-filter-wrapper-rtl.css 3.89 kB
build/attribute-filter-wrapper.css 3.88 kB
build/attribute-filter.css 4.01 kB
build/blocks-checkout.js 33.7 kB
build/blocks-components.js 32.6 kB
build/breadcrumbs-rtl.css 234 B
build/breadcrumbs.css 234 B
build/cart-blocks/cart-accepted-payment-methods-frontend.js 1.4 kB
build/cart-blocks/cart-accepted-payment-methods-style.js 153 B
build/cart-blocks/cart-cross-sells-frontend.js 267 B
build/cart-blocks/cart-cross-sells-products-frontend.js 5.57 kB
build/cart-blocks/cart-cross-sells-products-style.js 153 B
build/cart-blocks/cart-cross-sells-style.js 269 B
build/cart-blocks/cart-express-payment-style.js 155 B
build/cart-blocks/cart-items-frontend.js 281 B
build/cart-blocks/cart-items-style.js 240 B
build/cart-blocks/cart-line-items-frontend.js 9.24 kB
build/cart-blocks/cart-line-items-style.js 153 B
build/cart-blocks/cart-order-summary-style.js 339 B
build/cart-blocks/cart-totals-frontend.js 296 B
build/cart-blocks/cart-totals-style.js 253 B
build/cart-blocks/empty-cart-frontend.js 376 B
build/cart-blocks/empty-cart-style.js 375 B
build/cart-blocks/filled-cart-frontend.js 614 B
build/cart-blocks/filled-cart-style.js 332 B
build/cart-blocks/order-summary-coupon-form-style.js 155 B
build/cart-blocks/order-summary-discount-style.js 155 B
build/cart-blocks/order-summary-fee-frontend.js 288 B
build/cart-blocks/order-summary-fee-style.js 153 B
build/cart-blocks/order-summary-heading-frontend.js 347 B
build/cart-blocks/order-summary-heading-style.js 351 B
build/cart-blocks/order-summary-shipping-style.js 154 B
build/cart-blocks/order-summary-subtotal-frontend.js 291 B
build/cart-blocks/order-summary-subtotal-style.js 154 B
build/cart-blocks/order-summary-taxes-frontend.js 454 B
build/cart-blocks/order-summary-taxes-style.js 202 B
build/cart-blocks/proceed-to-checkout-frontend.js 7.64 kB
build/cart-blocks/proceed-to-checkout-style.js 1.09 kB
build/cart-rtl.css 9.22 kB
build/cart.css 9.21 kB
build/catalog-sorting-rtl.css 259 B
build/catalog-sorting.css 259 B
build/catalog-sorting.js 1.7 kB
build/checkout-blocks/actions-frontend.js 8.14 kB
build/checkout-blocks/actions-style.js 1.02 kB
build/checkout-blocks/billing-address-style.js 574 B
build/checkout-blocks/contact-information-style.js 653 B
build/checkout-blocks/fields-frontend.js 375 B
build/checkout-blocks/fields-style.js 342 B
build/checkout-blocks/order-note-frontend.js 673 B
build/checkout-blocks/order-summary-cart-items-frontend.js 6.49 kB
build/checkout-blocks/order-summary-cart-items-style.js 153 B
build/checkout-blocks/order-summary-coupon-form-style.js 155 B
build/checkout-blocks/order-summary-discount-style.js 154 B
build/checkout-blocks/order-summary-fee-frontend.js 291 B
build/checkout-blocks/order-summary-fee-style.js 155 B
build/checkout-blocks/order-summary-shipping-style.js 154 B
build/checkout-blocks/order-summary-style.js 341 B
build/checkout-blocks/order-summary-subtotal-frontend.js 289 B
build/checkout-blocks/order-summary-subtotal-style.js 155 B
build/checkout-blocks/order-summary-taxes-frontend.js 455 B
build/checkout-blocks/order-summary-taxes-style.js 201 B
build/checkout-blocks/payment-style.js 500 B
build/checkout-blocks/pickup-options-frontend.js 11.2 kB
build/checkout-blocks/pickup-options-style.js 481 B
build/checkout-blocks/shipping-address-style.js 517 B
build/checkout-blocks/shipping-method-frontend.js 1.97 kB
build/checkout-blocks/shipping-method-style.js 1.44 kB
build/checkout-blocks/shipping-methods-style.js 456 B
build/checkout-blocks/terms-frontend.js 1.56 kB
build/checkout-blocks/terms-style.js 1.03 kB
build/checkout-blocks/totals-frontend.js 338 B
build/checkout-blocks/totals-style.js 301 B
build/checkout-rtl.css 8.34 kB
build/checkout.css 8.33 kB
build/classic-shortcode-rtl.css 242 B
build/classic-shortcode.css 241 B
build/classic-shortcode.js 4.66 kB
build/collection-attribute-filter-frontend.js 494 B
build/collection-attribute-filter-rtl.css 3.5 kB
build/collection-attribute-filter.css 3.5 kB
build/collection-price-filter-frontend.js 615 B
build/collection-price-filter-rtl.css 1.07 kB
build/collection-price-filter.css 1.07 kB
build/collection-price-filter.js 3.27 kB
build/collection-stock-filter-frontend.js 396 B
build/collection-stock-filter-rtl.css 4.05 kB
build/collection-stock-filter.css 4.04 kB
build/customer-account-rtl.css 410 B
build/customer-account.css 409 B
build/customer-account.js 3.19 kB
build/featured-category-rtl.css 979 B
build/featured-category.css 978 B
build/featured-product-rtl.css 1.03 kB
build/featured-product.css 1.03 kB
build/filter-wrapper-rtl.css 378 B
build/filter-wrapper.css 378 B
build/filter-wrapper.js 2.38 kB
build/legacy-template-rtl.css 240 B
build/legacy-template.css 240 B
build/mini-cart-contents-block/cart-button-frontend.js 1.86 kB
build/mini-cart-contents-block/cart-button-style.js 1.23 kB
build/mini-cart-contents-block/checkout-button-frontend.js 1.95 kB
build/mini-cart-contents-block/checkout-button-style.js 1.44 kB
build/mini-cart-contents-block/empty-cart-frontend.js 383 B
build/mini-cart-contents-block/empty-cart-style.js 387 B
build/mini-cart-contents-block/filled-cart-frontend.js 284 B
build/mini-cart-contents-block/filled-cart-style.js 287 B
build/mini-cart-contents-block/footer-frontend.js 3.87 kB
build/mini-cart-contents-block/footer-style.js 1.96 kB
build/mini-cart-contents-block/items-frontend.js 246 B
build/mini-cart-contents-block/items-style.js 250 B
build/mini-cart-contents-block/products-table-frontend.js 8.59 kB
build/mini-cart-contents-block/shopping-button-frontend.js 501 B
build/mini-cart-contents-block/shopping-button-style.js 361 B
build/mini-cart-contents-block/title-frontend.js 2.04 kB
build/mini-cart-contents-block/title-items-counter-frontend.js 1.74 kB
build/mini-cart-contents-block/title-items-counter-style.js 1.2 kB
build/mini-cart-contents-block/title-label-frontend.js 1.68 kB
build/mini-cart-contents-block/title-label-style.js 1.14 kB
build/mini-cart-contents-block/title-style.js 1.38 kB
build/mini-cart-contents-rtl.css 3.23 kB
build/mini-cart-contents.css 3.22 kB
build/mini-cart-frontend.js 2.35 kB
build/mini-cart-rtl.css 2.44 kB
build/mini-cart.css 2.44 kB
build/order-confirmation-additional-information-rtl.css 366 B
build/order-confirmation-additional-information.css 366 B
build/order-confirmation-additional-information.js 1.58 kB
build/order-confirmation-billing-address-rtl.css 396 B
build/order-confirmation-billing-address.css 396 B
build/order-confirmation-billing-address.js 1.56 kB
build/order-confirmation-billing-wrapper.js 1.51 kB
build/order-confirmation-downloads-rtl.css 476 B
build/order-confirmation-downloads-wrapper.js 1.58 kB
build/order-confirmation-downloads.css 477 B
build/order-confirmation-downloads.js 1.91 kB
build/order-confirmation-shipping-address-rtl.css 452 B
build/order-confirmation-shipping-address.css 452 B
build/order-confirmation-shipping-address.js 1.56 kB
build/order-confirmation-shipping-wrapper.js 1.52 kB
build/order-confirmation-status-rtl.css 280 B
build/order-confirmation-status.css 280 B
build/order-confirmation-status.js 1.55 kB
build/order-confirmation-summary-rtl.css 460 B
build/order-confirmation-summary.css 460 B
build/order-confirmation-summary.js 1.76 kB
build/order-confirmation-totals-rtl.css 586 B
build/order-confirmation-totals-wrapper.js 1.8 kB
build/order-confirmation-totals.css 585 B
build/order-confirmation-totals.js 2.18 kB
build/packages-style-rtl.css 5.19 kB
build/packages-style.css 5.19 kB
build/price-filter-rtl.css 2.68 kB
build/price-filter-wrapper-frontend.js 8.11 kB
build/price-filter-wrapper-rtl.css 2.53 kB
build/price-filter-wrapper.css 2.53 kB
build/price-filter.css 2.67 kB
build/price-format.js 913 B
build/product-add-to-cart-rtl.css 1.37 kB
build/product-add-to-cart.css 1.38 kB
build/product-average-rating-frontend.js 1.88 kB
build/product-average-rating.js 1.4 kB
build/product-button-interactivity-frontend.js 8.29 kB
build/product-button-rtl.css 1.14 kB
build/product-button.css 1.14 kB
build/product-categories-rtl.css 654 B
build/product-categories.css 654 B
build/product-categories.js 2.6 kB
build/product-collection-no-results.js 1.66 kB
build/product-details-rtl.css 397 B
build/product-details.css 394 B
build/product-gallery-frontend.js 778 B
build/product-gallery-large-image-frontend.js 604 B
build/product-gallery-rtl.css 1.65 kB
build/product-gallery.css 1.65 kB
build/product-image-frontend.js 2.9 kB
build/product-image-gallery-rtl.css 307 B
build/product-image-gallery.css 306 B
build/product-image-rtl.css 996 B
build/product-image.css 994 B
build/product-image.js 2.58 kB
build/product-price-frontend.js 2.82 kB
build/product-price-rtl.css 644 B
build/product-price.css 643 B
build/product-price.js 2.34 kB
build/product-query-rtl.css 350 B
build/product-query.css 349 B
build/product-rating-counter-frontend.js 2.19 kB
build/product-rating-counter.js 1.7 kB
build/product-rating-frontend.js 2.53 kB
build/product-rating-rtl.css 247 B
build/product-rating-stars-frontend.js 2.43 kB
build/product-rating-stars-rtl.css 899 B
build/product-rating-stars.css 900 B
build/product-rating-stars.js 1.95 kB
build/product-rating.css 246 B
build/product-rating.js 2.04 kB
build/product-results-count-rtl.css 230 B
build/product-results-count.css 230 B
build/product-results-count.js 1.66 kB
build/product-reviews-rtl.css 458 B
build/product-reviews.css 458 B
build/product-sale-badge-frontend.js 2.01 kB
build/product-sale-badge-rtl.css 437 B
build/product-sale-badge.css 437 B
build/product-sale-badge.js 1.52 kB
build/product-search-rtl.css 419 B
build/product-search.css 417 B
build/product-search.js 2.62 kB
build/product-sku-frontend.js 2.02 kB
build/product-sku-rtl.css 240 B
build/product-sku.css 239 B
build/product-sku.js 1.53 kB
build/product-stock-indicator-frontend.js 2.2 kB
build/product-stock-indicator-rtl.css 232 B
build/product-stock-indicator.css 232 B
build/product-stock-indicator.js 1.71 kB
build/product-summary-frontend.js 2.36 kB
build/product-summary-rtl.css 549 B
build/product-summary.css 549 B
build/product-summary.js 1.88 kB
build/product-template-rtl.css 548 B
build/product-template.css 547 B
build/product-template.js 2.81 kB
build/product-title-frontend.js 2.31 kB
build/product-title-rtl.css 693 B
build/product-title.css 694 B
build/product-title.js 2.05 kB
build/rating-filter-rtl.css 4.09 kB
build/rating-filter-wrapper-frontend.js 19.7 kB
build/rating-filter-wrapper-rtl.css 3.95 kB
build/rating-filter-wrapper.css 3.95 kB
build/rating-filter.css 4.08 kB
build/rating-filter.js 5.8 kB
build/reviews-by-category-rtl.css 1.75 kB
build/reviews-by-category.css 1.75 kB
build/reviews-by-product-rtl.css 1.75 kB
build/reviews-by-product.css 1.75 kB
build/single-product-rtl.css 378 B
build/single-product.css 378 B
build/stock-filter-rtl.css 3.88 kB
build/stock-filter-wrapper-frontend.js 20 kB
build/stock-filter-wrapper-rtl.css 3.75 kB
build/stock-filter-wrapper.css 3.74 kB
build/stock-filter.css 3.87 kB
build/stock-filter.js 6.44 kB
build/store-notices-rtl.css 1.31 kB
build/store-notices.css 1.3 kB
build/store-notices.js 2.34 kB
build/wc-blocks-classic-template-revert-button-style-rtl.css 240 B
build/wc-blocks-classic-template-revert-button-style.css 239 B
build/wc-blocks-classic-template-revert-button.js 1.19 kB
build/wc-blocks-editor-style-rtl.css 7.29 kB
build/wc-blocks-editor-style.css 7.29 kB
build/wc-blocks-google-analytics.js 1.13 kB
build/wc-blocks-middleware.js 735 B
build/wc-blocks-registry.js 2.75 kB
build/wc-blocks-rtl.css 2.48 kB
build/wc-blocks-shared-context.js 860 B
build/wc-blocks-shared-hocs.js 1.41 kB
build/wc-blocks-vendors.js 61.9 kB
build/wc-blocks.css 2.48 kB
build/wc-blocks.js 9.19 kB
build/wc-interactivity-dropdown.js 493 B
build/wc-interactivity.js 12.7 kB
build/wc-payment-method-bacs.js 405 B
build/wc-payment-method-cheque.js 402 B
build/wc-payment-method-cod.js 508 B
build/wc-payment-method-paypal.js 439 B

compressed-size-action

);
} )
.concat( removedKeys )
.concat( addedKeys );
Copy link
Member

Choose a reason for hiding this comment

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

Can you add an inline comment explaining why this is needed?

Copy link
Member Author

Choose a reason for hiding this comment

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

cc @opr as I'm also not sure what this mean, but it helped get additional fields picked up and pushed.

src/Domain/Bootstrap.php Outdated Show resolved Hide resolved
*
* @var string
*/
const BILLING_FIELDS_KEY = '_additional_billing_fields';
Copy link
Member

Choose a reason for hiding this comment

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

As discussed, noting we could investigate using individual meta keys/values for new fields to avoid serialisation. So the data is queryable and searchable.

src/Domain/Services/CheckoutFields.php Show resolved Hide resolved
src/StoreApi/Routes/V1/CartUpdateCustomer.php Outdated Show resolved Hide resolved
src/StoreApi/Schemas/V1/AbstractAddressSchema.php Outdated Show resolved Hide resolved
} elseif ( 'postcode' === $key ) {
$carry[ $key ] = $address['postcode'] ? wc_format_postcode( sanitize_text_field( wp_unslash( $address['postcode'] ) ), $address['country'] ) : '';
} else {
$carry[ $key ] = sanitize_text_field( wp_unslash( $address[ $key ] ) );
Copy link
Member

Choose a reason for hiding this comment

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

Can additional fields consumers change this?

Copy link
Member Author

Choose a reason for hiding this comment

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

Currently no, do you see a good use case for that?

Copy link
Member

Choose a reason for hiding this comment

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

If something is defining a custom property in schema, it would make sense they can handle sanitisation but I'm not 100% sure.

@@ -274,16 +296,16 @@ protected function validate_email( \WC_Order $order ) {
protected function validate_addresses( \WC_Order $order ) {
$errors = new \WP_Error();
$needs_shipping = wc()->cart->needs_shipping();
$billing_address = $order->get_address( 'billing' );
Copy link
Member

Choose a reason for hiding this comment

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

We should make sure this wasn't in place for a reason.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it was only for ergonomics, we don't change billing_address or shipping_address values at all during the function call.

Copy link
Member

Choose a reason for hiding this comment

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

One is filtered. e.g. woocommerce_get_order_address so this might be breaking in ways I am unsure of.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm still not sure I see your point here.

Because we need $order in validate_address_fields. Previously it was only getting the address, right now, we pass the order and pull from the inside, but in both cases we're using get_address

Copy link
Member

Choose a reason for hiding this comment

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

My point is $order->get_address( 'billing' ) is ran through different filters to $order->get_billing_country(). It probably doesn't matter, it just struck me as odd we'd use $order->get_address here instead of the dedicated function unless there was a reason.


$customer_fields = $this->additional_fields_controller->filter_fields_for_customer( $order_fields );
foreach ( $customer_fields as $key => $value ) {
$this->additional_fields_controller->persist_field_for_customer( $key, $value, $customer );
Copy link
Member

Choose a reason for hiding this comment

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

Does this persist or just set? Because there is a $customer->save(); below.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point, I only set, we don't save.

Well, currently we also persist to customer due to a bug, but it should be set.

Copy link
Member

Choose a reason for hiding this comment

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

Perhaps change method name to reflect this then.

/**
* Checkout address form.
*/
const AddressForm = ( {
id = '',
fields = defaultFields,
Copy link
Member Author

Choose a reason for hiding this comment

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

Passing the whole fields as default no longer make sense, fields is now required.

);
} )
.concat( removedKeys )
.concat( addedKeys );
Copy link
Member Author

Choose a reason for hiding this comment

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

cc @opr as I'm also not sure what this mean, but it helped get additional fields picked up and pushed.

* Default field properties.
*/
export const defaultFields: AddressFields =
getSetting< AddressFields >( 'defaultFields' );
Copy link
Member Author

Choose a reason for hiding this comment

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

Previously, there was a list of hardcoded fields here, that moved to CheckoutFields and it will include other fields with it.

@@ -13,7 +13,7 @@
(see https://github.com/woocommerce/woocommerce-blocks/blob/trunk/.github/release-initial-checklist.md#initial-preparation)
-->
<config name="minimum_supported_wp_version" value="6.3" />
<config name="testVersion" value="7.3-" />
<config name="testVersion" value="7.4-" />
Copy link
Member Author

Choose a reason for hiding this comment

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

This was needed because I was using class type hinting.

src/StoreApi/Schemas/V1/AbstractAddressSchema.php Outdated Show resolved Hide resolved
@@ -90,18 +93,24 @@ public function get_properties() {
*/
public function sanitize_callback( $address, $request, $param ) {
Copy link
Member Author

Choose a reason for hiding this comment

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

We sanitize all incoming fields, include additional ones. Currently they're treated as text, in the future we would include things like select and checkboxes.

Comment on lines +178 to +206
protected function get_additional_address_fields_schema() {
$additional_fields_keys = $this->additional_fields_controller->get_address_fields_keys();

$fields = array_merge( $this->additional_fields_controller->get_core_fields(), $this->additional_fields_controller->get_additional_fields() );

$address_fields = array_filter(
$fields,
function( $key ) use ( $additional_fields_keys ) {
return in_array( $key, $additional_fields_keys, true );
},
ARRAY_FILTER_USE_KEY
);

$schema = [];
foreach ( $address_fields as $key => $field ) {
$schema[ $key ] = [
'description' => $field['label'],
'type' => 'string',
'context' => [ 'view', 'edit' ],
'required' => true,
];
}
return $schema;
}
Copy link
Member Author

Choose a reason for hiding this comment

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

We need to add those fields to the schema so they're accepted and validated.

@@ -205,6 +211,7 @@ protected function get_checkout_response( \WC_Order $order, PaymentResult $payme
'payment_details' => $this->prepare_payment_details_for_response( $payment_result->payment_details ),
'redirect_url' => $payment_result->redirect_url,
],
'additional_fields' => $this->get_additional_fields_response( $order ),
Copy link
Member Author

Choose a reason for hiding this comment

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

this key would hold all keys not in the address.

Comment on lines +395 to +404

$fields = $this->additional_fields_controller->get_additional_fields();
$address_fields_keys = $this->additional_fields_controller->get_address_fields_keys();
$address_fields = array_filter(
$fields,
function( $key ) use ( $address_fields_keys ) {
return in_array( $key, $address_fields_keys, true );
},
ARRAY_FILTER_USE_KEY
);
Copy link
Member Author

Choose a reason for hiding this comment

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

We also validate fields and key sure required fields are set, we return a set of errors alongside other missing fields.

senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 12, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 12, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 13, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 13, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 13, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 14, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 14, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 14, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 14, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 15, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 15, 2023
* Introduce Additional Fields API for Checkout Block woocommerce/woocommerce-blocks#12073

* add changelog

* Auto load the Blocks/Domain/Services/functions.php file

* add changelog

* revert test to what it was

* Update text domain for translations

* Ensure address data is added on the cart block too

* fix lint problem

---------

Co-authored-by: Thomas Roberts <[email protected]>
opr pushed a commit to woocommerce/woocommerce that referenced this pull request Dec 15, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 15, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 15, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 15, 2023
@mikejolley mikejolley removed their request for review December 15, 2023 15:47
opr pushed a commit to woocommerce/woocommerce that referenced this pull request Dec 15, 2023
opr pushed a commit to woocommerce/woocommerce that referenced this pull request Dec 15, 2023
opr pushed a commit to woocommerce/woocommerce that referenced this pull request Dec 15, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 18, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 18, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 18, 2023
senadir added a commit to woocommerce/woocommerce that referenced this pull request Dec 18, 2023
* Introduce Additional Fields API for Checkout Block woocommerce/woocommerce-blocks#12073

* revert test to what it was

* Default to text, if the type supplied is not supported throw an error

* Add type for options

* Return null if somehow the select made it through without options

* Make select fields type enum and add options to schema

* Lint fixes

* Update plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/address-form/address-form.tsx

Co-authored-by: Niels Lange <[email protected]>

* Update plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFields.php

Co-authored-by: Niels Lange <[email protected]>

* Update checks to log errors and fail gracefully

* Add field id to class names

* Fix lint error

* Fix short array use

* Introduce Additional Fields API for Checkout Block woocommerce/woocommerce-blocks#12073

* Default to text, if the type supplied is not supported throw an error

* Lint fixes

* Introduce Additional Fields API for Checkout Block woocommerce/woocommerce-blocks#12073

* add support for registering checkboxes

* remove extra error log

* add styling

* fix rebase conflit

* fix rebase conflit 2

* fix linter errors

* address review comments

* add warning for checkbox

* fix changes

---------

Co-authored-by: Thomas Roberts <[email protected]>
Co-authored-by: Thomas Roberts <[email protected]>
Co-authored-by: Niels Lange <[email protected]>
Copy link
Contributor

This PR has been marked as stale because it has not seen any activity within the past 7 days. Our team uses this tool to help surface pull requests that have slipped through review.

If deemed still relevant, the pr can be kept active by ensuring it's up to date with the main branch and removing the stale label.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
block: checkout Issues related to the checkout block. category: extensibility Work involving adding or updating extensibility. Useful to combine with other scopes impacted. focus: rest api Work impacting REST api routes. status: stale Stale issues and PRs have had no updates for 60 days. type: enhancement The issue is a request for an enhancement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants