Skip to content

News

Page 58

only on pages that render a form AND is deferred // by Rocket's Delay JS, so it missed both cross-page attribution and // utm_content / utm_term entirely. Fall back to a direct URL read if // the module is somehow absent. function getUtm(k) { if (window.ujUtm && typeof window.ujUtm.get === 'function') { return window.ujUtm.get(k) || ''; } try { return new URLSearchParams(location.search).get(k) || ''; } catch(_) { return ''; } } function pushSignupEvent(alreadySubscribed) { window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: 'newsletter_signup', already_subscribed: !!alreadySubscribed }); } // Persist a "this visitor signed up" flag so cross-page surfaces // (currently the exit-intent modal) can skip nagging them again. // Set on both new-subscriber success AND already-subscribed // response — both confirm the visitor is on the list. function markSignedUp() { try { localStorage.setItem('uj_newsletter_signed_up', '1'); } catch (_) {} } // Shared response handler for both JSONP and REST paths. Response // shape: { result: 'success'|'error', msg: '...' }. JSONP returns // this directly from Mailchimp; the REST endpoint mirrors the same // shape so this handler doesn't need to branch. function handleResponse(form, msg, btn, resp) { btn.disabled = false; var redirectUrl = form.getAttribute('data-redirect-url') || ''; if (resp && resp.result === 'success') { pushSignupEvent(false); markSignedUp(); if (redirectUrl) { window.location.href = redirectUrl; return; } form.reset(); msg.textContent = '✓ Thanks! Check your inbox to confirm.'; msg.className = 'uj-mc-form__msg uj-mc-form__msg--success'; } else { var text = (resp && resp.msg ? String(resp.msg) : 'Something went wrong. Please try again.').replace(/<[^>]*>/g, '').trim(); if (text.toLowerCase().indexOf('already subscribed') !== -1) { pushSignupEvent(true); markSignedUp(); if (redirectUrl) { window.location.href = redirectUrl; return; } msg.textContent = "You're already on the list, thanks!"; msg.className = 'uj-mc-form__msg uj-mc-form__msg--success'; } else { msg.textContent = text; msg.className = 'uj-mc-form__msg uj-mc-form__msg--error'; } } } document.addEventListener('submit', function(e){ var form = e.target; if (!form.classList || !form.classList.contains('uj-mc-form')) return; e.preventDefault(); var msg = form.querySelector('.uj-mc-form__msg'); var btn = form.querySelector('button[type=submit]'); btn.disabled = true; msg.textContent = 'Submitting…'; msg.className = 'uj-mc-form__msg uj-mc-form__msg--pending'; // Each is independently optional — internal links routinely carry // only one or two (the main-menu trip-planner link is bare // ?utm_content=…). Whatever is present ships; the rest go empty // and are dropped server-side rather than blanking a merge field. var utm = { source: getUtm('utm_source'), medium: getUtm('utm_medium'), campaign: getUtm('utm_campaign'), content: getUtm('utm_content'), term: getUtm('utm_term') }; var endpoint = form.dataset.endpoint || ''; var isRest = endpoint.indexOf('/wp-json/') > -1 || endpoint.indexOf('rest_route=') > -1; if (isRest) { // POST JSON to our server-side endpoint. Used when the form // needs a Mailchimp tag applied (mc_tags attribute set on the // shortcode). The endpoint upserts the subscriber and POSTs // the tag list in two API calls server-side. var fd = new FormData(form); var honeypotInput = form.querySelector('input[type=text][name^="b_"]'); var tagsAttr = form.getAttribute('data-uj-mc-tags') || ''; var tags = tagsAttr ? tagsAttr.split(',').map(function(s){ return s.trim(); }).filter(Boolean) : []; var payload = { email: fd.get('EMAIL') || '', fname: fd.get('FNAME') || '', mmerge9: fd.get('MMERGE9') || '', mmerge10: utm.source, mmerge11: utm.medium, mmerge12: utm.campaign, utm_content: utm.content, utm_term: utm.term, tags: tags, honeypot: honeypotInput ? honeypotInput.value : '' }; fetch(endpoint, { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(payload) }).then(function(r){ return r.json().catch(function(){ return { result: 'error', msg: 'Network error. Please try again.' }; }); }).then(function(resp){ handleResponse(form, msg, btn, resp); }).catch(function(){ handleResponse(form, msg, btn, { result: 'error', msg: 'Network error. Please try again.' }); }); return; } // JSONP path (Mailchimp hosted endpoint). var data = new URLSearchParams(new FormData(form)); if (utm.source) data.set('MMERGE10', utm.source); if (utm.medium) data.set('MMERGE11', utm.medium); if (utm.campaign) data.set('MMERGE12', utm.campaign); // content/term only once the audience actually has merge fields // for them — see uj_utm_extra_merge_tags(). Posting an unknown // merge tag makes Mailchimp reject the whole write. if (utm.content && EXTRA_MERGE_TAGS.utm_content) data.set(EXTRA_MERGE_TAGS.utm_content, utm.content); if (utm.term && EXTRA_MERGE_TAGS.utm_term) data.set(EXTRA_MERGE_TAGS.utm_term, utm.term); var cb = 'ujMc' + Date.now() + Math.floor(Math.random() * 10000); data.set('c', cb); window[cb] = function(resp){ try { delete window[cb]; } catch(_) { window[cb] = undefined; } var s = document.getElementById(cb + '_s'); if (s) s.parentNode.removeChild(s); handleResponse(form, msg, btn, resp); }; var script = document.createElement('script'); script.id = cb + '_s'; script.src = endpoint + '&' + data.toString(); script.onerror = function(){ if (typeof window[cb] === 'function') { window[cb]({ result: 'error', msg: 'Network error. Please try again.' }); } }; document.body.appendChild(script); }); })();