Created
August 11, 2021 13:12
-
-
Save husseyexplores/2e6d18a934387cc9150c44c9085f708c to your computer and use it in GitHub Desktop.
[Klaviyo Integration] Klaviyo signup form & BIS #klaviyo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<button type="button" class="btn klaviyo-bis-trigger-custom" {% if product.selected_or_first_available_variant.available %}style="display: none;"{% endif %}>Notify me when available</button> | |
<div | |
id="KlaviyoBIS-{{ product.id }}" | |
class="modal modal--square modal--mobile-friendly klaviyo-bis-popup" | |
data-product-id="{{ product.id }}" | |
> | |
<div class="modal__inner"> | |
<div class="modal__centered medium-up--text-center"> | |
<div class="modal__centered-content"> | |
<div class="klaviyo-bis"> | |
<h2>{{ product.title }}</h2> | |
<p>{{ 'products.back_in_stock.popup_body_content' | t }}</p> | |
<div class="form-vertical" style="padding-top: 15px;"> | |
<form action="#" class="klaviyo-bis-form-custom"> | |
<input type="hidden" name="subscribe_for_newsletter" value="true"> | |
<input type="hidden" name="platform" value="shopify"> | |
<input type="hidden" name="g" value="RzPhNs"> <!-- lst id --> | |
<input type="hidden" name="a" value="QQyd2Z"> <!-- pub api key --> | |
<input type="hidden" name="product" value="{{ product.id }}"> | |
<div {% if product.variants.size == 1 %}style="display: none;"{% endif %}> | |
<label for="KlaviyoBIS-{{ product.id }}--variants">Options</label> | |
<select id="KlaviyoBIS-{{ product.id }}--variants" name="variant" class="variants" style="width: 100%;"> | |
{%- for v in product.variants -%} | |
{%- unless v.available -%} | |
<option value="{{ v.id }}">{{ v.title }}</option> | |
{%- endunless -%} | |
{%- endfor -%} | |
</select> | |
</div> | |
<label for="KlaviyoBIS-{{ product.id }}--name">Name</label> | |
<input type="tel" id="KlaviyoBIS-{{ product.id }}--name" class="input-full" name="name" value="{% if customer %}{{ customer.first_name | default: '' }} {{ customer.last_name | default: '' }}{% endif %}"> | |
<label for="KlaviyoBIS-{{ product.id }}--name">Email *</label> | |
<input type="email" id="KlaviyoBIS-{{ product.id }}--email" class="input-full" name="email" autocorrect="off" autocapitalize="off" value="" required> | |
<label for="KlaviyoBIS-{{ product.id }}--phone">Phone Number</label> | |
<input type="tel" id="KlaviyoBIS-{{ product.id }}--phone" class="input-full" name="phone_number" pattern="[0-9\-]*" value="{% if customer %}{{ customer.phone | default: '' }}{% endif %}"> | |
<div class="completed_message alert" style="display: none;">{{ 'products.back_in_stock.subscription_success_label' | t }} <a href="#" role="button" class="text-close js-modal-close">Close</a></div> | |
<div class="error_message alert" style="display: none;"></div> | |
<button class="btn submit-btn" style="width: 100%;">{{ 'products.back_in_stock.popup_button_label' | t }}</button> | |
</form> | |
</div> | |
<!-- <button type="button" class="text-close js-modal-close">Close</button> --> | |
</div> | |
</div> | |
<button type="button" class="modal__close js-modal-close text-link"> | |
<svg aria-hidden="true" focusable="false" role="presentation" class="icon icon-close" viewBox="0 0 64 64"><path d="M19 17.61l27.12 27.13m0-27.12L19 44.74"/></svg> | |
<span class="icon__fallback-text">{{ 'general.accessibility.close_modal' | t | json }}</span> | |
</button> | |
</div> | |
</div> | |
</div> | |
<script> | |
(function() { | |
function domReady(fn) { | |
// If we're early to the party | |
document.addEventListener("DOMContentLoaded", fn); | |
// If late; I mean on time. | |
if (document.readyState === "interactive" || document.readyState === "complete" ) { | |
fn(); | |
} | |
} | |
let pid = {{ product.id }}; | |
let currentVId = {{ product.selected_or_first_available_variant.id }}; | |
domReady(function() { | |
let id = 'KlaviyoBIS-' + pid | |
let modal = new theme.Modals(id, id) | |
let modalElement = document.getElementById(id) | |
let productSection = document.getElementById('ProductSection-' + pid) | |
if (productSection) { | |
let trigger = productSection.querySelector('.klaviyo-bis-trigger-custom') | |
let bisForm = productSection.querySelector('.klaviyo-bis-form-custom') | |
let submitBtn = bisForm.querySelector('.submit-btn') | |
let bisFormVariants = bisForm.querySelector('.variants') | |
let succEl = bisForm.querySelector('.completed_message') | |
let errEl = bisForm.querySelector('.error_message') | |
let variantOptionsArray = Array.from(bisFormVariants.options) | |
productSection.addEventListener('variantChange', e => { | |
let variant = e.detail.variant | |
let available = variant.available | |
currentVId = variant.id | |
if (!available) { | |
trigger.style.display = 'block' | |
} else { | |
trigger.style.display = 'none' | |
} | |
}) | |
trigger.addEventListener('click', function() { | |
bisFormVariants.selectedIndex = variantOptionsArray.findIndex(x => x.value == currentVId) | |
modal.open(); | |
}) | |
bisForm.addEventListener('submit', e => { | |
console.log('submit') | |
e.preventDefault(); | |
e.stopPropagation(); | |
if (bisForm.checkValidity()) { | |
postFormData() | |
} | |
}) | |
function postFormData() { | |
succEl.style.display = 'none' | |
errEl.style.display = 'none' | |
var formData = new FormData(bisForm); | |
var data = {}; | |
formData.forEach((value, key) => { | |
value = typeof value === 'string' ? value.trim() : value | |
if (value) { | |
if (key == 'name') { | |
let nameParts = value.split(' ') | |
if (nameParts[0]) { | |
data.$first_name = nameParts[0] | |
} | |
if (nameParts[1]) { | |
data.$last_name = nameParts[1] | |
} | |
} else { | |
data[key] = value; | |
} | |
} | |
}); | |
console.log(data) | |
if (!data.email || !data.variant || !data.product) { | |
return | |
} | |
// data.variant = 1338281066525 | |
// data.product = 114834341917 | |
submitBtn.setAttribute('disabled', 'true') | |
fetch("https://a.klaviyo.com/onsite/components/back-in-stock/subscribe", { | |
"headers": { | |
"accept": "*/*", | |
"accept-language": "en-US,en;q=0.9", | |
"content-type": "application/x-www-form-urlencoded", | |
}, | |
"body": objToStrUrlEncode(data), | |
"method": "POST", | |
"mode": "cors", | |
"credentials": "omit" | |
}) | |
.then(r => r.json()) | |
.then(r => { | |
if (r.status == 200 || r.success) { | |
succEl.style.display = 'block' | |
submitBtn.style.display = 'none' | |
subscribeToList(data) | |
} else { | |
errEl.innerHTML = r.message | |
errEl.style.display = 'block' | |
submitBtn.removeAttribute('disabled') | |
} | |
}) | |
} | |
function subscribeToList(data) { | |
let newData = { $email: data.email, a: data.a, g: data.g, $fields: [] } | |
if (data.$first_name) { | |
newData.$first_name = data.$first_name | |
newData.$fields.push('$first_name') | |
} | |
if (data.$last_name) { | |
newData.$last_name = data.$last_name | |
newData.$fields.push('$last_name') | |
} | |
if (data.phone_number) { | |
newData.$phone_number = data.phone_number | |
newData.$fields.push('$phone_number') | |
} | |
newData.$fields = newData.$fields.join(',') | |
fetch("https://a.klaviyo.com/ajax/subscriptions/subscribe", { | |
"headers": { | |
"accept": "*/*", | |
"accept-language": "en-US,en;q=0.9", | |
"access-control-allow-headers": "*", | |
"content-type": "application/x-www-form-urlencoded; charset=UTF-8", | |
}, | |
"referrer": "https://help.klaviyo.com/", | |
"referrerPolicy": "strict-origin-when-cross-origin", | |
"body": objToStrUrlEncode(newData), | |
"method": "POST", | |
"mode": "cors", | |
"credentials": "omit" | |
}) | |
} | |
function objToStrUrlEncode(obj) { | |
const str = []; | |
for (var key in obj) { | |
if (obj.hasOwnProperty(key) && typeof obj[key] !== 'undefined') { | |
str.push(encodeURIComponent(key) + "=" + encodeURIComponent(obj[key])) | |
} | |
} | |
return str.join('&') | |
} | |
} | |
}) | |
})(); | |
</script> |
Glad you found it useful! You can ping me if you get stuck or need any pointers.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
damn that's 🔥 actually. I like this a lot more, thanks for sharing.
listen to my weird ass use case and see how ur second version is so perfect ❤ i wana set my unavailable product as a separate prod not a variant, and just reference it with it's id - user clicks a button to open mini form and register interest from the available prods page.
all examples used product form and extracting variables from page and i didn't want to write bare amounts of code to do it myself but i like this version much better. nice one 👍