| 1 |
/** |
| 2 |
* Checkout ACF Extra Fields widget behaviour. |
| 3 |
* |
| 4 |
* The fields have to be inside WooCommerce's checkout form to be sent with |
| 5 |
* the order. When this widget renders before the Checkout Form widget, PHP |
| 6 |
* prints them into the form directly. When it renders after it, the form is |
| 7 |
* already on the page, so PHP hands the block over in a hidden carrier and |
| 8 |
* this script moves it to the spot the Placement control names. |
| 9 |
*/ |
| 10 |
(function () { |
| 11 |
'use strict'; |
| 12 |
|
| 13 |
// Mirrors the WooCommerce hooks the PHP side prints from. |
| 14 |
const TARGETS = { |
| 15 |
before_billing: ['.woocommerce-billing-fields__field-wrapper', 'before'], |
| 16 |
after_billing: ['.woocommerce-billing-fields__field-wrapper', 'after'], |
| 17 |
// Woo hides .shipping_address until “ship to a different address” is |
| 18 |
// checked. Placing inside that box made Before/After shipping a no-op. |
| 19 |
before_shipping: ['.shipping_address', 'before'], |
| 20 |
after_shipping: ['.shipping_address', 'after'], |
| 21 |
before_order: ['.woocommerce-additional-fields', 'prepend'], |
| 22 |
after_order: ['.woocommerce-additional-fields', 'append'], |
| 23 |
}; |
| 24 |
|
| 25 |
const insert = (block, anchor, mode) => { |
| 26 |
if ('before' === mode) { |
| 27 |
anchor.parentNode.insertBefore(block, anchor); |
| 28 |
} else if ('after' === mode) { |
| 29 |
anchor.parentNode.insertBefore(block, anchor.nextSibling); |
| 30 |
} else if ('prepend' === mode) { |
| 31 |
anchor.insertBefore(block, anchor.firstChild); |
| 32 |
} else { |
| 33 |
anchor.appendChild(block); |
| 34 |
} |
| 35 |
}; |
| 36 |
|
| 37 |
const place = () => { |
| 38 |
const carriers = document.querySelectorAll('.ka-woo-checkout-acf-fields-carrier'); |
| 39 |
if (!carriers.length) { |
| 40 |
return; |
| 41 |
} |
| 42 |
|
| 43 |
const form = document.querySelector('form.woocommerce-checkout, form.checkout[name="checkout"]'); |
| 44 |
if (!form) { |
| 45 |
return; |
| 46 |
} |
| 47 |
|
| 48 |
carriers.forEach((carrier) => { |
| 49 |
const block = carrier.firstElementChild; |
| 50 |
if (!block) { |
| 51 |
carrier.remove(); |
| 52 |
return; |
| 53 |
} |
| 54 |
|
| 55 |
const [selector, mode] = TARGETS[carrier.getAttribute('data-ka-acf-placement')] || TARGETS.after_order; |
| 56 |
const anchor = form.querySelector(selector); |
| 57 |
|
| 58 |
if (anchor) { |
| 59 |
insert(block, anchor, mode); |
| 60 |
} else { |
| 61 |
// A layout without that section: keep the fields in the form. |
| 62 |
insert(block, form.querySelector('.woocommerce-additional-fields') || form.querySelector('#customer_details') || form, 'append'); |
| 63 |
} |
| 64 |
|
| 65 |
carrier.remove(); |
| 66 |
}); |
| 67 |
|
| 68 |
// PHP can print the same block on woocommerce_before/after_checkout_shipping_form, |
| 69 |
// which WooCommerce fires inside the hidden .shipping_address. Lift it |
| 70 |
// to a sibling so Before/After shipping stays visible. |
| 71 |
document.querySelectorAll('.shipping_address .ka-woo-checkout-acf-fields').forEach((block) => { |
| 72 |
const addr = block.closest('.shipping_address'); |
| 73 |
if (!addr || !addr.parentNode) { |
| 74 |
return; |
| 75 |
} |
| 76 |
if ('after_shipping' === block.getAttribute('data-ka-acf-placement')) { |
| 77 |
addr.parentNode.insertBefore(block, addr.nextSibling); |
| 78 |
} else { |
| 79 |
addr.parentNode.insertBefore(block, addr); |
| 80 |
} |
| 81 |
}); |
| 82 |
}; |
| 83 |
|
| 84 |
if ('loading' === document.readyState) { |
| 85 |
document.addEventListener('DOMContentLoaded', place); |
| 86 |
} else { |
| 87 |
place(); |
| 88 |
} |
| 89 |
})(); |
| 90 |
|