in theme.liquid - Uses console.log for reliable debug output - Sets cart attribute: has_hulk_option = "true" | "false" - Then configure your Checkout Block to hide COD when has_hulk_option = true */ (function () { const DEBUG = true; const TAG = '[HULK-COD]'; function log(...args) { if (DEBUG) console.log(TAG, ...args); } function err(...args) { console.error(TAG, ...args); } let debounceTimer = null; function scheduleUpdate(delay = 700) { if (debounceTimer) clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { debounceTimer = null; updateHulkOptionFlag(); }, delay); } async function updateHulkOptionFlag() { try { log('Checking cart for Hulk options...'); const res = await fetch('/cart.js', { cache: 'no-cache' }); if (!res.ok) throw new Error('Failed to fetch /cart.js: ' + res.status); const cart = await res.json(); const foundProps = []; const items = Array.isArray(cart.items) ? cart.items : []; items.forEach(item => { const props = item.properties || {}; Object.entries(props).forEach(([k, v]) => { if (v != null && String(v).trim() !== '' && String(k).length && !String(k).startsWith('_')) { foundProps.push({ key: k, value: v }); } }); }); const anyHulkOption = foundProps.length > 0; const newVal = anyHulkOption ? 'true' : 'false'; const currentAttr = (cart.attributes && cart.attributes.has_hulk_option) ? String(cart.attributes.has_hulk_option) : 'false'; log('Cart items:', items.length, 'Hulk props found:', foundProps.length); if (foundProps.length) log('Sample props:', foundProps.slice(0, 5)); if (currentAttr === newVal) { log('No update needed — has_hulk_option already', currentAttr); return; } log('Updating cart attribute has_hulk_option =>', newVal); const updRes = await fetch('/cart/update.js', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ attributes: { has_hulk_option: newVal } }) }); if (!updRes.ok) { log('Warning: /cart/update.js returned', updRes.status); } else { log('Cart update request succeeded (sent).'); } // Optional verify: fetch cart again (DEBUG only) if (DEBUG) { try { const verify = await fetch('/cart.js', { cache: 'no-cache' }); const cart2 = await verify.json(); log('Cart attributes after update:', cart2.attributes || {}); } catch (e) { log('Could not verify cart after update:', e); } } } catch (e) { err('Error in updateHulkOptionFlag:', e); } } // RUN once on page load document.addEventListener('DOMContentLoaded', () => { log('Script loaded (DOMContentLoaded)'); scheduleUpdate(300); // small delay to allow page scripts to settle }); // Hook Add-to-Cart clicks (works for most themes) document.body.addEventListener('click', (e) => { const addBtn = e.target.closest( 'form[action*="/cart/add"] [type="submit"], ' + 'form[action*="/cart/add"] input[type="submit"], ' + 'button[name="add"], [data-add-to-cart], .add-to-cart, .ProductForm__AddToCart, .product-form__submit' ); if (addBtn) { log('Add to Cart clicked -> scheduling Hulk option check'); scheduleUpdate(900); // give drawer or ajax a moment to update } }, { passive: true }); // Listen for some common custom events used by themes/apps ['ajaxCart:afterAdd', 'cart:refresh', 'cart:updated', 'cart:change'].forEach(evt => { document.addEventListener(evt, () => { log('Custom event fired:', evt); scheduleUpdate(300); }); }); // MutationObserver on common cart drawer selectors (if drawer exists) const drawerSelectors = [ '#CartDrawer', '[id*="CartDrawer"]', '.drawer', '.cart-drawer', '.ajaxcart', '.ajax-cart', '.slide-cart', '.side-cart' ]; let drawer = null; for (const s of drawerSelectors) { drawer = document.querySelector(s); if (drawer) break; } if (drawer) { log('Found cart drawer element for MutationObserver:', drawer); const mo = new MutationObserver((mutations) => { // minimal throttle scheduleUpdate(400); }); mo.observe(drawer, { childList: true, subtree: true, attributes: false }); } else { log('No cart drawer element found at load time (will rely on XHR/fetch/click hooks).'); } // XHR hook: catch older XHR-based add-to-cart (function (open) { XMLHttpRequest.prototype.open = function (method, url) { this.addEventListener('load', function () { try { if (typeof url === 'string' && (url.includes('/cart/add') || url.includes('/cart/change') || url.includes('/cart/update') || url.includes('/cart.js'))) { log('XHR hook detected cart change for URL:', url); scheduleUpdate(300); } } catch (e) { /* ignore */ } }); open.apply(this, arguments); }; })(XMLHttpRequest.prototype.open); // fetch hook: catch modern fetch-based add-to-cart calls if (window.fetch) { const originalFetch = window.fetch; window.fetch = function () { const args = Array.from(arguments); let url = ''; try { const arg0 = args[0]; url = typeof arg0 === 'string' ? arg0 : (arg0 && arg0.url) || ''; } catch (e) { url = ''; } return originalFetch.apply(this, args).then((response) => { try { if (typeof url === 'string' && (url.includes('/cart/add') || url.includes('/cart/change') || url.includes('/cart/update') || url.includes('/cart.js'))) { log('fetch() hook detected cart change for URL:', url); scheduleUpdate(300); } } catch (e) { /* ignore */ } return response; }).catch((err) => { // still propagate error throw err; }); }; } // Provide a console helper to manually trigger / debug window.__hulk_cod_check = function (delay = 0) { log('Manual trigger called, delay=', delay); if (!delay) return updateHulkOptionFlag(); scheduleUpdate(delay); }; // Expose a simple status function window.__hulk_cod_status = async function () { try { const r = await fetch('/cart.js', { cache: 'no-cache' }); const c = await r.json(); log('Cart items:', (c.items || []).length, 'Cart attributes:', c.attributes || {}); return c; } catch (e) { err('Status check error:', e); throw e; } }; })();
Skip to content