*/ (function() { 'use strict'; const CONFIG = { storageKey: 'aos_utm_data', storageDuration: 30, // days utmParams: ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'], // Shopify attribution mapping shopifyFields: { utm_source: 'source', utm_medium: 'medium', utm_campaign: 'campaign', utm_content: 'content', utm_term: 'term', landing_page: 'landing_site', referrer: 'referring_site' } }; // ============================================ // STEP 1: CAPTURE & STORE UTM PARAMETERS // ============================================ function captureUTMFromURL() { const params = new URLSearchParams(window.location.search); const utmData = {}; let hasUTM = false; CONFIG.utmParams.forEach(param => { if (params.has(param)) { utmData[param] = params.get(param); hasUTM = true; } }); return hasUTM ? utmData : null; } function getStoredUTMData() { try { const stored = localStorage.getItem(CONFIG.storageKey); if (stored) { const data = JSON.parse(stored); // Check if data is still valid (within duration) const timestamp = data.timestamp || 0; const now = Date.now(); const maxAge = CONFIG.storageDuration * 24 * 60 * 60 * 1000; if (now - timestamp < maxAge) { return data; } } } catch (e) { console.error('Error reading UTM data:', e); } return null; } function saveUTMData(utmData) { try { const dataToStore = { ...utmData, timestamp: Date.now(), landing_page: utmData.landing_page || window.location.href, referrer: utmData.referrer || document.referrer || 'direct' }; localStorage.setItem(CONFIG.storageKey, JSON.stringify(dataToStore)); // Also set as cookie for server-side access setCookie(CONFIG.storageKey, JSON.stringify(dataToStore), CONFIG.storageDuration); console.log('UTM data saved:', dataToStore); return dataToStore; } catch (e) { console.error('Error saving UTM data:', e); return null; } } function setCookie(name, value, days) { const date = new Date(); date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); const expires = "expires=" + date.toUTCString(); document.cookie = name + "=" + encodeURIComponent(value) + ";" + expires + ";path=/;SameSite=Lax"; } // ============================================ // STEP 2: MANAGE UTM DATA (NEW OR STORED) // ============================================ function initializeUTMTracking() { // Check for new UTM parameters in current URL const newUTM = captureUTMFromURL(); if (newUTM) { // New UTM found - overwrite stored data console.log('New UTM parameters detected, updating storage'); return saveUTMData({ ...newUTM, landing_page: window.location.href, referrer: document.referrer || 'direct' }); } else { // No new UTM - get stored data const storedUTM = getStoredUTMData(); if (!storedUTM) { // First visit, no UTM - save as direct traffic console.log('First visit without UTM, marking as direct'); return saveUTMData({ utm_source: 'direct', utm_medium: 'none', landing_page: window.location.href, referrer: document.referrer || 'direct' }); } console.log('Using stored UTM data:', storedUTM); return storedUTM; } } // ============================================ // STEP 3: AUTO-APPEND UTM TO INTERNAL LINKS // ============================================ function appendUTMToURL(url, utmData) { try { const urlObj = new URL(url, window.location.origin); // Only add UTM if not already present CONFIG.utmParams.forEach(param => { if (utmData[param] && !urlObj.searchParams.has(param)) { urlObj.searchParams.set(param, utmData[param]); } }); return urlObj.toString(); } catch (e) { return url; // Return original if parsing fails } } function isInternalLink(url) { try { const urlObj = new URL(url, window.location.origin); return urlObj.hostname === window.location.hostname; } catch (e) { // Relative URLs are internal return !url.startsWith('http://') && !url.startsWith('https://'); } } function hasUTMParameters(url) { try { const urlObj = new URL(url, window.location.origin); return CONFIG.utmParams.some(param => urlObj.searchParams.has(param)); } catch (e) { return false; } } function addUTMToInternalLinks(utmData) { if (!utmData) return; // Function to update a single link function updateLink(link) { const href = link.getAttribute('href'); if (!href || href === '#' || href.startsWith('javascript:') || href.startsWith('mailto:') || href.startsWith('tel:')) { return; } // Only update internal links without UTM if (isInternalLink(href) && !hasUTMParameters(href)) { const newHref = appendUTMToURL(href, utmData); link.setAttribute('href', newHref); } } // Update all existing links document.querySelectorAll('a[href]').forEach(updateLink); // Watch for dynamically added links const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.nodeType === 1) { // Element node if (node.tagName === 'A' && node.hasAttribute('href')) { updateLink(node); } // Also check children node.querySelectorAll && node.querySelectorAll('a[href]').forEach(updateLink); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); } // ============================================ // STEP 4: SEND TO SHOPIFY ATTRIBUTION // ============================================ function sendToShopifyAttribution(utmData) { if (!utmData) return; // Method 1: Use Shopify's analytics tracking if (window.ShopifyAnalytics && window.ShopifyAnalytics.lib) { try { const attributionData = {}; Object.keys(CONFIG.shopifyFields).forEach(key => { const shopifyField = CONFIG.shopifyFields[key]; if (utmData[key]) { attributionData[shopifyField] = utmData[key]; } }); // Set landing site if (utmData.landing_page) { attributionData.landing_site = utmData.landing_page; } // Set referring site if (utmData.referrer && utmData.referrer !== 'direct') { attributionData.referring_site = utmData.referrer; } console.log('Sending to Shopify Analytics:', attributionData); // This sets the attribution data for the session if (window.ShopifyAnalytics.lib.config) { window.ShopifyAnalytics.lib.config.Attribution = attributionData; } } catch (e) { console.error('Error setting Shopify attribution:', e); } } // Method 2: Add to checkout attributes (for order-level tracking) addToCheckoutAttributes(utmData); // Method 3: Add to cart note attributes addToCartAttributes(utmData); } function addToCheckoutAttributes(utmData) { // This will be picked up during checkout window._shopifyCheckoutAttributes = window._shopifyCheckoutAttributes || {}; CONFIG.utmParams.forEach(param => { if (utmData[param]) { window._shopifyCheckoutAttributes[param] = utmData[param]; } }); if (utmData.landing_page) { window._shopifyCheckoutAttributes['landing_page'] = utmData.landing_page; } if (utmData.referrer) { window._shopifyCheckoutAttributes['referrer'] = utmData.referrer; } } function addToCartAttributes(utmData) { // Hook into cart form submissions document.addEventListener('submit', function(e) { const form = e.target; // Check if it's a cart form if (form.action && (form.action.includes('/cart/add') || form.action.includes('/cart'))) { // Add hidden fields for UTM data CONFIG.utmParams.forEach(param => { if (utmData[param]) { addHiddenField(form, `attributes[${param}]`, utmData[param]); } }); if (utmData.landing_page) { addHiddenField(form, 'attributes[landing_page]', utmData.landing_page); } if (utmData.referrer) { addHiddenField(form, 'attributes[referrer]', utmData.referrer); } } }); } function addHiddenField(form, name, value) { // Check if field already exists let field = form.querySelector(`input[name="${name}"]`); if (!field) { field = document.createElement('input'); field.type = 'hidden'; field.name = name; form.appendChild(field); } field.value = value; } // ============================================ // STEP 5: AJAX CART HANDLING // ============================================ function interceptAjaxCalls(utmData) { // Intercept fetch calls const originalFetch = window.fetch; window.fetch = function(...args) { let [url, options] = args; if (typeof url === 'string' && url.includes('/cart/add')) { options = options || {}; // Add UTM data to body if it's a POST request if (options.method === 'POST' || !options.method) { try { const body = options.body ? JSON.parse(options.body) : {}; body.attributes = body.attributes || {}; CONFIG.utmParams.forEach(param => { if (utmData[param]) { body.attributes[param] = utmData[param]; } }); if (utmData.landing_page) body.attributes.landing_page = utmData.landing_page; if (utmData.referrer) body.attributes.referrer = utmData.referrer; options.body = JSON.stringify(body); } catch (e) { console.error('Error adding UTM to fetch:', e); } } } return originalFetch.apply(this, [url, options]); }; // Intercept jQuery AJAX if jQuery is loaded if (window.jQuery) { const originalAjax = jQuery.ajax; jQuery.ajax = function(url, options) { if (typeof url === 'object') { options = url; url = options.url; } if (url && url.includes('/cart/add')) { options.data = options.data || {}; if (typeof options.data === 'object') { options.data.attributes = options.data.attributes || {}; CONFIG.utmParams.forEach(param => { if (utmData[param]) { options.data.attributes[param] = utmData[param]; } }); if (utmData.landing_page) options.data.attributes.landing_page = utmData.landing_page; if (utmData.referrer) options.data.attributes.referrer = utmData.referrer; } } return originalAjax.call(this, url, options); }; } } // ============================================ // STEP 6: INITIALIZE EVERYTHING // ============================================ function init() { console.log('Initializing UTM Tracking System...'); // Initialize UTM tracking (capture new or get stored) const utmData = initializeUTMTracking(); if (utmData) { // Add UTM to all internal links if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => addUTMToInternalLinks(utmData)); } else { addUTMToInternalLinks(utmData); } // Send to Shopify attribution sendToShopifyAttribution(utmData); // Intercept AJAX cart calls interceptAjaxCalls(utmData); console.log('UTM Tracking System initialized successfully'); } } // Start the tracking system init(); // Expose utility function to get current UTM data window.getUTMData = function() { return getStoredUTMData(); }; // Expose function to manually clear UTM data window.clearUTMData = function() { localStorage.removeItem(CONFIG.storageKey); console.log('UTM data cleared'); }; })(); Skip to Main Content
Articles of Style Customer Review: Jordan Shallow

Articles of Style Customer Review: Jordan Shallow

For performance coach and educator Jordan Shallow, the uniform has always been simple: gym clothes, sneakers, elastic waistbands—function over fashion. So when he shows up in a tailored suit, people notice.

 


Look Good. No Guesswork.

“It’s either something serious is happening, or someone’s dead,” he jokes. “But the comments are always the same—*‘Wow, you’re not in gym clothes’—and, ‘Wow, that suit is amazing.’”

That’s exactly why Jordan turned to Articles of Style: not to reinvent his style, but to remove the mental load from the moments when he does need to dress up.

A man in a suit and long coat stands confidently against a gray background.

“I don’t want to think about what I’m wearing,” he says. “A capsule wardrobe solves that.”

Man with a beard sitting on a chair, wearing black athletic clothing.

At Articles of Style, we designed a custom capsule for Jordan with timeless, versatile pieces he can wear confidently for client meetings, seminars, or speaking engagements—without sacrificing comfort or ease.

Because when your job demands your full focus, your wardrobe shouldn’t.

See Jordan's Full Capsule

A collection of various coats, shirts, and trousers hanging on hangers.
Collage of a man in various outfits and poses against a neutral background.

Click here to view the Smart Muscle Capsule.

SHOP THE CAPSULE


READY TO UPGRADE YOUR WARDROBE?

Book the Capsule Wardrobe Experience.

I look forward to working with you!

Yours in style,

Dan Trepanier


MORE FROM ARTICLES OF STYLE: