Add hooks when reading and writing additional fields (#46870)
* add new filters for reading and writing fields * rename functions * add test for action * Add changefile(s) from automation for the following project(s): woocommerce-blocks, woocommerce * update docs * fix typo in test and linting issues --------- Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
parent
738bbb0078
commit
2054353f91
|
@ -22,16 +22,19 @@
|
|||
- [The select input when focused](#the-select-input-when-focused)
|
||||
- [Validation and sanitization](#validation-and-sanitization)
|
||||
- [Sanitization](#sanitization)
|
||||
- [Using the `woocommerce_blocks_sanitize_additional_field` filter](#using-the-woocommerce_blocks_sanitize_additional_field-filter)
|
||||
- [Using the `woocommerce_sanitize_additional_field` filter](#using-the-woocommerce_sanitize_additional_field-filter)
|
||||
- [Example of sanitization](#example-of-sanitization)
|
||||
- [Validation](#validation)
|
||||
- [Single field validation](#single-field-validation)
|
||||
- [Using the `woocommerce_blocks_validate_additional_field` action](#using-the-woocommerce_blocks_validate_additional_field-action)
|
||||
- [Using the `woocommerce_validate_additional_field` action](#using-the-woocommerce_validate_additional_field-action)
|
||||
- [The `WP_Error` object](#the-wp_error-object)
|
||||
- [Example of single-field validation](#example-of-single-field-validation)
|
||||
- [Multiple field validation](#multiple-field-validation)
|
||||
- [Using the `woocommerce_blocks_validate_location_{location}_fields` action](#using-the-woocommerce_blocks_validate_location_location_fields-action)
|
||||
- [Example of location validation](#example-of-location-validation)
|
||||
- [Backward compatibility](#backward-compatibility)
|
||||
- [React to to saving fields](#react-to-to-saving-fields)
|
||||
- [React to reading fields](#react-to-reading-fields)
|
||||
- [A full example](#a-full-example)
|
||||
|
||||
A common use-case for developers and merchants is to add a new field to the Checkout form to collect additional data about a customer or their order.
|
||||
|
@ -223,7 +226,7 @@ There are plans to expand this list, but for now these are the types available.
|
|||
|
||||
## Using the API
|
||||
|
||||
To register additional checkout fields you must use the `woocommerce_blocks_register_checkout_field` function.
|
||||
To register additional checkout fields you must use the `woocommerce_register_additional_checkout_field` function.
|
||||
|
||||
It is recommended to run this function after the `woocommerce_blocks_loaded` action.
|
||||
|
||||
|
@ -338,7 +341,7 @@ This example demonstrates rendering a text field in the address section:
|
|||
add_action(
|
||||
'woocommerce_blocks_loaded',
|
||||
function() {
|
||||
woocommerce_blocks_register_checkout_field(
|
||||
woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => 'namespace/gov-id',
|
||||
'label' => 'Government ID',
|
||||
|
@ -381,7 +384,7 @@ This example demonstrates rendering a checkbox field in the contact information
|
|||
add_action(
|
||||
'woocommerce_blocks_loaded',
|
||||
function() {
|
||||
woocommerce_blocks_register_checkout_field(
|
||||
woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => 'namespace/marketing-opt-in',
|
||||
'label' => 'Do you want to subscribe to our newsletter?',
|
||||
|
@ -407,7 +410,7 @@ This example demonstrates rendering a select field in the order information sect
|
|||
add_action(
|
||||
'woocommerce_blocks_loaded',
|
||||
function() {
|
||||
woocommerce_blocks_register_checkout_field(
|
||||
woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => 'namespace/how-did-you-hear-about-us',
|
||||
'label' => 'How did you hear about us?',
|
||||
|
@ -462,9 +465,9 @@ These actions happen in two places:
|
|||
|
||||
Sanitization is used to ensure the value of a field is in a specific format. An example is when taking a government ID, you may want to format it so that all letters are capitalized and there are no spaces. At this point, the value should **not** be checked for _validity_. That will come later. This step is only intended to set the field up for validation.
|
||||
|
||||
#### Using the `woocommerce_blocks_sanitize_additional_field` filter
|
||||
#### Using the `woocommerce_sanitize_additional_field` filter
|
||||
|
||||
To run a custom sanitization function for a field you can use the `sanitize_callback` function on registration, or the `woocommerce_blocks_sanitize_additional_field` filter.
|
||||
To run a custom sanitization function for a field you can use the `sanitize_callback` function on registration, or the `woocommerce_sanitize_additional_field` filter.
|
||||
|
||||
| Argument | Type | Description |
|
||||
|--------------|-------------------|-------------------------------------------------------------------------|
|
||||
|
@ -477,7 +480,7 @@ This example shows how to remove whitespace and capitalize all letters in the ex
|
|||
|
||||
```php
|
||||
add_action(
|
||||
'woocommerce_blocks_sanitize_additional_field',
|
||||
'woocommerce_sanitize_additional_field',
|
||||
function ( $field_value, $field_key ) {
|
||||
if ( 'namespace/gov-id' === $field_key ) {
|
||||
$field_value = str_replace( ' ', '', $field_key );
|
||||
|
@ -496,9 +499,9 @@ There are two phases of validation in the additional checkout fields system. The
|
|||
|
||||
#### Single field validation
|
||||
|
||||
##### Using the `woocommerce_blocks_validate_additional_field` action
|
||||
##### Using the `woocommerce_validate_additional_field` action
|
||||
|
||||
When the `woocommerce_blocks_validate_additional_field` action is fired the callback receives the field's key, the field's value, and a `WP_Error` object.
|
||||
When the `woocommerce_validate_additional_field` action is fired the callback receives the field's key, the field's value, and a `WP_Error` object.
|
||||
|
||||
To add validation errors to the response, use the [`WP_Error::add`](https://developer.wordpress.org/reference/classes/wp_error/add/) method.
|
||||
|
||||
|
@ -518,7 +521,7 @@ The below example shows how to apply custom validation to the `namespace/gov-id`
|
|||
|
||||
```php
|
||||
add_action(
|
||||
'woocommerce_blocks_validate_additional_field',
|
||||
'woocommerce_validate_additional_field',
|
||||
function ( WP_Error $errors, $field_key, $field_value ) {
|
||||
if ( 'namespace/gov-id' === $field_key ) {
|
||||
$match = preg_match( '/[A-Z0-9]{5}/', $field_value );
|
||||
|
@ -538,7 +541,7 @@ If no validation errors are encountered the function can just return void.
|
|||
|
||||
#### Multiple field validation
|
||||
|
||||
There are cases where the validity of a field depends on the value of another field, for example validating the format of a government ID based on what country the shopper is in. In this case, validating only single fields (as above) is not sufficient as the country may be unknown during the `woocommerce_blocks_validate_additional_field` action.
|
||||
There are cases where the validity of a field depends on the value of another field, for example validating the format of a government ID based on what country the shopper is in. In this case, validating only single fields (as above) is not sufficient as the country may be unknown during the `woocommerce_validate_additional_field` action.
|
||||
|
||||
To solve this, it is possible to validate a field in the context of the location it renders in. The other fields in that location will be passed to this action.
|
||||
|
||||
|
@ -588,6 +591,89 @@ add_action(
|
|||
|
||||
If these fields were rendered in the "contact" location instead, the code would be the same except the hook used would be: `woocommerce_blocks_validate_location_contact_fields`.
|
||||
|
||||
## Backward compatibility
|
||||
|
||||
Due to technical reasons, it's not yet possible to specify the meta key for fields, as we want them to be prefixed and managed. Plugins with existing fields in shortcode Checkout can be compatible and react to reading and saving fields using hooks.
|
||||
|
||||
Assuming 2 fields, named `my-plugin-namespace/address-field` in the address step and `my-plugin-namespace/my-other-field` in the order step, you can:
|
||||
|
||||
### React to to saving fields
|
||||
|
||||
You can react to those fields being saved by hooking into `woocommerce_set_additional_field_value` action.
|
||||
|
||||
```php
|
||||
add_action(
|
||||
'woocommerce_set_additional_field_value',
|
||||
function ( $key, $value, $group, $wc_object ) {
|
||||
if ( 'my-plugin-namespace/address-field' !== $key ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'billing' === $group ) {
|
||||
$my_plugin_address_key = 'existing_billing_address_field_key';
|
||||
} else {
|
||||
$my_plugin_address_key = 'existing_shipping_address_field_key';
|
||||
}
|
||||
|
||||
$wc_object->update_meta_data( $my_plugin_address_key, $value, true );
|
||||
},
|
||||
10,
|
||||
4
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_set_additional_field_value',
|
||||
function ( $key, $value, $group, $wc_object ) {
|
||||
if ( 'my-plugin-namespace/my-other-field' !== $key ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$my_plugin_key = 'existing_order_field_key';
|
||||
|
||||
$wc_object->update_meta_data( $my_plugin_key, $value, true );
|
||||
},
|
||||
10,
|
||||
4
|
||||
);
|
||||
```
|
||||
|
||||
This way, you can ensure existing systems will continue working and your integration will continue to work. However, ideally, you should migrate your existing data and systems to use the new meta fields.
|
||||
|
||||
|
||||
### React to reading fields
|
||||
|
||||
You can use the `woocommerce_get_default_value_for_{$key}` filters to provide a different default value (a value coming from another meta field for example):
|
||||
|
||||
```php
|
||||
add_filter(
|
||||
"woocommerce_blocks_get_default_value_for_my-plugin-namespace/address-field",
|
||||
function ( $value, $group, $wc_object ) {
|
||||
|
||||
if ( 'billing' === $group ) {
|
||||
$my_plugin_key = 'existing_billing_address_field_key';
|
||||
} else {
|
||||
$my_plugin_key = 'existing_shipping_address_field_key';
|
||||
}
|
||||
|
||||
return $wc_object->get_meta( $my_plugin_key );
|
||||
},
|
||||
10,
|
||||
3
|
||||
);
|
||||
|
||||
add_filter(
|
||||
"woocommerce_blocks_get_default_value_for_my-plugin-namespace/my-other-field",
|
||||
function ( $value, $group, $wc_object ) {
|
||||
|
||||
$my_plugin_key = 'existing_order_field_key';
|
||||
|
||||
return $wc_object->get_meta( $my_plugin_key );
|
||||
},
|
||||
10,
|
||||
3
|
||||
);
|
||||
```
|
||||
|
||||
## A full example
|
||||
|
||||
In this full example we will register the Government ID text field and verify that it conforms to a specific pattern.
|
||||
|
@ -598,7 +684,7 @@ This example is just a combined version of the examples shared above.
|
|||
add_action(
|
||||
'woocommerce_blocks_loaded',
|
||||
function() {
|
||||
woocommerce_blocks_register_checkout_field(
|
||||
woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => 'namespace/gov-id',
|
||||
'label' => 'Government ID',
|
||||
|
@ -611,7 +697,7 @@ add_action(
|
|||
),
|
||||
),
|
||||
);
|
||||
woocommerce_blocks_register_checkout_field(
|
||||
woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => 'namespace/confirm-gov-id',
|
||||
'label' => 'Confirm government ID',
|
||||
|
@ -626,7 +712,7 @@ add_action(
|
|||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_blocks_sanitize_additional_field',
|
||||
'woocommerce_sanitize_additional_field',
|
||||
function ( $field_value, $field_key ) {
|
||||
if ( 'namespace/gov-id' === $field_key || 'namespace/confirm-gov-id' === $field_key ) {
|
||||
$field_value = str_replace( ' ', '', $field_key );
|
||||
|
@ -639,7 +725,7 @@ add_action(
|
|||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_blocks_validate_additional_field',
|
||||
'woocommerce_validate_additional_field',
|
||||
function ( WP_Error $errors, $field_key, $field_value ) {
|
||||
if ( 'namespace/gov-id' === $field_key ) {
|
||||
$match = preg_match( '/[A-Z0-9]{5}/', $field_value );
|
||||
|
|
|
@ -49,7 +49,7 @@ class Additional_Checkout_Fields_Test_Helper {
|
|||
*/
|
||||
public function register_custom_checkout_fields() {
|
||||
// Address fields, checkbox, textbox, select
|
||||
woocommerce_blocks_register_checkout_field(
|
||||
woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => 'first-plugin-namespace/government-ID',
|
||||
'label' => 'Government ID',
|
||||
|
@ -67,7 +67,7 @@ class Additional_Checkout_Fields_Test_Helper {
|
|||
},
|
||||
),
|
||||
);
|
||||
woocommerce_blocks_register_checkout_field(
|
||||
woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => 'first-plugin-namespace/confirm-government-ID',
|
||||
'label' => 'Confirm government ID',
|
||||
|
@ -85,7 +85,7 @@ class Additional_Checkout_Fields_Test_Helper {
|
|||
},
|
||||
),
|
||||
);
|
||||
woocommerce_blocks_register_checkout_field(
|
||||
woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => 'first-plugin-namespace/truck-size-ok',
|
||||
'label' => 'Can a truck fit down your road?',
|
||||
|
@ -93,7 +93,7 @@ class Additional_Checkout_Fields_Test_Helper {
|
|||
'type' => 'checkbox',
|
||||
)
|
||||
);
|
||||
woocommerce_blocks_register_checkout_field(
|
||||
woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => 'first-plugin-namespace/road-size',
|
||||
'label' => 'How wide is your road?',
|
||||
|
@ -118,7 +118,7 @@ class Additional_Checkout_Fields_Test_Helper {
|
|||
|
||||
// Fake sanitization function that removes full stops from the Government ID string.
|
||||
add_filter(
|
||||
'woocommerce_blocks_sanitize_additional_field',
|
||||
'woocommerce_sanitize_additional_field',
|
||||
function ( $field_value, $field_key ) {
|
||||
if ( 'first-plugin-namespace/government-ID' === $field_key ) {
|
||||
$field_value = str_replace( '.', '', $field_value );
|
||||
|
@ -130,7 +130,7 @@ class Additional_Checkout_Fields_Test_Helper {
|
|||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_blocks_validate_additional_field',
|
||||
'woocommerce_validate_additional_field',
|
||||
function ( WP_Error $errors, $field_key, $field_value ) {
|
||||
if ( 'first-plugin-namespace/government-ID' === $field_key || 'first-plugin-namespace/confirm-government-ID' === $field_key ) {
|
||||
$match = preg_match( '/[A-Z0-9]{5}/', $field_value );
|
||||
|
@ -155,7 +155,7 @@ class Additional_Checkout_Fields_Test_Helper {
|
|||
);
|
||||
|
||||
// Contact fields, one checkbox, select, and text input.
|
||||
woocommerce_blocks_register_checkout_field(
|
||||
woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => 'second-plugin-namespace/marketing-opt-in',
|
||||
'label' => 'Do you want to subscribe to our newsletter?',
|
||||
|
@ -163,7 +163,7 @@ class Additional_Checkout_Fields_Test_Helper {
|
|||
'type' => 'checkbox',
|
||||
)
|
||||
);
|
||||
woocommerce_blocks_register_checkout_field(
|
||||
woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => 'second-plugin-namespace/gift-message-in-package',
|
||||
'label' => 'Enter a gift message to include in the package',
|
||||
|
@ -171,7 +171,7 @@ class Additional_Checkout_Fields_Test_Helper {
|
|||
'type' => 'text',
|
||||
)
|
||||
);
|
||||
woocommerce_blocks_register_checkout_field(
|
||||
woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => 'second-plugin-namespace/type-of-purchase',
|
||||
'label' => 'Is this a personal purchase or a business purchase?',
|
||||
|
@ -193,7 +193,7 @@ class Additional_Checkout_Fields_Test_Helper {
|
|||
|
||||
// A field of each type in additional information section.
|
||||
|
||||
woocommerce_blocks_register_checkout_field(
|
||||
woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => 'third-plugin-namespace/please-send-me-a-free-gift',
|
||||
'label' => 'Would you like a free gift with your order?',
|
||||
|
@ -202,7 +202,7 @@ class Additional_Checkout_Fields_Test_Helper {
|
|||
)
|
||||
);
|
||||
|
||||
woocommerce_blocks_register_checkout_field(
|
||||
woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => 'third-plugin-namespace/what-is-your-favourite-colour',
|
||||
'label' => 'What is your favourite colour?',
|
||||
|
@ -211,7 +211,7 @@ class Additional_Checkout_Fields_Test_Helper {
|
|||
)
|
||||
);
|
||||
|
||||
woocommerce_blocks_register_checkout_field(
|
||||
woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => 'third-plugin-namespace/how-did-you-hear-about-us',
|
||||
'label' => 'How did you hear about us?',
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: add
|
||||
|
||||
Add support for hooking into reading and saving additional fields.
|
|
@ -309,7 +309,7 @@ class CheckoutFields {
|
|||
public function default_validate_callback( $value, $field ) {
|
||||
if ( ! empty( $field['required'] ) && empty( $value ) ) {
|
||||
return new WP_Error(
|
||||
'woocommerce_blocks_checkout_field_required',
|
||||
'woocommerce_required_checkout_field',
|
||||
sprintf(
|
||||
// translators: %s is field key.
|
||||
__( 'The field %s is required.', 'woocommerce' ),
|
||||
|
@ -401,26 +401,26 @@ class CheckoutFields {
|
|||
*/
|
||||
private function validate_options( &$options ) {
|
||||
if ( empty( $options['id'] ) ) {
|
||||
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', 'A checkout field cannot be registered without an id.', '8.6.0' );
|
||||
_doing_it_wrong( 'woocommerce_register_additional_checkout_field', 'A checkout field cannot be registered without an id.', '8.6.0' );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Having fewer than 2 after exploding around a / means there is no namespace.
|
||||
if ( count( explode( '/', $options['id'] ) ) < 2 ) {
|
||||
$message = sprintf( 'Unable to register field with id: "%s". %s', $options['id'], 'A checkout field id must consist of namespace/name.' );
|
||||
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
_doing_it_wrong( 'woocommerce_register_additional_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( empty( $options['label'] ) ) {
|
||||
$message = sprintf( 'Unable to register field with id: "%s". %s', $options['id'], 'The field label is required.' );
|
||||
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
_doing_it_wrong( 'woocommerce_register_additional_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( empty( $options['location'] ) ) {
|
||||
$message = sprintf( 'Unable to register field with id: "%s". %s', $options['id'], 'The field location is required.' );
|
||||
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
_doing_it_wrong( 'woocommerce_register_additional_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -431,7 +431,7 @@ class CheckoutFields {
|
|||
|
||||
if ( ! in_array( $options['location'], array_keys( $this->fields_locations ), true ) ) {
|
||||
$message = sprintf( 'Unable to register field with id: "%s". %s', $options['id'], 'The field location is invalid.' );
|
||||
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
_doing_it_wrong( 'woocommerce_register_additional_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -442,7 +442,7 @@ class CheckoutFields {
|
|||
// Check to see if field is already in the array.
|
||||
if ( ! empty( $this->additional_fields[ $id ] ) || in_array( $id, $this->fields_locations[ $location ], true ) ) {
|
||||
$message = sprintf( 'Unable to register field with id: "%s". %s', $id, 'The field is already registered.' );
|
||||
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
_doing_it_wrong( 'woocommerce_register_additional_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -454,27 +454,27 @@ class CheckoutFields {
|
|||
$options['type'],
|
||||
implode( ', ', $this->supported_field_types )
|
||||
);
|
||||
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
_doing_it_wrong( 'woocommerce_register_additional_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $options['sanitize_callback'] ) && ! is_callable( $options['sanitize_callback'] ) ) {
|
||||
$message = sprintf( 'Unable to register field with id: "%s". %s', $id, 'The sanitize_callback must be a valid callback.' );
|
||||
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
_doing_it_wrong( 'woocommerce_register_additional_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! empty( $options['validate_callback'] ) && ! is_callable( $options['validate_callback'] ) ) {
|
||||
$message = sprintf( 'Unable to register field with id: "%s". %s', $id, 'The validate_callback must be a valid callback.' );
|
||||
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
_doing_it_wrong( 'woocommerce_register_additional_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Hidden fields are not supported right now. They will be registered with hidden => false.
|
||||
if ( ! empty( $options['hidden'] ) && true === $options['hidden'] ) {
|
||||
$message = sprintf( 'Registering a field with hidden set to true is not supported. The field "%s" will be registered as visible.', $id );
|
||||
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
_doing_it_wrong( 'woocommerce_register_additional_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
// Don't return here unlike the other fields because this is not an issue that will prevent registration.
|
||||
}
|
||||
|
||||
|
@ -494,7 +494,7 @@ class CheckoutFields {
|
|||
|
||||
if ( empty( $options['options'] ) || ! is_array( $options['options'] ) ) {
|
||||
$message = sprintf( 'Unable to register field with id: "%s". %s', $id, 'Fields of type "select" must have an array of "options".' );
|
||||
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
_doing_it_wrong( 'woocommerce_register_additional_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
return false;
|
||||
}
|
||||
$cleaned_options = [];
|
||||
|
@ -504,7 +504,7 @@ class CheckoutFields {
|
|||
foreach ( $options['options'] as $option ) {
|
||||
if ( ! isset( $option['value'] ) || ! isset( $option['label'] ) ) {
|
||||
$message = sprintf( 'Unable to register field with id: "%s". %s', $id, 'Fields of type "select" must have an array of "options" and each option must contain a "value" and "label" member.' );
|
||||
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
_doing_it_wrong( 'woocommerce_register_additional_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -513,7 +513,7 @@ class CheckoutFields {
|
|||
|
||||
if ( in_array( $sanitized_value, $added_values, true ) ) {
|
||||
$message = sprintf( 'Duplicate key found when registering field with id: "%s". The value in each option of "select" fields must be unique. Duplicate value "%s" found. The duplicate key will be removed.', $id, $sanitized_value );
|
||||
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
_doing_it_wrong( 'woocommerce_register_additional_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -559,7 +559,7 @@ class CheckoutFields {
|
|||
|
||||
if ( isset( $options['required'] ) && true === $options['required'] ) {
|
||||
$message = sprintf( 'Registering checkbox fields as required is not supported. "%s" will be registered as optional.', $id );
|
||||
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
_doing_it_wrong( 'woocommerce_register_additional_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
}
|
||||
|
||||
return $field_data;
|
||||
|
@ -582,7 +582,7 @@ class CheckoutFields {
|
|||
|
||||
if ( ! is_array( $attributes ) || 0 === count( $attributes ) ) {
|
||||
$message = sprintf( 'An invalid attributes value was supplied when registering field with id: "%s". %s', $id, 'Attributes must be a non-empty array.' );
|
||||
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
_doing_it_wrong( 'woocommerce_register_additional_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
return [];
|
||||
}
|
||||
|
||||
|
@ -608,7 +608,7 @@ class CheckoutFields {
|
|||
if ( count( $attributes ) !== count( $valid_attributes ) ) {
|
||||
$invalid_attributes = array_keys( array_diff_key( $attributes, $valid_attributes ) );
|
||||
$message = sprintf( 'Invalid attribute found when registering field with id: "%s". Attributes: %s are not allowed.', $id, implode( ', ', $invalid_attributes ) );
|
||||
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
_doing_it_wrong( 'woocommerce_register_additional_checkout_field', esc_html( $message ), '8.6.0' );
|
||||
}
|
||||
|
||||
// Escape attributes to remove any malicious code and return them.
|
||||
|
@ -677,9 +677,9 @@ class CheckoutFields {
|
|||
* @param string $field_key Key of the field being sanitized.
|
||||
*
|
||||
* @since 8.6.0
|
||||
* @deprecated 8.7.0 Use woocommerce_blocks_sanitize_additional_field instead.
|
||||
* @deprecated 8.7.0 Use woocommerce_sanitize_additional_field instead.
|
||||
*/
|
||||
$field_value = apply_filters_deprecated( '__experimental_woocommerce_blocks_sanitize_additional_field', array( $field_value, $field_key ), '8.7.0', 'woocommerce_blocks_sanitize_additional_field', 'This action has been graduated, use woocommerce_blocks_sanitize_additional_field instead.' );
|
||||
$field_value = apply_filters_deprecated( '__experimental_woocommerce_blocks_sanitize_additional_field', array( $field_value, $field_key ), '8.7.0', 'woocommerce_sanitize_additional_field', 'This action has been graduated, use woocommerce_sanitize_additional_field instead.' );
|
||||
|
||||
/**
|
||||
* Allow custom sanitization of an additional field.
|
||||
|
@ -689,7 +689,7 @@ class CheckoutFields {
|
|||
*
|
||||
* @since 8.7.0
|
||||
*/
|
||||
return apply_filters( 'woocommerce_blocks_sanitize_additional_field', $field_value, $field_key );
|
||||
return apply_filters( 'woocommerce_sanitize_additional_field', $field_value, $field_key );
|
||||
|
||||
} catch ( \Throwable $e ) {
|
||||
// One of the filters errored so skip it. This allows the checkout process to continue.
|
||||
|
@ -738,9 +738,9 @@ class CheckoutFields {
|
|||
* @param mixed $field_value The value of the field being validated.
|
||||
*
|
||||
* @since 8.6.0
|
||||
* @deprecated 8.7.0 Use woocommerce_blocks_validate_additional_field instead.
|
||||
* @deprecated 8.7.0 Use woocommerce_validate_additional_field instead.
|
||||
*/
|
||||
wc_do_deprecated_action( '__experimental_woocommerce_blocks_validate_additional_field', array( $errors, $field_key, $field_value ), '8.7.0', 'woocommerce_blocks_validate_additional_field', 'This action has been graduated, use woocommerce_blocks_validate_additional_field instead.' );
|
||||
wc_do_deprecated_action( '__experimental_woocommerce_blocks_validate_additional_field', array( $errors, $field_key, $field_value ), '8.7.0', 'woocommerce_validate_additional_field', 'This action has been graduated, use woocommerce_validate_additional_field instead.' );
|
||||
/**
|
||||
* Pass an error object to allow validation of an additional field.
|
||||
*
|
||||
|
@ -750,7 +750,7 @@ class CheckoutFields {
|
|||
*
|
||||
* @since 8.7.0
|
||||
*/
|
||||
do_action( 'woocommerce_blocks_validate_additional_field', $errors, $field_key, $field_value );
|
||||
do_action( 'woocommerce_validate_additional_field', $errors, $field_key, $field_value );
|
||||
|
||||
} catch ( \Throwable $e ) {
|
||||
|
||||
|
@ -785,7 +785,7 @@ class CheckoutFields {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns an array of fields keys for the address group.
|
||||
* Returns an array of fields keys for the address location.
|
||||
*
|
||||
* @return array An array of fields keys.
|
||||
*/
|
||||
|
@ -794,7 +794,7 @@ class CheckoutFields {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns an array of fields keys for the contact group.
|
||||
* Returns an array of fields keys for the contact location.
|
||||
*
|
||||
* @return array An array of fields keys.
|
||||
*/
|
||||
|
@ -803,7 +803,7 @@ class CheckoutFields {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns an array of fields keys for the additional area group.
|
||||
* Returns an array of fields keys for the additional area location.
|
||||
*
|
||||
* @return array An array of fields keys.
|
||||
* @deprecated 8.9.0 Use get_order_fields_keys instead.
|
||||
|
@ -823,7 +823,7 @@ class CheckoutFields {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns an array of fields for a given group.
|
||||
* Returns an array of fields for a given location.
|
||||
*
|
||||
* @param string $location The location to get fields for (address|contact|order).
|
||||
* @return array An array of fields definitions.
|
||||
|
@ -941,7 +941,7 @@ class CheckoutFields {
|
|||
|
||||
if ( ! $this->is_field( $key ) ) {
|
||||
return new WP_Error(
|
||||
'woocommerce_blocks_checkout_field_invalid',
|
||||
'woocommerce_invalid_checkout_field',
|
||||
\sprintf(
|
||||
// translators: % is field key.
|
||||
__( 'The field %s is invalid.', 'woocommerce' ),
|
||||
|
@ -952,7 +952,7 @@ class CheckoutFields {
|
|||
|
||||
if ( ! in_array( $key, $this->fields_locations[ $location ], true ) ) {
|
||||
return new WP_Error(
|
||||
'woocommerce_blocks_checkout_field_invalid_location',
|
||||
'woocommerce_invalid_checkout_field_location',
|
||||
\sprintf(
|
||||
// translators: %1$s is field key, %2$s location.
|
||||
__( 'The field %1$s is invalid for the location %2$s.', 'woocommerce' ),
|
||||
|
@ -965,7 +965,7 @@ class CheckoutFields {
|
|||
$field = $this->additional_fields[ $key ];
|
||||
if ( ! empty( $field['required'] ) && empty( $value ) ) {
|
||||
return new WP_Error(
|
||||
'woocommerce_blocks_checkout_field_required',
|
||||
'woocommerce_required_checkout_field',
|
||||
\sprintf(
|
||||
// translators: %s is field key.
|
||||
__( 'The field %s is required.', 'woocommerce' ),
|
||||
|
@ -977,6 +977,28 @@ class CheckoutFields {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all fields key for a given group.
|
||||
*
|
||||
* @param string $group The group to get the key for (shipping|billing|other).
|
||||
*
|
||||
* @return string[] Field keys.
|
||||
*/
|
||||
public function get_fields_for_group( $group = 'other' ) {
|
||||
if ( 'shipping' === $group ) {
|
||||
return $this->get_fields_for_location( 'address' );
|
||||
}
|
||||
|
||||
if ( 'billing' === $group ) {
|
||||
return $this->get_fields_for_location( 'address' );
|
||||
}
|
||||
|
||||
return \array_merge(
|
||||
$this->get_fields_for_location( 'contact' ),
|
||||
$this->get_fields_for_location( 'order' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given key is a valid field.
|
||||
*
|
||||
|
@ -1057,6 +1079,17 @@ class CheckoutFields {
|
|||
private function set_array_meta( string $key, $value, WC_Data $wc_object, string $group ) {
|
||||
$meta_key = self::get_group_key( $group ) . $key;
|
||||
|
||||
/**
|
||||
* Allow reacting for saving an additional field value.
|
||||
*
|
||||
* @param string $key The key of the field being saved.
|
||||
* @param mixed $value The value of the field being saved.
|
||||
* @param string $group The group of this location (shipping|billing|other).
|
||||
* @param WC_Customer|WC_Order $wc_object The object to set the field value for.
|
||||
*
|
||||
* @since 8.9.0
|
||||
*/
|
||||
do_action( 'woocommerce_set_additional_field_value', $key, $value, $group, $wc_object );
|
||||
// Convert boolean values to strings because Data Stores will skip false values.
|
||||
if ( is_bool( $value ) ) {
|
||||
$value = $value ? '1' : '0';
|
||||
|
@ -1082,18 +1115,31 @@ class CheckoutFields {
|
|||
|
||||
$meta_key = self::get_group_key( $group ) . $key;
|
||||
|
||||
$meta_data = $wc_object->get_meta( $meta_key, true );
|
||||
$value = $wc_object->get_meta( $meta_key, true );
|
||||
|
||||
if ( ! $value ) {
|
||||
/**
|
||||
* Allow providing a default value for additional fields if no value is already set.
|
||||
*
|
||||
* @param null $value The default value for the filter, always null.
|
||||
* @param string $group The group of this key (shipping|billing|other).
|
||||
* @param WC_Data $wc_object The object to get the field value for.
|
||||
*
|
||||
* @since 8.9.0
|
||||
*/
|
||||
$value = apply_filters( "woocommerce_get_default_value_for_{$key}", null, $group, $wc_object );
|
||||
}
|
||||
|
||||
// We cast the value to a boolean if the field is a checkbox.
|
||||
if ( $this->is_field( $key ) && 'checkbox' === $this->additional_fields[ $key ]['type'] ) {
|
||||
return '1' === $meta_data;
|
||||
return '1' === $value;
|
||||
}
|
||||
|
||||
if ( null === $meta_data ) {
|
||||
if ( null === $value ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $meta_data;
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1127,6 +1173,25 @@ class CheckoutFields {
|
|||
}
|
||||
}
|
||||
|
||||
$missing_fields = array_diff( array_keys( $this->get_fields_for_group( $group ) ), array_keys( $meta_data ) );
|
||||
|
||||
foreach ( $missing_fields as $missing_field ) {
|
||||
/**
|
||||
* Allow providing a default value for additional fields if no value is already set.
|
||||
*
|
||||
* @param null $value The default value for the filter, always null.
|
||||
* @param string $group The group of this key (shipping|billing|other).
|
||||
* @param WC_Data $wc_object The object to get the field value for.
|
||||
*
|
||||
* @since 8.9.0
|
||||
*/
|
||||
$value = apply_filters( "woocommerce_get_default_value_for_{$missing_field}", null, $group, $wc_object );
|
||||
|
||||
if ( $value ) {
|
||||
$meta_data[ $missing_field ] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $meta_data;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
use Automattic\WooCommerce\Blocks\Package;
|
||||
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
|
||||
|
||||
if ( ! function_exists( 'woocommerce_blocks_register_checkout_field' ) ) {
|
||||
if ( ! function_exists( 'woocommerce_register_additional_checkout_field' ) ) {
|
||||
/**
|
||||
* Register a checkout field.
|
||||
*
|
||||
* @param array $options Field arguments. See CheckoutFields::register_checkout_field() for details.
|
||||
* @throws \Exception If field registration fails.
|
||||
*/
|
||||
function woocommerce_blocks_register_checkout_field( $options ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
|
||||
function woocommerce_register_additional_checkout_field( $options ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
|
||||
|
||||
// Check if `woocommerce_blocks_loaded` ran. If not then the CheckoutFields class will not be available yet.
|
||||
// In that case, re-hook `woocommerce_blocks_loaded` and try running this again.
|
||||
|
@ -19,7 +19,7 @@ if ( ! function_exists( 'woocommerce_blocks_register_checkout_field' ) ) {
|
|||
add_action(
|
||||
'woocommerce_blocks_loaded',
|
||||
function () use ( $options ) {
|
||||
woocommerce_blocks_register_checkout_field( $options );
|
||||
woocommerce_register_additional_checkout_field( $options );
|
||||
}
|
||||
);
|
||||
return;
|
||||
|
@ -39,11 +39,11 @@ if ( ! function_exists( '__experimental_woocommerce_blocks_register_checkout_fie
|
|||
*
|
||||
* @param array $options Field arguments. See CheckoutFields::register_checkout_field() for details.
|
||||
* @throws \Exception If field registration fails.
|
||||
* @deprecated 5.6.0 Use woocommerce_blocks_register_checkout_field() instead.
|
||||
* @deprecated 5.6.0 Use woocommerce_register_additional_checkout_field() instead.
|
||||
*/
|
||||
function __experimental_woocommerce_blocks_register_checkout_field( $options ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
|
||||
wc_deprecated_function( __FUNCTION__, '8.9.0', 'woocommerce_blocks_register_checkout_field' );
|
||||
woocommerce_blocks_register_checkout_field( $options );
|
||||
wc_deprecated_function( __FUNCTION__, '8.9.0', 'woocommerce_register_additional_checkout_field' );
|
||||
woocommerce_register_additional_checkout_field( $options );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -142,7 +142,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
'type' => 'checkbox',
|
||||
),
|
||||
);
|
||||
array_map( 'woocommerce_blocks_register_checkout_field', $this->fields );
|
||||
array_map( 'woocommerce_register_additional_checkout_field', $this->fields );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -287,7 +287,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
*/
|
||||
public function test_optional_field_in_schema() {
|
||||
$id = 'plugin-namespace/optional-field';
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Optional Field',
|
||||
|
@ -324,7 +324,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$doing_it_wrong_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$doing_it_wrong_mocker->shouldReceive( 'doing_it_wrong_run' )->withArgs(
|
||||
array(
|
||||
'woocommerce_blocks_register_checkout_field',
|
||||
'woocommerce_register_additional_checkout_field',
|
||||
'A checkout field cannot be registered without an id.',
|
||||
)
|
||||
)->once();
|
||||
|
@ -338,7 +338,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
10,
|
||||
2
|
||||
);
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'label' => 'Invalid ID',
|
||||
'location' => 'order',
|
||||
|
@ -366,7 +366,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$doing_it_wrong_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$doing_it_wrong_mocker->shouldReceive( 'doing_it_wrong_run' )->withArgs(
|
||||
array(
|
||||
'woocommerce_blocks_register_checkout_field',
|
||||
'woocommerce_register_additional_checkout_field',
|
||||
\esc_html( \sprintf( 'Unable to register field with id: "%s". A checkout field id must consist of namespace/name.', $id ) ),
|
||||
|
||||
)
|
||||
|
@ -381,7 +381,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
10,
|
||||
2
|
||||
);
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Invalid ID',
|
||||
|
@ -410,7 +410,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$doing_it_wrong_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$doing_it_wrong_mocker->shouldReceive( 'doing_it_wrong_run' )->withArgs(
|
||||
array(
|
||||
'woocommerce_blocks_register_checkout_field',
|
||||
'woocommerce_register_additional_checkout_field',
|
||||
\esc_html( \sprintf( 'Unable to register field with id: "%s". The field label is required.', $id ) ),
|
||||
)
|
||||
)->once();
|
||||
|
@ -424,7 +424,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
10,
|
||||
2
|
||||
);
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'location' => 'order',
|
||||
|
@ -452,7 +452,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$doing_it_wrong_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$doing_it_wrong_mocker->shouldReceive( 'doing_it_wrong_run' )->withArgs(
|
||||
array(
|
||||
'woocommerce_blocks_register_checkout_field',
|
||||
'woocommerce_register_additional_checkout_field',
|
||||
\esc_html( \sprintf( 'Unable to register field with id: "%s". The field location is required.', $id ) ),
|
||||
)
|
||||
)->once();
|
||||
|
@ -466,7 +466,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
10,
|
||||
2
|
||||
);
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Missing Location',
|
||||
|
@ -493,7 +493,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$doing_it_wrong_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$doing_it_wrong_mocker->shouldReceive( 'doing_it_wrong_run' )->withArgs(
|
||||
array(
|
||||
'woocommerce_blocks_register_checkout_field',
|
||||
'woocommerce_register_additional_checkout_field',
|
||||
\esc_html( \sprintf( 'Unable to register field with id: "%s". The field location is invalid.', $id ) ),
|
||||
)
|
||||
)->once();
|
||||
|
@ -508,7 +508,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
2
|
||||
);
|
||||
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Invalid Location',
|
||||
|
@ -538,7 +538,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$doing_it_wrong_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$doing_it_wrong_mocker->shouldReceive( 'doing_it_wrong_run' )->withArgs(
|
||||
array(
|
||||
'woocommerce_blocks_register_checkout_field',
|
||||
'woocommerce_register_additional_checkout_field',
|
||||
\esc_html( \sprintf( 'Unable to register field with id: "%s". The field is already registered.', $id ) ),
|
||||
)
|
||||
)->once();
|
||||
|
@ -553,7 +553,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
2
|
||||
);
|
||||
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Government ID',
|
||||
|
@ -580,7 +580,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$doing_it_wrong_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$doing_it_wrong_mocker->shouldReceive( 'doing_it_wrong_run' )->withArgs(
|
||||
array(
|
||||
'woocommerce_blocks_register_checkout_field',
|
||||
'woocommerce_register_additional_checkout_field',
|
||||
\esc_html(
|
||||
sprintf(
|
||||
'Unable to register field with id: "%s". Registering a field with type "%s" is not supported. The supported types are: %s.',
|
||||
|
@ -602,7 +602,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
2
|
||||
);
|
||||
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Invalid Type',
|
||||
|
@ -632,7 +632,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$doing_it_wrong_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$doing_it_wrong_mocker->shouldReceive( 'doing_it_wrong_run' )->withArgs(
|
||||
array(
|
||||
'woocommerce_blocks_register_checkout_field',
|
||||
'woocommerce_register_additional_checkout_field',
|
||||
\esc_html( sprintf( 'Unable to register field with id: "%s". %s', $id, 'The sanitize_callback must be a valid callback.' ) ),
|
||||
)
|
||||
)->once();
|
||||
|
@ -647,7 +647,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
2
|
||||
);
|
||||
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Invalid Sanitize',
|
||||
|
@ -678,7 +678,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$doing_it_wrong_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$doing_it_wrong_mocker->shouldReceive( 'doing_it_wrong_run' )->withArgs(
|
||||
array(
|
||||
'woocommerce_blocks_register_checkout_field',
|
||||
'woocommerce_register_additional_checkout_field',
|
||||
\esc_html( sprintf( 'Unable to register field with id: "%s". %s', $id, 'The validate_callback must be a valid callback.' ) ),
|
||||
)
|
||||
)->once();
|
||||
|
@ -693,7 +693,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
2
|
||||
);
|
||||
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Invalid Validate',
|
||||
|
@ -724,7 +724,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$doing_it_wrong_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$doing_it_wrong_mocker->shouldReceive( 'doing_it_wrong_run' )->withArgs(
|
||||
array(
|
||||
'woocommerce_blocks_register_checkout_field',
|
||||
'woocommerce_register_additional_checkout_field',
|
||||
\esc_html( sprintf( 'An invalid attributes value was supplied when registering field with id: "%s". %s', $id, 'Attributes must be a non-empty array.' ) ),
|
||||
)
|
||||
)->once();
|
||||
|
@ -739,7 +739,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
2
|
||||
);
|
||||
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Invalid Attribute',
|
||||
|
@ -794,7 +794,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$doing_it_wrong_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$doing_it_wrong_mocker->shouldReceive( 'doing_it_wrong_run' )->withArgs(
|
||||
array(
|
||||
'woocommerce_blocks_register_checkout_field',
|
||||
'woocommerce_register_additional_checkout_field',
|
||||
\esc_html( sprintf( 'Invalid attribute found when registering field with id: "%s". Attributes: %s are not allowed.', $id, implode( ', ', $invalid_attributes ) ) ),
|
||||
)
|
||||
)->once();
|
||||
|
@ -809,7 +809,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
2
|
||||
);
|
||||
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Invalid Attribute Values',
|
||||
|
@ -868,7 +868,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$doing_it_wrong_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$doing_it_wrong_mocker->shouldReceive( 'doing_it_wrong_run' )->withArgs(
|
||||
array(
|
||||
'woocommerce_blocks_register_checkout_field',
|
||||
'woocommerce_register_additional_checkout_field',
|
||||
\esc_html( sprintf( 'Unable to register field with id: "%s". %s', $id, 'Fields of type "select" must have an array of "options".' ) ),
|
||||
)
|
||||
)->once();
|
||||
|
@ -883,7 +883,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
2
|
||||
);
|
||||
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Missing Options',
|
||||
|
@ -913,7 +913,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$doing_it_wrong_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$doing_it_wrong_mocker->shouldReceive( 'doing_it_wrong_run' )->withArgs(
|
||||
array(
|
||||
'woocommerce_blocks_register_checkout_field',
|
||||
'woocommerce_register_additional_checkout_field',
|
||||
\esc_html( sprintf( 'Unable to register field with id: "%s". %s', $id, 'Fields of type "select" must have an array of "options" and each option must contain a "value" and "label" member.' ) ),
|
||||
)
|
||||
)->once();
|
||||
|
@ -928,7 +928,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
2
|
||||
);
|
||||
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Invalid Options',
|
||||
|
@ -960,7 +960,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$doing_it_wrong_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$doing_it_wrong_mocker->shouldReceive( 'doing_it_wrong_run' )->withArgs(
|
||||
array(
|
||||
'woocommerce_blocks_register_checkout_field',
|
||||
'woocommerce_register_additional_checkout_field',
|
||||
\esc_html( sprintf( 'Duplicate key found when registering field with id: "%s". The value in each option of "select" fields must be unique. Duplicate value "%s" found. The duplicate key will be removed.', $id, 'duplicate' ) ),
|
||||
)
|
||||
)->once();
|
||||
|
@ -975,7 +975,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
2
|
||||
);
|
||||
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Duplicate Options',
|
||||
|
@ -1026,7 +1026,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
*/
|
||||
public function test_optional_select_has_empty_value() {
|
||||
$id = 'plugin-namespace/optional-select';
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Optional Select',
|
||||
|
@ -1068,7 +1068,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$doing_it_wrong_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$doing_it_wrong_mocker->shouldReceive( 'doing_it_wrong_run' )->withArgs(
|
||||
array(
|
||||
'woocommerce_blocks_register_checkout_field',
|
||||
'woocommerce_register_additional_checkout_field',
|
||||
\esc_html( sprintf( 'Registering checkbox fields as required is not supported. "%s" will be registered as optional.', $id ) ),
|
||||
)
|
||||
)->once();
|
||||
|
@ -1083,7 +1083,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
2
|
||||
);
|
||||
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Checkbox Only Optional',
|
||||
|
@ -1127,7 +1127,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$doing_it_wrong_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$doing_it_wrong_mocker->shouldReceive( 'doing_it_wrong_run' )->withArgs(
|
||||
array(
|
||||
'woocommerce_blocks_register_checkout_field',
|
||||
'woocommerce_register_additional_checkout_field',
|
||||
\esc_html( sprintf( 'Registering a field with hidden set to true is not supported. The field "%s" will be registered as visible.', $id ) ),
|
||||
)
|
||||
)->once();
|
||||
|
@ -1142,7 +1142,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
2
|
||||
);
|
||||
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Hidden Field',
|
||||
|
@ -1168,7 +1168,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
)
|
||||
);
|
||||
|
||||
\__internal_woocommerce_blocks_deregister_checkout_field( $id );
|
||||
\__internal_woocommerce_blocks_deregister_checkout_field( $id );
|
||||
|
||||
// Ensures the field isn't registered.
|
||||
$this->assertFalse( $this->controller->is_field( $id ), \sprintf( '%s is still registered', $id ) );
|
||||
|
@ -1280,7 +1280,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
*/
|
||||
public function test_placing_order_sanitize_text() {
|
||||
$id = 'plugin-namespace/sanitize-text';
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Sanitize Text',
|
||||
|
@ -1346,7 +1346,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
*/
|
||||
public function test_placing_order_validate_text() {
|
||||
$id = 'plugin-namespace/validate-text';
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Validate Text',
|
||||
|
@ -1415,7 +1415,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
*/
|
||||
public function test_sanitize_filter() {
|
||||
$id = 'plugin-namespace/filter-sanitize';
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Filter Sanitize',
|
||||
|
@ -1425,7 +1425,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
);
|
||||
|
||||
add_filter(
|
||||
'woocommerce_blocks_sanitize_additional_field',
|
||||
'woocommerce_sanitize_additional_field',
|
||||
function ( $value, $key ) use ( $id ) {
|
||||
if ( $key === $id ) {
|
||||
return 'sanitized-' . $value;
|
||||
|
@ -1492,7 +1492,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
*/
|
||||
public function test_validate_filter() {
|
||||
$id = 'plugin-namespace/filter-validate';
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'Filter Validate',
|
||||
|
@ -1503,7 +1503,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_blocks_validate_additional_field',
|
||||
'woocommerce_validate_additional_field',
|
||||
function ( \WP_Error $errors, $key, $value ) use ( $id ) {
|
||||
if ( $key === $id && 'invalid' === $value ) {
|
||||
$errors->add( 'my_invalid_value', 'Invalid value provided.' );
|
||||
|
@ -1569,7 +1569,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
public function test_place_order_required_address_field() {
|
||||
$id = 'plugin-namespace/my-required-field';
|
||||
$label = 'My Required Field';
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => $label,
|
||||
|
@ -1633,7 +1633,7 @@ class AdditionalFields extends MockeryTestCase {
|
|||
*/
|
||||
public function test_place_order_required_contact_field() {
|
||||
$id = 'plugin-namespace/my-required-contact-field';
|
||||
\woocommerce_blocks_register_checkout_field(
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'My Required Field',
|
||||
|
@ -1863,4 +1863,199 @@ class AdditionalFields extends MockeryTestCase {
|
|||
$this->assertEquals( 'engineering', ( (array) $data['additional_fields'] )['plugin-namespace/job-function'], print_r( $data, true ) );
|
||||
$this->assertArrayNotHasKey( 'plugin-namespace/leave-on-porch', $data['additional_fields'], print_r( $data, true ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures we can provide a default value if a field is not set.
|
||||
*/
|
||||
public function test_reading_values_externally() {
|
||||
$id = 'plugin-namespace/my-external-field';
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'My Required Field',
|
||||
'location' => 'order',
|
||||
'type' => 'text',
|
||||
'required' => true,
|
||||
)
|
||||
);
|
||||
|
||||
add_filter(
|
||||
"woocommerce_get_default_value_for_{$id}",
|
||||
function () {
|
||||
return 'external-value';
|
||||
},
|
||||
10,
|
||||
2
|
||||
);
|
||||
|
||||
$request = new \WP_REST_Request( 'GET', '/wc/store/v1/checkout' );
|
||||
$request->set_header( 'Nonce', wp_create_nonce( 'wc_store_api' ) );
|
||||
$response = rest_get_server()->dispatch( $request );
|
||||
$data = $response->get_data();
|
||||
|
||||
$this->assertEquals( 200, $response->get_status(), print_r( $data, true ) );
|
||||
$this->assertEquals( 'external-value', ( (array) $data['additional_fields'] )[ $id ], print_r( $data, true ) );
|
||||
|
||||
\__internal_woocommerce_blocks_deregister_checkout_field( $id );
|
||||
|
||||
\remove_all_filters( "woocommerce_get_default_value_for_{$id}" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that we cannot overwrite existing fields.
|
||||
*/
|
||||
public function test_not_overwriting_values() {
|
||||
$id = 'plugin-namespace/my-external-field';
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'My Required Field',
|
||||
'location' => 'order',
|
||||
'type' => 'text',
|
||||
'required' => true,
|
||||
)
|
||||
);
|
||||
|
||||
add_filter(
|
||||
"woocommerce_get_default_value_for_{$id}",
|
||||
function () {
|
||||
return 'external-value';
|
||||
},
|
||||
10,
|
||||
2
|
||||
);
|
||||
|
||||
$request = new \WP_REST_Request( 'POST', '/wc/store/v1/checkout' );
|
||||
$request->set_header( 'Nonce', wp_create_nonce( 'wc_store_api' ) );
|
||||
$request->set_body_params(
|
||||
array(
|
||||
'billing_address' => (object) array(
|
||||
'first_name' => 'test',
|
||||
'last_name' => 'test',
|
||||
'company' => '',
|
||||
'address_1' => 'test',
|
||||
'address_2' => '',
|
||||
'city' => 'test',
|
||||
'state' => '',
|
||||
'postcode' => 'cb241ab',
|
||||
'country' => 'GB',
|
||||
'phone' => '',
|
||||
'email' => 'testaccount@test.com',
|
||||
'plugin-namespace/gov-id' => 'gov id',
|
||||
),
|
||||
'shipping_address' => (object) array(
|
||||
'first_name' => 'test',
|
||||
'last_name' => 'test',
|
||||
'company' => '',
|
||||
'address_1' => 'test',
|
||||
'address_2' => '',
|
||||
'city' => 'test',
|
||||
'state' => '',
|
||||
'postcode' => 'cb241ab',
|
||||
'country' => 'GB',
|
||||
'phone' => '',
|
||||
'plugin-namespace/gov-id' => 'gov id',
|
||||
),
|
||||
'payment_method' => 'bacs',
|
||||
'additional_fields' => array(
|
||||
'plugin-namespace/job-function' => 'engineering',
|
||||
$id => 'value',
|
||||
),
|
||||
)
|
||||
);
|
||||
$response = rest_get_server()->dispatch( $request );
|
||||
$data = $response->get_data();
|
||||
|
||||
$this->assertEquals( 200, $response->get_status(), print_r( $data, true ) );
|
||||
$this->assertEquals( 'value', ( (array) $data['additional_fields'] )[ $id ], print_r( $data, true ) );
|
||||
|
||||
\__internal_woocommerce_blocks_deregister_checkout_field( $id );
|
||||
\remove_all_filters( "woocommerce_get_default_value_for_{$id}" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that we can react to saving a field.
|
||||
*/
|
||||
public function test_reacting_to_value_save() {
|
||||
$this->unregister_fields();
|
||||
$id = 'plugin-namespace/my-external-field';
|
||||
\woocommerce_register_additional_checkout_field(
|
||||
array(
|
||||
'id' => $id,
|
||||
'label' => 'My Required Field',
|
||||
'location' => 'order',
|
||||
'type' => 'text',
|
||||
'required' => true,
|
||||
)
|
||||
);
|
||||
|
||||
$set_value_mocker = \Mockery::mock( 'ActionCallback' );
|
||||
$set_value_mocker->shouldReceive( 'woocommerce_set_additional_field_value' )->withArgs(
|
||||
array(
|
||||
$id,
|
||||
'my-value',
|
||||
'other',
|
||||
\Mockery::type( 'WC_Order' ),
|
||||
)
|
||||
)->atLeast( 1 );
|
||||
|
||||
add_action(
|
||||
'woocommerce_set_additional_field_value',
|
||||
array(
|
||||
$set_value_mocker,
|
||||
'woocommerce_set_additional_field_value',
|
||||
),
|
||||
10,
|
||||
4
|
||||
);
|
||||
|
||||
$request = new \WP_REST_Request( 'POST', '/wc/store/v1/checkout' );
|
||||
$request->set_header( 'Nonce', wp_create_nonce( 'wc_store_api' ) );
|
||||
$request->set_body_params(
|
||||
array(
|
||||
'billing_address' => (object) array(
|
||||
'first_name' => 'test',
|
||||
'last_name' => 'test',
|
||||
'company' => '',
|
||||
'address_1' => 'test',
|
||||
'address_2' => '',
|
||||
'city' => 'test',
|
||||
'state' => '',
|
||||
'postcode' => 'cb241ab',
|
||||
'country' => 'GB',
|
||||
'phone' => '',
|
||||
'email' => 'testaccount@test.com',
|
||||
),
|
||||
'shipping_address' => (object) array(
|
||||
'first_name' => 'test',
|
||||
'last_name' => 'test',
|
||||
'company' => '',
|
||||
'address_1' => 'test',
|
||||
'address_2' => '',
|
||||
'city' => 'test',
|
||||
'state' => '',
|
||||
'postcode' => 'cb241ab',
|
||||
'country' => 'GB',
|
||||
'phone' => '',
|
||||
),
|
||||
'payment_method' => 'bacs',
|
||||
'additional_fields' => array(
|
||||
$id => 'my-value',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$response = rest_get_server()->dispatch( $request );
|
||||
$data = $response->get_data();
|
||||
|
||||
$this->assertEquals( 200, $response->get_status(), print_r( $data, true ) );
|
||||
|
||||
\remove_action(
|
||||
'woocommerce_set_additional_field_value',
|
||||
array(
|
||||
$set_value_mocker,
|
||||
'woocommerce_set_additional_field_value',
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue