Skip to content

Commit

Permalink
Define custom element for order-attribution
Browse files Browse the repository at this point in the history
to move DOM manipulations  to JS only.
To support multiple checkout & register forms on the same page.

Addresses #44159
  • Loading branch information
tomalec committed Feb 2, 2024
1 parent ca8a6aa commit dd706e9
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 22 deletions.
71 changes: 57 additions & 14 deletions plugins/woocommerce/client/legacy/js/frontend/order-attribution.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,9 @@
* @param {Object} values Object containing field values.
*/
function updateFormValues( values ) {
// Update inputs if any exist.
if( $( `input[name^="${params.prefix}"]` ) ) {
for( const key of Object.keys( wc_order_attribution.fields ) ) {
$( `input[name="${params.prefix}${key}"]` ).value = values && values[ key ] || '';
}
// Update `<wc-order-attribution-input>` elements if any exist.
for( const element of document.querySelectorAll( 'wc-order-attribution-input' ) ) {
element.values = values;
}

};
Expand Down Expand Up @@ -105,15 +103,6 @@
// Run init.
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.
// Conditionally, wait for and use 'wp-data' & 'wc-blocks-checkout.

Expand All @@ -136,4 +125,58 @@
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-input', class extends HTMLElement {
// Our bundler version does not support private class members, so we use a convention od `_` prefix.
// #values
// #fields
constructor(){
super();
// Cache fields available at the construction time, to avoid malformed behavior if they change in runtime.
this._fields = wc_order_attribution.fields;
// Allow values to be lazily set before CE upgrade.
if ( this.hasOwnProperty( '_values' ) ) {
let value = this.values;
// Restore the setter.
delete this.values;
this.values = value;
}
}
/**
* 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._fields ) {
inputs += `<input type="hidden" name="${params.prefix}${fieldName}" value=""/>`;
}
this.innerHTML = inputs;
this.values = this.values;
}

/**
* Update form values.
*/
set values( values ) {
this._values = values;
for( const fieldName of this._fields ) {
const input = this.querySelector( `input[name="${params.prefix}${fieldName}"]` );
if( input ) {
input.value = values && values[ fieldName ] || "";
} else {
console.warn( `Field "${fieldName}" not found. Most likely, the '<wc-order-attribution-input>' element was manipulated.`);
}
}
}
get values() {
return this._values;
}
} );

}( window.wc_order_attribution ) );
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ function() {
}
);

add_action( 'woocommerce_checkout_after_customer_details', array( $this, 'source_form_elements' ) );
add_action( 'woocommerce_register_form', array( $this, 'source_form_elements' ) );
add_action( 'woocommerce_checkout_after_customer_detailss', array( $this, 'stamp_html_element' ) );
add_action( 'woocommerce_register_form', array( $this, 'stamp_html_element' ) );

// Update order based on submitted fields.
add_action(
Expand Down Expand Up @@ -330,14 +330,11 @@ private function output_origin_column( WC_Order $order ) {
}

/**
* Print `<input type="hidden">` elements for source fields.
* To be picked up and populated with data by the JS.
* Add `<wc-order-attribution-input>` element that contributes the order attribution values to the enclosing form.
* Used for checkout & customer register forms.
*/
public function source_form_elements() {
foreach ( $this->field_names as $field_name ) {
printf( '<input type="hidden" name="%s" value="" />', esc_attr( $this->get_prefixed_field_name( $field_name ) ) );
}
public function stamp_html_element() {
printf( '<wc-order-attribution-input></wc-order-attribution-input>' );
}

/**
Expand Down

0 comments on commit dd706e9

Please sign in to comment.