Move rendering of Order Attribution inputs fully to JS (#44335)
- Define custom element for order-attribution to move DOM manipulations to JS only. To support multiple checkout & register forms on the same page. Co-authored-by: Justin Palmer <228780+layoutd@users.noreply.github.com> Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
parent
49b3e510cb
commit
c0750d5567
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: patch
|
||||||
|
Type: update
|
||||||
|
|
||||||
|
Move the rendering of Order Attribution inputs fully to JS. Support multiple instances on the same page.
|
|
@ -7,6 +7,7 @@
|
||||||
const $ = document.querySelector.bind( document );
|
const $ = document.querySelector.bind( document );
|
||||||
const propertyAccessor = ( obj, path ) => path.split( '.' ).reduce( ( acc, part ) => acc && acc[ part ], obj );
|
const propertyAccessor = ( obj, path ) => path.split( '.' ).reduce( ( acc, part ) => acc && acc[ part ], obj );
|
||||||
const returnNull = () => null;
|
const returnNull = () => null;
|
||||||
|
const stringifyFalsyInputValue = ( value ) => value === null || value === undefined ? '' : value;
|
||||||
|
|
||||||
// Hardcode Checkout store key (`wc.wcBlocksData.CHECKOUT_STORE_KEY`), as we no longer have `wc-blocks-checkout` as a dependency.
|
// Hardcode Checkout store key (`wc.wcBlocksData.CHECKOUT_STORE_KEY`), as we no longer have `wc-blocks-checkout` as a dependency.
|
||||||
const CHECKOUT_STORE_KEY = 'wc/store/checkout';
|
const CHECKOUT_STORE_KEY = 'wc/store/checkout';
|
||||||
|
@ -31,11 +32,9 @@
|
||||||
* @param {Object} values Object containing field values.
|
* @param {Object} values Object containing field values.
|
||||||
*/
|
*/
|
||||||
function updateFormValues( values ) {
|
function updateFormValues( values ) {
|
||||||
// Update inputs if any exist.
|
// Update `<wc-order-attribution-inputs>` elements if any exist.
|
||||||
if( $( `input[name^="${params.prefix}"]` ) ) {
|
for( const element of document.querySelectorAll( 'wc-order-attribution-inputs' ) ) {
|
||||||
for( const key of Object.keys( wc_order_attribution.fields ) ) {
|
element.values = values;
|
||||||
$( `input[name="${params.prefix}${key}"]` ).value = values && values[ key ] || '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -105,15 +104,6 @@
|
||||||
// Run init.
|
// Run init.
|
||||||
wc_order_attribution.setOrderTracking( params.allowTracking );
|
wc_order_attribution.setOrderTracking( params.allowTracking );
|
||||||
|
|
||||||
// Wait for (async) classic checkout initialization and set source values once loaded.
|
|
||||||
if ( $( 'form.woocommerce-checkout' ) !== null ) {
|
|
||||||
const previousInitCheckout = document.body.oninit_checkout;
|
|
||||||
document.body.oninit_checkout = () => {
|
|
||||||
updateFormValues( getData() );
|
|
||||||
previousInitCheckout && previousInitCheckout();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Work around the lack of explicit script dependency for the checkout block.
|
// Work around the lack of explicit script dependency for the checkout block.
|
||||||
// Conditionally, wait for and use 'wp-data' & 'wc-blocks-checkout.
|
// Conditionally, wait for and use 'wp-data' & 'wc-blocks-checkout.
|
||||||
|
|
||||||
|
@ -136,4 +126,61 @@
|
||||||
eventuallyInitializeCheckoutBlock();
|
eventuallyInitializeCheckoutBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define an element to contribute order attribute values to the enclosing form.
|
||||||
|
* To be used with the classic checkout.
|
||||||
|
*/
|
||||||
|
window.customElements.define( 'wc-order-attribution-inputs', class extends HTMLElement {
|
||||||
|
// Our bundler version does not support private class members, so we use a convention of `_` prefix.
|
||||||
|
// #values
|
||||||
|
// #fieldNames
|
||||||
|
constructor(){
|
||||||
|
super();
|
||||||
|
// Cache fieldNames available at the construction time, to avoid malformed behavior if they change in runtime.
|
||||||
|
this._fieldNames = Object.keys( wc_order_attribution.fields );
|
||||||
|
// Allow values to be lazily set before CE upgrade.
|
||||||
|
if ( this.hasOwnProperty( '_values' ) ) {
|
||||||
|
let values = this.values;
|
||||||
|
// Restore the setter.
|
||||||
|
delete this.values;
|
||||||
|
this.values = values || {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Stamp input elements to the element's light DOM.
|
||||||
|
*
|
||||||
|
* We could use `.elementInternals.setFromValue` and avoid sprouting `<input>` elements,
|
||||||
|
* but it's not yet supported in Safari.
|
||||||
|
*/
|
||||||
|
connectedCallback() {
|
||||||
|
let inputs = '';
|
||||||
|
for( const fieldName of this._fieldNames ) {
|
||||||
|
const value = stringifyFalsyInputValue( this.values[ fieldName ] );
|
||||||
|
inputs += `<input type="hidden" name="${params.prefix}${fieldName}" value="${value}"/>`;
|
||||||
|
}
|
||||||
|
this.innerHTML = inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update form values.
|
||||||
|
*/
|
||||||
|
set values( values ) {
|
||||||
|
this._values = values;
|
||||||
|
if( this.isConnected ) {
|
||||||
|
for( const fieldName of this._fieldNames ) {
|
||||||
|
const input = this.querySelector( `input[name="${params.prefix}${fieldName}"]` );
|
||||||
|
if( input ) {
|
||||||
|
input.value = stringifyFalsyInputValue( this.values[ fieldName ] );
|
||||||
|
} else {
|
||||||
|
console.warn( `Field "${fieldName}" not found. Most likely, the '<wc-order-attribution-inputs>' element was manipulated.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get values() {
|
||||||
|
return this._values;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
}( window.wc_order_attribution ) );
|
}( window.wc_order_attribution ) );
|
||||||
|
|
|
@ -111,8 +111,8 @@ class OrderAttributionController implements RegisterHooksInterface {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
add_action( 'woocommerce_checkout_after_customer_details', array( $this, 'source_form_elements' ) );
|
add_action( 'woocommerce_checkout_after_customer_details', array( $this, 'stamp_html_element' ) );
|
||||||
add_action( 'woocommerce_register_form', array( $this, 'source_form_elements' ) );
|
add_action( 'woocommerce_register_form', array( $this, 'stamp_html_element' ) );
|
||||||
|
|
||||||
// Update order based on submitted fields.
|
// Update order based on submitted fields.
|
||||||
add_action(
|
add_action(
|
||||||
|
@ -342,14 +342,11 @@ class OrderAttributionController implements RegisterHooksInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print `<input type="hidden">` elements for source fields.
|
* Add `<wc-order-attribution-inputs>` element that contributes the order attribution values to the enclosing form.
|
||||||
* To be picked up and populated with data by the JS.
|
|
||||||
* Used for checkout & customer register forms.
|
* Used for checkout & customer register forms.
|
||||||
*/
|
*/
|
||||||
public function source_form_elements() {
|
public function stamp_html_element() {
|
||||||
foreach ( $this->field_names as $field_name ) {
|
printf( '<wc-order-attribution-inputs></wc-order-attribution-inputs>' );
|
||||||
printf( '<input type="hidden" name="%s" value="" />', esc_attr( $this->get_prefixed_field_name( $field_name ) ) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue