PageSourceSearch

https://blackparakeetztoo.com/wp-content/plugins/woocommerce/asset…/frontend/order-attribution.js?ver=11.2.0

js blackparakeetztoo.com collected 2026-10-08 08:10:00 UTC 7,357 bytes, 234 lines download raw bytes

1( function ( wc_order_attribution ) {
2	'use strict';
3	// Cache params reference for shorter reusability.
4	const params = wc_order_attribution.params;
5
6	// Helper functions.
7	const $ = document.querySelector.bind( document );
8	const propertyAccessor = ( obj, path ) => path.split( '.' ).reduce( ( acc, part ) => acc && acc[ part ], obj );
9	const returnNull = () => null;
10	const stringifyFalsyInputValue = ( value ) => value === null || value === undefined ? '' : value;
11
12	// Hardcode Checkout store key (`wc.wcBlocksData.CHECKOUT_STORE_KEY`), as we no longer have `wc-blocks-checkout` as a dependency.
13	const CHECKOUT_STORE_KEY = 'wc/store/checkout';
14
15	/**
16	 * Get the order attribution data.
17	 *
18	 * Returns object full of `null`s if tracking is disabled or if sourcebuster.js is blocked.
19	 *
20	 * @returns {Object} Schema compatible object.
21	 */
22	wc_order_attribution.getAttributionData = function() {
23		const accessor = params.allowTracking && isSbjsAvailable() ? propertyAccessor : returnNull;
24		const getter  = isSbjsAvailable() ? sbjs.get : {};
25		const entries = Object.entries( wc_order_attribution.fields )
26			.map( ( [ key, property ] ) => [ key, accessor( getter, property ) ] );
27		return Object.fromEntries( entries );
28	}
29
30	/**
31	 * Remove duplicate `<wc-order-attribution-inputs>` elements within each owning form to prevent
32	 * sending the same data multiple times. Treat groups without an enclosing form as document-owned.
33	 */
34	function removeDuplicateInputGroups() {
35		const owners = new Set();
36
37		document.querySelectorAll( 'wc-order-attribution-inputs' ).forEach( ( group ) => {
38			const owner = group.closest( 'form' ) || document;
39
40			if ( owners.has( owner ) ) {
41				group.remove();
42			} else {
43				owners.add( owner );
44			}
45		} );
46	}
47
48	/**
49	 * Update `wc_order_attribution` input elements' values.
50	 *
51	 * @param {Object} values Object containing field values.
52	 */
53	function updateFormValues( values ) {
54		// Remove duplicates before updating to ensure only one set of elements exists.
55		removeDuplicateInputGroups();
56		// Update `<wc-order-attribution-inputs>` elements if any exist.
57		for( const element of document.querySelectorAll( 'wc-order-attribution-inputs' ) ) {
58			element.values = values;
59		}
60
61	};
62
63	/**
64	 * Update Checkout extension data.
65	 *
66	 * @param {Object} values Object containing field values.
67	 */
68	function updateCheckoutBlockData( values ) {
69		// Update Checkout block data if available.
70		if (
71			window.wp &&
72			window.wp.data &&
73			window.wp.data.dispatch &&
74			window.wc &&
75			window.wc.wcBlocksData
76		) {
77			window.wp.data
78				.dispatch( window.wc.wcBlocksData.CHECKOUT_STORE_KEY )
79				.setExtensionData(
80					'woocommerce/order-attribution',
81					values,
82					true
83				);
84		}
85	}
86
87	/**
88	 * Determine whether sourcebuster.js is available.
89	 *
90	 * @returns {boolean} Whether sourcebuster.js is available.
91	 */
92	function isSbjsAvailable() {
93		return typeof sbjs !== 'undefined';
94	}
95
96	/**
97	 * Initialize sourcebuster & set data, or clear cookies & data.
98	 *
99	 * @param {boolean} allow Whether to allow tracking or disable it.
100	 */
101	wc_order_attribution.setOrderTracking = function( allow ) {
102		params.allowTracking = allow;
103		if ( ! allow ) {
104			// Reset cookies, and clear form data.
105			removeTrackingCookies();
106		} else if ( ! isSbjsAvailable() ) {
107			return; // Do nothing, as sourcebuster.js is not loaded.
108		} else {
109			// If not done yet, initialize sourcebuster.js which populates `sbjs.get` object.
110			sbjs.init( {
111				lifetime: Number( params.lifetime ),
112				session_length: Number( params.session ),
113				base64: Boolean( params.base64 ),
114				timezone_offset: '0', // utc
115			} );
116		}
117		const values = wc_order_attribution.getAttributionData();
118		updateFormValues( values );
119		updateCheckoutBlockData( values );
120	}
121
122	/**
123	 * Remove sourcebuster.js cookies.
124	 * To be called whenever tracking is disabled or consent is revoked.
125	 */
126	function removeTrackingCookies() {
127		const domain = window.location.hostname;
128		const sbCookies = [
129			'sbjs_current',
130			'sbjs_current_add',
131			'sbjs_first',
132			'sbjs_first_add',
133			'sbjs_session',
134			'sbjs_udata',
135			'sbjs_migrations',
136			'sbjs_promo'
137		];
138
139		// Remove cookies
140		sbCookies.forEach( ( name ) => {
141			document.cookie = `${name}=; path=/; max-age=-999; domain=.${domain};`;
142		} );
143	}
144
145	// Run init.
146	wc_order_attribution.setOrderTracking( params.allowTracking );
147
148	// Work around the lack of explicit script dependency for the checkout block.
149	// Conditionally, wait for and use 'wp-data' & 'wc-blocks-checkout.
150
151	// Wait for (async) block checkout initialization and set source values once loaded.
152	function eventuallyInitializeCheckoutBlock() {
153		if (
154			window.wp && window.wp.data && typeof window.wp.data.subscribe === 'function'
155		) {
156			// Update checkout block data once more if the checkout store was loaded after this script.
157			const unsubscribe = window.wp.data.subscribe( function () {
158				unsubscribe();
159				updateCheckoutBlockData( wc_order_attribution.getAttributionData() );
160			}, CHECKOUT_STORE_KEY );
161		}
162	};
163	// Wait for DOMContentLoaded to make sure wp.data is in place, if applicable for the page.
164	if (document.readyState === "loading") {
165		document.addEventListener("DOMContentLoaded", eventuallyInitializeCheckoutBlock);
166	} else {
167		eventuallyInitializeCheckoutBlock();
168	}
169
170	/**
171	 * Define an element to contribute order attribute values to the enclosing form.
172	 * To be used with the classic checkout.
173	 */
174	window.customElements.define( 'wc-order-attribution-inputs', class extends HTMLElement {
175		// Our bundler version does not support private class members, so we use a convention of `_` prefix.
176		// #values
177		// #fieldNames
178		constructor(){
179			super();
180			// Cache fieldNames available at the construction time, to avoid malformed behavior if they change in runtime.
181			this._fieldNames = Object.keys( wc_order_attribution.fields );
182			// Allow values to be lazily set before CE upgrade.
183			if ( this.hasOwnProperty( '_values' ) ) {
184				let values = this.values;
185				// Restore the setter.
186				delete this.values;
187				this.values = values || {};
188			}
189		}
190		/**
191		 * Stamp input elements to the element's light DOM.
192		 *
193		 * We could use `.elementInternals.setFromValue` and avoid sprouting `<input>` elements,
194		 * but it's not yet supported in Safari.
195		 */
196		connectedCallback() {
197			this.innerHTML = '';
198			const inputs = new DocumentFragment();
199			for( const fieldName of this._fieldNames ) {
200				const input = document.createElement( 'input' );
201				input.type = 'hidden';
202				input.name = `${params.prefix}${fieldName}`;
203				input.value = stringifyFalsyInputValue( ( this.values && this.values[ fieldName ] ) || '' );
204				inputs.appendChild( input );
205			}
206			this.appendChild( inputs );
207		}
208
209		/**
210		 * Update form values.
211		 */
212		set values( values ) {
213			this._values = values;
214			if( this.isConnected ) {
215				for( const fieldName of this._fieldNames ) {
216					const input = this.querySelector( `input[name="${params.prefix}${fieldName}"]` );
217					if( input ) {
218						input.value = stringifyFalsyInputValue( this.values[ fieldName ] );
219					} else {
220						console.warn(
221							`Field "${fieldName}" not found. ` +
222							`Most likely, the '<wc-order-attribution-inputs>' element was manipulated.`
223						);
224					}
225				}
226			}
227		}
228		get values() {
229			return this._values;
230		}
231	} );
232
233
234}( window.wc_order_attribution ) );

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.