Hey @lounatuna ,
Great to hear that almost everything is working! The fact that your cart totals are calculating correctly now is fantastic - that was the main battle. And kudos for getting creative with hosting your own Afterpay logo - that’s exactly the right approach when CDN resources don’t cooperate!
Now, about that pesky “Silver Guy from Terminator 2” situation
- I totally get it! Afterpay’s script is being more persistent than we’d like, and the intermittent behavior you’re seeing (coming and going with refreshes) suggests it’s a timing issue combined with Afterpay actively hunting for price elements to attach to.
Perfect timing that I found the window.AfterPay object! That’s actually the key to a much more elegant solution. Since you can see the Widgets object, we can use Afterpay’s own API to control exactly what gets rendered and where.
Here’s the ULTIMATE TERMINATOR SOLUTION
that should finally put an end to those rogue line item messages:
Step 1: Replace your existing cart-drawer.liquid script
Remove the script you added previously and replace it with this enhanced version:
<script>
document.addEventListener('DOMContentLoaded', function() {
// NUCLEAR OPTION: Intercept Afterpay's widget creation
if (window.AfterPay && window.AfterPay.Widgets) {
// Store the original widget creation method
const originalPaymentSchedule = window.AfterPay.Widgets.PaymentSchedule;
// Override it to block cart line item widgets
window.AfterPay.Widgets.PaymentSchedule = function(config) {
// Check if this widget is trying to attach to a cart line item
const target = typeof config.target === 'string' ?
document.querySelector(config.target) : config.target;
if (target && target.closest('.cart-item')) {
// Block it! Return a dummy object
return {
update: function() {},
destroy: function() {}
};
}
// Allow everything else
return originalPaymentSchedule.call(this, config);
};
}
// AGGRESSIVE AFTERPAY LINE ITEM DESTROYER ?
function destroyLineItemAfterpay() {
// Find and destroy all individual line item Afterpay elements
const selectors = [
'.cart-item .afterpay-message',
'.cart-item [data-afterpay-paragraph]',
'.cart-item .afterpay-paragraph',
'.cart-item [class*="afterpay"]',
'.cart-item [id*="afterpay"]',
'.cart-drawer .afterpay-paragraph:not(#afterpay-cart-drawer-message)',
'.cart-drawer [data-afterpay-paragraph]:not(#afterpay-cart-drawer-message)',
'.cart-item [data-afterpay-widget]'
];
selectors.forEach(selector => {
const elements = document.querySelectorAll(selector);
elements.forEach(el => {
if (el.id !== 'afterpay-cart-drawer-message' && !el.closest('#afterpay-cart-drawer-message')) {
el.remove(); // Complete destruction
}
});
});
}
// Function to update Afterpay messaging in cart drawer
function updateCartDrawerAfterpay() {
const afterpayElement = document.getElementById('afterpay-cart-drawer-message');
const totalElement = document.querySelector('.totals__total-value');
if (afterpayElement && totalElement) {
// Get the cart total
const totalText = totalElement.textContent || totalElement.innerText;
const totalAmount = parseFloat(totalText.replace(/[^\d.-]/g, ''));
if (totalAmount && totalAmount >= 1) {
// Calculate installment amount
const installmentAmount = (totalAmount / 4).toFixed(2);
// Create the Afterpay message with your hosted logo
afterpayElement.innerHTML = `
<div class="afterpay-text">
<span>or 4 interest-free payments of $${installmentAmount} with</span>
<img src="YOUR_HOSTED_AFTERPAY_LOGO_URL_HERE"
alt="Afterpay" style="height: 16px; margin-left: 4px;">
</div>
`;
} else {
afterpayElement.innerHTML = '';
}
}
// Destroy any rogue line item messages after updating
setTimeout(destroyLineItemAfterpay, 50);
setTimeout(destroyLineItemAfterpay, 200);
setTimeout(destroyLineItemAfterpay, 500);
}
// Create a more aggressive CSS injection
function injectTerminatorCSS() {
const style = document.createElement('style');
style.id = 'afterpay-terminator-styles';
style.textContent = `
/* TERMINATOR MODE: Hide all individual cart item Afterpay messages */
.cart-item .afterpay-message,
.cart-item [data-afterpay-paragraph],
.cart-item .afterpay-paragraph,
.cart-item [class*="afterpay"]:not(.cart-item__details):not(.cart-item__media):not(.cart-item__totals),
.cart-item [id*="afterpay"],
.cart-item [data-afterpay-widget],
.cart-drawer .afterpay-paragraph:not(#afterpay-cart-drawer-message),
.cart-drawer [data-afterpay-paragraph]:not(#afterpay-cart-drawer-message) {
display: none !important;
visibility: hidden !important;
opacity: 0 !important;
height: 0 !important;
width: 0 !important;
overflow: hidden !important;
position: absolute !important;
left: -9999px !important;
}
/* Style for the correct cart total Afterpay message */
.cart-afterpay {
margin: 10px 0;
text-align: center;
}
.afterpay-text {
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
color: #6c7173;
}
.afterpay-text img {
height: 16px;
vertical-align: middle;
}
`;
// Remove existing style if it exists
const existingStyle = document.getElementById('afterpay-terminator-styles');
if (existingStyle) {
existingStyle.remove();
}
document.head.appendChild(style);
}
// Run the terminator CSS injection immediately
injectTerminatorCSS();
// Set up a mutation observer to catch Afterpay when it tries to sneak back in
const terminatorObserver = new MutationObserver(function(mutations) {
let shouldDestroy = false;
mutations.forEach(function(mutation) {
// Check for added nodes that might be Afterpay elements
if (mutation.addedNodes.length > 0) {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) { // Element node
if (node.matches && (
node.matches('[data-afterpay-paragraph]') ||
node.matches('.afterpay-paragraph') ||
node.matches('[class*="afterpay"]') ||
node.matches('[data-afterpay-widget]') ||
(node.querySelector && node.querySelector('[data-afterpay-paragraph], .afterpay-paragraph, [class*="afterpay"], [data-afterpay-widget]'))
)) {
shouldDestroy = true;
}
}
});
}
});
if (shouldDestroy) {
setTimeout(destroyLineItemAfterpay, 10);
setTimeout(destroyLineItemAfterpay, 100);
}
});
// Watch the entire cart drawer for changes
const cartDrawer = document.querySelector('.cart-drawer');
if (cartDrawer) {
terminatorObserver.observe(cartDrawer, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['class', 'data-afterpay-paragraph', 'data-afterpay-widget']
});
}
// Update on page load with multiple attempts
setTimeout(() => {
updateCartDrawerAfterpay();
destroyLineItemAfterpay();
injectTerminatorCSS(); // Reinject in case it got overridden
}, 100);
setTimeout(() => {
destroyLineItemAfterpay();
}, 500);
setTimeout(() => {
destroyLineItemAfterpay();
}, 1000);
// Update when cart drawer opens
const cartDrawerElement = document.querySelector('cart-drawer');
if (cartDrawerElement) {
const drawerObserver = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
if (cartDrawerElement.classList.contains('active')) {
setTimeout(() => {
updateCartDrawerAfterpay();
destroyLineItemAfterpay();
injectTerminatorCSS(); // Reinject CSS in case it got overridden
}, 50);
setTimeout(destroyLineItemAfterpay, 200);
setTimeout(destroyLineItemAfterpay, 500);
}
}
});
});
drawerObserver.observe(cartDrawerElement, { attributes: true });
}
// Update when quantity changes
document.addEventListener('change', function(e) {
if (e.target.matches('.quantity__input')) {
setTimeout(() => {
updateCartDrawerAfterpay();
destroyLineItemAfterpay();
}, 100);
setTimeout(destroyLineItemAfterpay, 500);
}
});
// Update when items are added/removed
document.addEventListener('click', function(e) {
if (e.target.matches('.cart-remove-button') ||
e.target.closest('.cart-remove-button') ||
e.target.matches('.quantity__button') ||
e.target.closest('.quantity__button')) {
setTimeout(() => {
updateCartDrawerAfterpay();
destroyLineItemAfterpay();
}, 100);
setTimeout(destroyLineItemAfterpay, 500);
}
});
// Nuclear option: Periodic cleanup every 2 seconds when cart is open
setInterval(() => {
const cartDrawer = document.querySelector('cart-drawer');
if (cartDrawer && cartDrawer.classList.contains('active')) {
destroyLineItemAfterpay();
}
}, 2000);
});
</script>
Step 2: Enhanced theme.liquid interceptor
Add this to your theme.liquid file (this is the key improvement using the AfterPay object you found):
<script>
// Ultimate Afterpay Interceptor using window.AfterPay
(function() {
// Wait for AfterPay to load
function initAfterpayInterceptor() {
if (window.AfterPay && window.AfterPay.Widgets) {
// Method 1: Override the PaymentSchedule widget creation
const originalPaymentSchedule = window.AfterPay.Widgets.PaymentSchedule;
window.AfterPay.Widgets.PaymentSchedule = function(config) {
const target = typeof config.target === 'string' ?
document.querySelector(config.target) : config.target;
// Block widgets targeting cart line items
if (target && target.closest('.cart-item')) {
console.log('Blocked Afterpay widget on cart line item');
return { update: function() {}, destroy: function() {} };
}
return originalPaymentSchedule.call(this, config);
};
// Method 2: Override any automatic widget initialization
if (window.AfterPay.initializeForProduct) {
const originalInitialize = window.AfterPay.initializeForProduct;
window.AfterPay.initializeForProduct = function(element) {
if (element && element.closest('.cart-drawer')) {
return; // Block initialization in cart drawer
}
return originalInitialize.call(this, element);
};
}
// Method 3: Block automatic paragraph creation
const originalCreateElement = document.createElement;
document.createElement = function(tagName) {
const element = originalCreateElement.call(document, tagName);
if (tagName.toLowerCase() === 'div' || tagName.toLowerCase() === 'span') {
const originalSetAttribute = element.setAttribute;
element.setAttribute = function(name, value) {
if ((name === 'data-afterpay-paragraph' || name.includes('afterpay')) &&
document.querySelector('.cart-drawer.active')) {
const cartItem = this.closest('.cart-item');
if (cartItem) {
console.log('Blocked Afterpay attribute on cart item');
return;
}
}
return originalSetAttribute.call(this, name, value);
};
}
return element;
};
} else {
// AfterPay not loaded yet, try again
setTimeout(initAfterpayInterceptor, 100);
}
}
// Start the interceptor
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initAfterpayInterceptor);
} else {
initAfterpayInterceptor();
}
})();
</script>
Step 3: Remove the old CSS
Since the new script includes the CSS injection, you can remove the CSS you added to cart-drawer.css.
## What makes this solution different:
Uses AfterPay’s own API: Intercepts widget creation at the source using window.AfterPay.Widgets
Multiple destruction waves: Runs cleanup at multiple intervals to catch sneaky widgets
Enhanced CSS blocking: More aggressive hiding with multiple CSS properties
Mutation observer: Watches for new elements being added and destroys them immediately
API interception: Prevents widget creation in the first place rather than just hiding
## Don’t forget:- Replace YOUR_HOSTED_AFTERPAY_LOGO_URL_HERE with your actual hosted logo URL
- Make sure your theme.liquid still has those Afterpay variables set to false
This solution attacks the problem from five different angles:
- CSS hiding (immediate visual fix)
- DOM element removal (nuclear destruction)
- Widget API interception (prevents creation)
- Attribute blocking (stops configuration)
- Continuous monitoring (catches anything that slips through)
If the Silver Guy still manages to come back after this, then honestly, we might need to call in Sarah Connor!
But seriously, this should finally terminate those persistent line item messages once and for all.
Let me know how it goes - I’m confident this will solve the intermittent behavior too since we’re now working with AfterPay’s native API instead of fighting against it.
Cheers!
Shubham | Untechnickle