*/ (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
The Tailor Game feat. Rich Freshman

The Tailor Game feat. Rich Freshman

Meet my new friend Rich Freshman, West Hollywood tailor and clothier. Growing up in Memphis, he learned the value of dressing like a gentleman early in life.

"I taught myself to sew at 13 because of a crush I had on this girl. I was a kind of geeky kid, and i didn’t dress very well. From my middle-school observations I figured the easiest way to get her attention, and the attention of other pretty girls, was to: 1) become an athlete, 2) become an asshole, or 3) learn how to dress better than my competition. Athletics weren’t my thing, and I was a really nice and shy kid, so being a jerk to women was out. I chose fashion and although things never worked out with my crush, I fell in love with menswear and tailoring.

That summer I was definitely my school's 'most improved' in the fashion department. I went from knowing zero about fashion at 13 to being a student of Ralph Lauren and Brooks Brothers. I never wanted to be like Mike - I wanted to be like Ralph. I wanted to study architecture growing up, but fashion became my breakfast, lunch, and dinner. I found power and gained confidence from it. In a way this is my architecture. I design menswear, take measurements, draft patterns, create finished structures, and modify them as needed."

Two things you need to know about Rich. 1) He often wears a (color coordinated) measuring tape as an accessory with his sharply tailored outfits. It's a genius marketing play that has brought him some significant business. 2) He makes suits, but rarely wears them. He prefers the added creativity of separates.

Here, he shares his story and shows us the art of the double-breasted blazer.

1. Colorful Cord

"I don’t recall wanting to be a kid, really. I’ve always wanted to be an adult and to be treated as such. My dad was a pharmaceutical rep in the 90s... He was pretty fly and I observed how well people treated him, and how much they respected him. I wanted that identity.

I skipped over the baggy jeans and Jordans and went straight to polos, drivers, chinos, cable knits, etc. I was a broke kid, but I would save up and find good sales at Brooks Brothers… It would trip the sales staff out, I think, because here’s a 15 year-old black teen shopping with middle-aged white executive types. I can still recall the level of respect they showed me once they saw how serious I was. That’s what made me want to do this even more."

"I’ve always enjoyed color and pattern-mixing. I don’t do the over-the- top bedazzled stuff, but I'lll take a teal jacket, mix it with a muted-brown glen plaid trouser, and balance it off with a cognac shoe."

2. Fresh Fall Salmon

"After a year of studying architecture in Memphis, I dropped out to start my first tailoring business. It was an alteration outsourcing company. I would drive all over the city picking-up alterations from local dry cleaners, take them back to my loft, do the tailoring, and then take them to back to the cleaners. Eventually, the business grew, and the following year I opened a tailoring storefront in downtown Memphis.

I spent my off days hanging out with and assisting other tailors, trying to hone my craft. I’m a big believer in modeling. If you find someone with skillsets or traits that you admire, spend some time learning from them…  My buddy from high school introduced me to the tailor who would ultimately become my mentor; Michael C Thomas.

He was in his 30s when i was in my 20s, you know. He was young, he was cool, and he had impeccable style. His shop became a regular spot and he’s served as a mentor ever since."

"When my brother, my daughter, and I moved out to San Diego in 2010, I saw a void in mens’ style - especially tailored-wear. I recognized an opportunity to create what i felt was missing. So I developed my own aesthetic and shifted from alterations to made-to-measure. This was the natural course of my evolution as a tailor, I think.

Now, I’m here in LA trying to make my mark in the industry and, like Dan, trying to show the world that tailoring is cool again, baby! And this is what it looks like for us."

As a traveling tailor, Rich scores some points in my book for keeping his fabric swatches and measuring tools in vintage suitcases. More on that later...

3. Windowpane Jacketing

"My clients in LA vary. I have male clients and female clients. From young talent managers to established Grammy winners. The common denominator is that they all wanted to improve their image at some point. Even the clients who initially weren’t very style conscious have become impeccably dressed men and women... It makes me proud.

My typical aesthetic is very clean, British, and inspired by 40s Americana. Think Vegas, Sinatra, Palm Springs. It’s clean and sexy, but it pops."

"Regarding what to look for in a clothier, treat it the same as if you were looking for a personal trainer. If my goal is to get jacked, i’m not going to look for the slim yoga trainer. I’m going for the biggest trainer available. I want the guy who is better than me and has the results I’m looking to achieve.

If you want a very conservative corporate style, find a conservative tailor/clothier. If you want to hit the red carpet circuit and grab attention, find a tailor who specializes in that. Ultimately, it's a relationship business and you want to make sure that your interests are aligned."

Thanks, as always, for reading and special thanks to Rich for participating!

Yours in style,

Dan