PageSourceSearch

https://www.iskreni.net/trgovina/wp-content/plugins/klaviyo/includes/js/wck-started-checkout.js?ver=3.8.3

js iskreni.net collected 2026-10-02 07:11:04 UTC 9,308 bytes, 285 lines download raw bytes

1/**
2 * WCK Started Checkout
3 *
4 * Incoming event object
5 * @typedef {object} kl_checkout
6 *   @property {string} email - Email of current logged in user
7 *
8 *   @property {object} event_data - Data for started checkout event
9 *     @property {object} $extra - Event data
10 *     @property {string} $service - Value will always be "woocommerce"
11 *     @property {int} value - Total value of checkout event
12 *     @property {array} Categories - Product categories (array of strings)
13 *     @property {string} Currency - Currency type
14 *     @property {string} CurrencySymbol - Currency type symbol
15 *     @property {array} ItemNames - List of items in the cart
16 *
17 */
18
19
20/**
21 * Attach event listeners to save billing fields.
22 */
23
24// Constants for the klaviyo api url prefix and revision
25const KLAVIYO_API_URL_PREFIX = 'https://a.klaviyo.com/';
26const KLAVIYO_API_REVISION = '2026-04-15';
27
28var identify_object = {
29  'company_id': public_key.token,
30  'properties': {}
31};
32
33var klaviyo_cookie_id = '__kla_id';
34
35function buildProfileRequestPayload(event_attributes) {
36  const topLevelAttributes = ['email', 'first_name', 'last_name'];
37
38  // Destructure event_attributes:
39  // - properties: gets the properties object from event_attributes, defaulting to empty object if not present
40  // - restAttributes: gets all other fields from event_attributes using the rest operator (...)
41  const { properties = {}, ...restAttributes } = event_attributes || {};
42
43  // Create a new object for the filtered properties to avoid mutating the original input
44  const filteredProperties = { ...properties };
45  const dataAttributes = { ...restAttributes };
46
47  // Move top level attributes from properties to data level
48  topLevelAttributes.forEach(field => {
49    if (filteredProperties[field] !== undefined) {
50      dataAttributes[field] = filteredProperties[field];
51      delete filteredProperties[field];
52    }
53  });
54
55  // Add the filtered properties back to dataAttributes
56  dataAttributes.properties = filteredProperties;
57
58  return JSON.stringify({
59    data: {
60      type: "profile",
61      attributes: dataAttributes
62    }
63  })
64}
65
66function buildEventRequestPayload(customer_properties, event_properties, metric_attributes) {
67  return JSON.stringify({
68    data: {
69      type: 'event',
70      attributes: {
71        properties: {
72          ...event_properties,
73        },
74        metric: {
75        data: {
76          type: 'metric',
77          attributes: {
78            ...metric_attributes,
79          }
80        }
81      },
82      profile: {
83        data: {
84          type: 'profile',
85          attributes: {
86            ...customer_properties,
87          }
88        }
89      }
90      }
91    }
92  })
93}
94
95function makePublicAPIcall(endpoint, event_data) {
96  var company_id = public_key.token;
97  jQuery.ajax(KLAVIYO_API_URL_PREFIX + endpoint + '?company_id=' + company_id, {
98    type: "POST",
99    contentType: "application/json",
100    data: event_data,
101    headers: {
102      'revision': KLAVIYO_API_REVISION,
103      'X-Klaviyo-User-Agent': plugin_meta_data.data,
104    }
105  });
106}
107
108function decodeKlaviyoCookieData(cookie) {
109  var name = klaviyo_cookie_id + "=";
110  var decodedCookie = decodeURIComponent(cookie);
111  var ca = decodedCookie.split(';');
112  for (var i = 0; i < ca.length; i++) {
113    var c = ca[i];
114    while (c.charAt(0) == ' ') {
115      c = c.substring(1);
116    }
117    if (c.indexOf(name) == 0) {
118      return decodeURIComponent(atob(c.substring(name.length, c.length)));
119    }
120  }
121  return "";
122}
123
124function getKlaviyoCookie() {
125  return decodeKlaviyoCookieData(document.cookie);
126}
127
128function encodeKlaviyoCookieData(cookie_data) {
129  return btoa(encodeURIComponent(JSON.stringify(cookie_data)));
130}
131
132function setKlaviyoCookie(cookie_data) {
133  // Get existing cookie data
134  const existingCookieData = getKlaviyoCookie();
135  let mergedData = {};
136
137  // If we have existing data, parse it and merge with new data
138  if (existingCookieData) {
139    try {
140      const parsedExistingData = typeof existingCookieData === 'string' ?
141        JSON.parse(existingCookieData) : existingCookieData;
142      mergedData = { ...parsedExistingData, ...cookie_data };
143    } catch (e) {
144      // If parsing fails, just use the new data
145      mergedData = cookie_data;
146    }
147  } else {
148    mergedData = cookie_data;
149  }
150
151  const cvalue = encodeKlaviyoCookieData(mergedData);
152  const date = new Date();
153  date.setTime(date.getTime() + (63072e6)); // adding 2 years in milliseconds to current time
154  const expires = "expires=" + date.toUTCString();
155  document.cookie = klaviyo_cookie_id + "=" + cvalue + ";" + expires + "; path=/";
156}
157
158  /**
159   * Queries the dom for first_name, last_name, and email inputs being displayed on the checkout page.
160   * If both shipping and billing forms are present, both input nodes will be returned for the type (ie. first_name)
161   * @return {object} an object of dom nodes (firstNameNode, lastNameNode, emailNode)
162   */
163function getTrackingNodes() {
164  var emailNodes = jQuery('input[id*="email"]:visible, input[name*="email"]:visible');
165  var firstNameNodes = jQuery('input[id*="first_name"]:visible, input[name*="first_name"]:visible');
166  var lastNameNodes = jQuery('input[id*="last_name"]:visible, input[name*="last_name"]:visible');
167
168  return { firstNameNodes, lastNameNodes, emailNodes};
169}
170
171/**
172 * The event listener to be added to visible email, first_name, and last_name nodes.
173 * It makes a call to client/profile with the values from the email field and either
174 * the first_name or last_name value depending on the caller
175 * @return {undefined}
176 */
177function identifyUser(nameType, self) {
178  var { emailNodes } = getTrackingNodes();
179  var email = emailNodes.val();
180  var identify_properties = {
181    [nameType]: jQuery.trim(jQuery(self).val())
182  }
183  if (email) {
184    identify_properties["email"] = email;
185    setKlaviyoCookie(identify_properties);
186    identify_object.properties = identify_properties;
187    makePublicAPIcall('client/profiles/', buildProfileRequestPayload(identify_object));
188  }
189}
190
191/**
192 * Adds the event listeners for tracking on the first name and last name inputs.
193 * If both the shipping and billing forms are visible, listeners will be added to all first name and last name nodes
194 * @return {undefined}
195 */
196function klIdentifyBillingField() {
197  var { firstNameNodes, lastNameNodes } = getTrackingNodes();
198  firstNameNodes.each(function(){
199    var node = jQuery(this);
200    node.change(() => identifyUser("first_name", node));
201  });
202  lastNameNodes.each(function(){
203    var node = jQuery(this);
204    node.change(() => identifyUser("last_name", node));
205  });
206}
207
208window.addEventListener("load", function () {
209  // Custom checkouts/payment platforms may still load this file but won't
210  // fire woocommerce_after_checkout_form hook to load checkout data.
211  if (typeof kl_checkout === 'undefined') {
212    return;
213  }
214
215  var WCK = WCK || {};
216  WCK.trackStartedCheckout = function () {
217    var metric_attributes = {
218      'name': 'Started Checkout',
219      'service': 'woocommerce'
220    }
221    var customer_properties = {}
222    if (kl_checkout.email) {
223      customer_properties['email'] = kl_checkout.email;
224      // Identify user once we have an email. This will trigger AVAB if enabled.
225      klaviyo.identify(customer_properties);
226    } else if (kl_checkout.exchange_id) {
227      // Klaviyo use is already identified if we have an exchange ID.
228      customer_properties['_kx'] = kl_checkout.exchange_id;
229    } else {
230      return;
231    }
232
233    makePublicAPIcall('client/events/', buildEventRequestPayload(customer_properties, kl_checkout.event_data, metric_attributes));
234  };
235
236  var klCookie = getKlaviyoCookie();
237
238  // Priority of emails for syncing Started Checkout event: Logged-in user,
239  // cookied exchange ID, cookied email, billing email address
240  if (kl_checkout.email !== "") {
241    identify_object.properties = {
242      'email': kl_checkout.email
243    };
244    makePublicAPIcall('client/profiles/', buildProfileRequestPayload(identify_object));
245    setKlaviyoCookie(identify_object.properties);
246    WCK.trackStartedCheckout();
247  } else if (klCookie && JSON.parse(klCookie).$exchange_id !== undefined) {
248    kl_checkout.exchange_id = JSON.parse(klCookie).$exchange_id;
249    WCK.trackStartedCheckout();
250  } else if (klCookie && JSON.parse(klCookie).email !== undefined) {
251    kl_checkout.email = JSON.parse(klCookie).email;
252    WCK.trackStartedCheckout();
253  } else {
254    if (jQuery) {
255      var { firstNameNodes, lastNameNodes, emailNodes } = getTrackingNodes();
256      emailNodes.change(function () {
257        var elem = jQuery(this),
258          email = jQuery.trim(elem.val());
259
260        if (email && /@/.test(email)) {
261          var params = {
262            "email": email
263          };
264
265          if (firstNameNodes.length > 0) {
266            // Values come from first visible input node in the DOM
267            params["first_name"] = firstNameNodes.val();
268          }
269          if (lastNameNodes.length > 0) {
270            params["last_name"] = lastNameNodes.val();
271          }
272
273          setKlaviyoCookie(params);
274          kl_checkout.email = params.email;
275          identify_object.properties = params;
276          makePublicAPIcall('client/profiles/', buildProfileRequestPayload((identify_object)));
277          WCK.trackStartedCheckout();
278        }
279      });
280
281      // Save billing fields
282      klIdentifyBillingField();
283    }
284  }
285});

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.