Search for products, concerns and keywords.


Your Brand Consultant Agreement has been successfully renewed.
There was a problem processing your Brand Consultant Agreement renewal. Please try again.
There was a system error. Please try again.
There was an issue adding this product. Please refresh the page and try again
You're saving 10% on your entire order, including subscription orders and one-time purchases!

Be a product of the product! Schedule convenient, monthly deliveries of your favorite R+F products at the discounted Consultant price.

Join PC Perks for Free
  • Free gift ($50+ value) with 2nd qualifying order + exclusive offers
  • Fully flexible subscription: Choose delivery frequency and delay or cancel anytime before shipment
Item has been added to your bag.
This field is required.
Home | REDEFINE Pore Refining Toner
  • REDEFINE Pore Refining Toner

REDEFINE Pore Refining Toner

$50.00

This item is part of Redefine Regimen

Save 20% when you buy a regimen versus purchasing each product individually.

60 Day Money Back Guarantee

Don't love it? It's on us. Learn More

60 Day Money Back Guarantee

Don't love it? It's on us. Learn More

Tone up! Our skin-softening toner minimizes + unclogs pores, gently exfoliates + helps promote natural cell turnover.

Recommended Usage: Twice daily, in the AM + PM after cleansing the face
Size: 125 mL / 4.2 Fl. Oz. U.S.

DETAILS

What it is: A gentle exfoliating toner with Fruit Acids that evens the appearance of skin tone, minimizes pores + preps skin for the steps that follow.

Why you need it: Fruit Acids are known to help to promote natural cell turnover. Get smoother, softer, younger-looking skin and maximize benefits of your AM and PM moisturizers.

For best results, use the full Redefine Regimen.

ITEM NUMBER: AATN125

KEY CONCERNS

Fine Lines, Deep Wrinkles, Loss of Firmness, Pore Tightening, Lifting, Sculpting, Defining

SKIN TYPE

Suitable for all skin types.

KEY BENEFITS

Softens skin, minimizes the appearance of pores + exfoliates to promote natural cell turnover

INGREDIENTS

Proprietary Technology + Key Ingredients
  • Fruit Acids

    Help promote natural cell turnover for smoother skin texture
  • Niacinamide (Vitamin B3)

    Evens the appearance of skin tone for a youthful glow
  • Deep Sea Water

    Rich in natural minerals and helps minimize the appearance of pores
View All Ingredients

RESULTS

  • 94%

    had softer, more supple skin*
  • 94%

    had smoother-feeling skin*
  • 91%

    noticed firmer skin*
  • 85%

    had plumper, fuller-looking skin*
View Full Study
New Customers Save 25%

REDEFINE 30-Day Regimen

Our best selling regimen now under $100 with code WELCOME25

$125.00

HOW TO USE

Use twice daily in the AM + PM, avoiding eye area.
  1. After cleansing, use a gauze pad to apply over face + neck.
  2. Do not rinse.
  3. Allow to dry.
 

HOW TO USE

Use twice daily in the AM + PM, avoiding eye area.
  1. After cleansing, use a gauze pad to apply over face + neck.
  2. Do not rinse.
  3. Allow to dry.
 

View Less View More

New Customers Save 25%

REDEFINE 30-Day Regimen

Our best selling regimen now under $100 with code WELCOME25

$125.00

Reviews

Common questions about the Rodan + Fields

REDEFINE Pore Refining Toner

What does REDEFINE Pore Refining Toner do?

Redefine Pore Refining Toner is the second step in the REDEFINE Regimen and prepares skin for the Redefine steps that follow. It is a skin softening toner that polishes the skin, helps promote natural skin turnover and minimizes the appearance of pores. Additionally, Redefine Pore Refining Toner gently exfoliates and prepares the skin to help deliver ingredients in the step that follows faster and more evenly onto the skin.

Is witch hazel good for minimizing pores?

Witch Hazel is used in Redefine Pore Refining Toner for quick drying. Skin feels instantly tighter and natural minerals help to minimize the appearance of pores.

Does REDEFINE Pore Refining Toner have alcohol?

Yes, Redefine Pore Refining Toner does contain Witch Hazel, and there is some alcohol in Witch Hazel. It is used in small amounts to help condition the skin, and when part of the entire formulation is not drying. Also, when used with the entire REDEFINE Regimen will not dry your skin.

Is there witch hazel in REDEFINE Pore Refining Toner?

Yes, Redefine Pore Refining Toner does contain Witch Hazel for quick drying. Skin feels instantly tighter and natural minerals help to minimize the appearance of pores.

What are the ingredients in REDEFINE Pore Refining Toner?

Redefine Pore Refining Toner contains Fruit Acids to help promote natural cell turnover for smoother skin texture and Niacinamide (vitamin B3) to even the appearance of skin tone for a youthful glow. Additionally, Deep Sea Water from the Atlantic coast of France is rich in natural minerals to help to minimize the appearance of pores.

What are the skin benefits of alpha hydroxy acid (AHAs) in REDEFINE Pore Refining Toner?

Redefine Pore Refining Toner contains fruit extracts that contain AHAs (optimal levels to be effective without being harsh). AHAs are known to help to promote natural cell turnover for smoother skin texture by unclogging pores, exfoliating skin surface for the appearance of smoother skin.

Common questions about the Rodan + Fields

REDEFINE Pore Refining Toner

What does REDEFINE Pore Refining Toner do?

Redefine Pore Refining Toner is the second step in the REDEFINE Regimen and prepares skin for the Redefine steps that follow. It is a skin softening toner that polishes the skin, helps promote natural skin turnover and minimizes the appearance of pores. Additionally, Redefine Pore Refining Toner gently exfoliates and prepares the skin to help deliver ingredients in the step that follows faster and more evenly onto the skin.

Is witch hazel good for minimizing pores?

Witch Hazel is used in Redefine Pore Refining Toner for quick drying. Skin feels instantly tighter and natural minerals help to minimize the appearance of pores.

Does REDEFINE Pore Refining Toner have alcohol?

Yes, Redefine Pore Refining Toner does contain Witch Hazel, and there is some alcohol in Witch Hazel. It is used in small amounts to help condition the skin, and when part of the entire formulation is not drying. Also, when used with the entire REDEFINE Regimen will not dry your skin.

Is there witch hazel in REDEFINE Pore Refining Toner?

Yes, Redefine Pore Refining Toner does contain Witch Hazel for quick drying. Skin feels instantly tighter and natural minerals help to minimize the appearance of pores.

What are the ingredients in REDEFINE Pore Refining Toner?

Redefine Pore Refining Toner contains Fruit Acids to help promote natural cell turnover for smoother skin texture and Niacinamide (vitamin B3) to even the appearance of skin tone for a youthful glow. Additionally, Deep Sea Water from the Atlantic coast of France is rich in natural minerals to help to minimize the appearance of pores.

What are the skin benefits of alpha hydroxy acid (AHAs) in REDEFINE Pore Refining Toner?

Redefine Pore Refining Toner contains fruit extracts that contain AHAs (optimal levels to be effective without being harsh). AHAs are known to help to promote natural cell turnover for smoother skin texture by unclogging pores, exfoliating skin surface for the appearance of smoother skin.

(function() { 'use strict'; // ============================================ // CONFIGURATION - EDIT THESE VALUES // ============================================ const marketingCards = [ // ============================================ // MARKETING CARDS - EVERGREEN - "Lash Day Offer" // ============================================ { // URLS to match for immediate render urlMatches: ['beauty-enhancements','lash-serum-and-eyebrow-tint'], // PLACEMENT: Choose ONE method (comment out the others) insertAtPosition: 3, // Insert AFTER this position in the grid // insertAfterProductCode: 'HRVRGG01', // Insert AFTER this CAT ID // insertBeforeProductCode: 'HAAGR', // OR insert BEFORE this CAT ID // POSITION: 'Start' or 'End' (if not set, uses insertAtPosition. If insertAtPosition exceeds product count, defaults to 'End') // placement: 'End', // 'Start' or 'End' titleText: 'YOUR LASHES.
BUT BETTER.
', bodyText: 'Celebrate National Lash Day with a boost. Get 20% off Lash Boost + a FREE Mini Eye Cream, for a limited time.', ctaText: 'USE CODE LASHDAY', ctaHref: '/shop/r-f-lash-boost/p/ENHLSH01', cardHref: '/shop/r-f-lash-boost/p/ENHLSH01', disclaimerText: '', textShadowEnabled: false, // BACKGROUND: Image URL or null for solid color backgroundImage: 'https://www.rodanandfields.com/en-us/medias/LASH-DAY-marketing-module-horizontal-image.jpg?context=bWFzdGVyfGltYWdlc3wxMTMwOTh8aW1hZ2UvanBlZ3xhRGczTDJneFppOHlPRFExTVRReE1UY3lNakkzTUM5TVFWTklMVVJCV1MxdFlYSnJaWFJwYm1jdGJXOWtkV3hsWDJodmNtbDZiMjUwWVd4ZmFXMWhaMlV1YW5CbnxhNTZkMTEyODgxNzdhM2NkNGQxODNkYmRjNWRkNGUyZDVjYjNmYjRlYWQxZjc0NjRhMGJjMjZjZjI5N2Y2YTI0', backgroundColor: '#FFFFFF', // Used only if backgroundImage is null copyBackgroundColor: '#FFFFFF', splitImageHalf: true, // LAYOUT copyAlign: 'left' }, // ============================================ // MARKETING CARDS - EVERGREEN - "Pure C Promo MC" // ============================================ { // URLS to match for immediate render urlMatches: ['best-sellers','redefine','skin-care-regimens'], // PLACEMENT: Choose ONE method (comment out the others) insertAtPosition: 3, // Insert AFTER this position in the grid // insertAfterProductCode: 'HRVRGG01', // Insert AFTER this CAT ID // insertBeforeProductCode: 'HAAGR', // OR insert BEFORE this CAT ID // POSITION: 'Start' or 'End' (if not set, uses insertAtPosition. If insertAtPosition exceeds product count, defaults to 'End') // placement: 'End', // 'Start' or 'End' titleText: 'LIMITED-TIME: PURE C EXCLUSIVE OFFERS', bodyText: 'Pair with Active Hydration Serum and save $45 or buy Pure C, get a complimentary Hydra Mask ($54 Value)', ctaText: 'Shop Now', ctaHref: '/category/face-serums', cardHref: '/category/face-serums', disclaimerText: 'Valid thru 2/28/26. See Terms & Conditions', textShadowEnabled: false, // BACKGROUND: Image URL or null for solid color backgroundImage: 'https://www.rodanandfields.com/en-us/medias/Pure-C-Promo-Marketing-Module.jpg?context=bWFzdGVyfGltYWdlc3w2NTk0MHxpbWFnZS9qcGVnfGFESXdMMmhoWmk4eU9ETTVOems1TnpjeE9UVTRNaTlRZFhKbExVTXRVSEp2Ylc4dFRXRnlhMlYwYVc1bkxVMXZaSFZzWlM1cWNHY3xhNmFmZWY2YjU3MzM5ZWY2NWNlN2Q5Njk1MWFjYTY1MzE0MWI4NzQ3OWY1YWUyNTM0NDY4YzUwMzcyYzcwY2Mz', backgroundColor: '#FFFFFF', // Used only if backgroundImage is null copyBackgroundColor: '#FFFFFF', splitImageHalf: true, // LAYOUT copyAlign: 'left' }, // ============================================ // MARKETING CARDS - EVERGREEN - "Pure C Evergreen MC" // ============================================ { // URLS to match for immediate render urlMatches: ['face-serums','anti-aging-skin-care'], // PLACEMENT: Choose ONE method (comment out the others) insertAtPosition: 3, // Insert AFTER this position in the grid // insertAfterProductCode: 'HRVRGG01', // Insert AFTER this CAT ID // insertBeforeProductCode: 'HAAGR', // OR insert BEFORE this CAT ID // POSITION: 'Start' or 'End' (if not set, uses insertAtPosition. If insertAtPosition exceeds product count, defaults to 'End') // placement: 'End', // 'Start' or 'End' titleText: 'NEW PURE C SERUM', bodyText: 'Activate your skin’s longevity for firmer, smoother, brighter skin...now and for years to come', ctaText: 'Learn More', ctaHref: '/discover/purec', cardHref: '/discover/purec', disclaimerText: '', textShadowEnabled: false, // BACKGROUND: Image URL or null for solid color backgroundImage: 'https://www.rodanandfields.com/en-us/medias/Pure-C-Evergreen-Marketing-Module.jpg?context=bWFzdGVyfGltYWdlc3w5MjQxOXxpbWFnZS9qcGVnfGFEVXhMMmhoTlM4eU9ETTVOems1TnpRMU56UXpPQzlRZFhKbExVTXRSWFpsY21keVpXVnVMVTFoY210bGRHbHVaeTFOYjJSMWJHVXVhbkJufDNkZTgzNTUzYTFjY2QwMjY2OWVlZjljODYwZmNjYWY5YzRmNGFjNWE2Y2I3YjM4YjczNTdjODhmOTQzZDcwMDY', backgroundColor: '#FFFFFF', // Used only if backgroundImage is null copyBackgroundColor: '#FFFFFF', splitImageHalf: true, // LAYOUT copyAlign: 'left' }, // ============================================ // MARKETING CARDS - EVERGREEN - "Money Back Guarantee" // ============================================ { // URLS to match for immediate render urlMatches: ['exfoliants','eye-creams-and-treatments','neck-and-decollete','reverse','soothe','unblemish'], // PLACEMENT: Choose ONE method (comment out the others) insertAtPosition: 3, // Insert AFTER this position in the grid // insertAfterProductCode: 'HRVRGG01', // Insert AFTER this CAT ID // insertBeforeProductCode: 'HAAGR', // OR insert BEFORE this CAT ID // POSITION: 'Start' or 'End' (if not set, uses insertAtPosition. If insertAtPosition exceeds product count, defaults to 'End') // placement: 'End', // 'Start' or 'End' titleText: 'Love it or get your money back.', bodyText: 'We stand behind our science, formulas + results with a 60-Day Money Back Guarantee.', ctaText: 'Learn More', ctaHref: '/satisfaction-guarantee', cardHref: '/satisfaction-guarantee', disclaimerText: '', textShadowEnabled: false, // BACKGROUND: Image URL or null for solid color backgroundImage: 'https://www.rodanandfields.com/en-us/medias/60-day-Guarantee.jpg?context=bWFzdGVyfGltYWdlc3wyNDc0OTd8aW1hZ2UvanBlZ3xhREppTDJnek1TOHlPRE01TnprNU5qRTBOamN4T0M4Mk1DMWtZWGt0UjNWaGNtRnVkR1ZsTG1wd1p3fDM1ZDU3NGEwZDllNWMxZDUwYzk1NDJhZjMwNGZkM2Y5NGEwMmM3NTQ2MzhjYTI0ZDk2NWQ4ZjJlOTY2NTJmYWE', backgroundColor: '#F5F4F2', // Used only if backgroundImage is null copyBackgroundColor: '#F5F4F2', splitImageHalf: true, // LAYOUT copyAlign: 'left' }, // ============================================ // MARKETING CARDS - EVERGREEN - "#1 Female Dermatologist Founded Skincare Brand" // ============================================= { // URLS to match for immediate render urlMatches: ['acne-pores-blackheads-skin-care','dry-skin-care','skin-care-essentials','face-moisturizers','lip-care-and-color','sensitive-skin-care','sun-protection','toners','uneven-skin-tone-and-dark-marks-skin-care'], // PLACEMENT: Choose ONE method (comment out the others) insertAtPosition: 3, // Insert AFTER this position in the grid // insertAfterProductCode: 'HRVRGG01', // Insert AFTER this CAT ID // insertBeforeProductCode: 'HAAGR', // OR insert BEFORE this CAT ID // POSITION: 'Start' or 'End' (if not set, uses insertAtPosition. If insertAtPosition exceeds product count, defaults to 'End') // placement: 'End', // 'Start' or 'End' titleText: '#1 Female Dermatologist Founded Skincare Brand in the U.S.*', bodyText: '', ctaText: 'Learn More', ctaHref: '/nx/our-story', cardHref: '/nx/our-story', disclaimerText: '*Source Euromonitor Int’l Ltd. 2024; See rodanandfields.com for details.', textShadowEnabled: false, // BACKGROUND: Image URL or null for solid color backgroundImage: 'https://www.rodanandfields.com/en-us/medias/Female-Derm.jpg?context=bWFzdGVyfGltYWdlc3wyNDQ2MTR8aW1hZ2UvanBlZ3xhR1k1TDJnellTOHlPRE01TnprNU5qUXdPRGcyTWk5R1pXMWhiR1V0UkdWeWJTNXFjR2N8NDc0NTdhYzliNzNhMTA3ZGJkYzc5NzVmNjMzNzcyMGUwYzE5OGQzMDk3MDE3ZWRhNTk2NTM3ZjZlZGZhNjdjMQ', backgroundColor: '#F5F4F2', // Used only if backgroundImage is null copyBackgroundColor: '#F5F4F2', splitImageHalf: true, // LAYOUT copyAlign: 'left' }, // ============================================ // MARKETING CARDS - EVERGREEN - "Rodan + Fields is the #1 Premium Lash Serum" // ============================================= { // URLS to match for immediate render urlMatches: [], // PLACEMENT: Choose ONE method (comment out the others) insertAtPosition: 3, // Insert AFTER this position in the grid // insertAfterProductCode: 'HRVRGG01', // Insert AFTER this CAT ID // insertBeforeProductCode: 'HAAGR', // OR insert BEFORE this CAT ID // POSITION: 'Start' or 'End' (if not set, uses insertAtPosition. If insertAtPosition exceeds product count, defaults to 'End') // placement: 'End', // 'Start' or 'End' titleText: 'Rodan + Fields is the #1 Premium Lash Serum Brand in the US in 2024*', bodyText: '', ctaText: '', ctaHref: '', cardHref: '', disclaimerText: '*Source Euromonitor International Limited; Custom research conducted June-Aug 2025, retail value RSP terms; all channels; Lash Serum including Lash Serum products sold as part of Sets and Kits', textShadowEnabled: false, // BACKGROUND: Image URL or null for solid color backgroundImage: 'https://www.rodanandfields.com/en-us/medias/Lash-Boost-MC-Image.jpg?context=bWFzdGVyfGltYWdlc3wyMDE1Mjd8aW1hZ2UvanBlZ3xhRFJsTDJneU1DOHlPRE01TnprNU5UZzRORFUzTkM5TVlYTm9MVUp2YjNOMExVMURMVWx0WVdkbExtcHdad3w2MTVjMTdmN2Q2MDJlYmIzMzhmOWQ2OTg0MmRlNTFiODg5N2Q5OTBhNDFlODQwMmNjODliMzM3Yjk3NGJiNjIz', backgroundColor: '#F5F4F2', // Used only if backgroundImage is null copyBackgroundColor: '#F5F4F2', splitImageHalf: true, // LAYOUT copyAlign: 'left' }, // ============================================ // MARKETING CARDS - EVERGREEN - "Klarna" // ============================================= { // URLS to match for immediate render urlMatches: ['regimen-sets','rf-paired-multi-action-regimens','skin-care-tools-and-accessories'], // PLACEMENT: Choose ONE method (comment out the others) insertAtPosition: 3, // Insert AFTER this position in the grid // insertAfterProductCode: 'HRVRGG01', // Insert AFTER this CAT ID // insertBeforeProductCode: 'HAAGR', // OR insert BEFORE this CAT ID // POSITION: 'Start' or 'End' (if not set, uses insertAtPosition. If insertAtPosition exceeds product count, defaults to 'End') // placement: 'End', // 'Start' or 'End' titleText: 'Buy now. Pay later.', bodyText: 'Select Klarna at checkout to split your purchase into 4 interest-free payments.', ctaText: '', ctaHref: '', cardHref: '', disclaimerText: '', textShadowEnabled: false, // BACKGROUND: Image URL or null for solid color backgroundImage: 'https://www.rodanandfields.com/en-us/medias/Klarna.jpg?context=bWFzdGVyfGltYWdlc3wzMTE3NnxpbWFnZS9qcGVnfGFETmlMMmc1TVM4eU9ETTVOems1T1RFMk1UTTNOQzlMYkdGeWJtRXVhbkJufDUwMzJkNzBjNzRjZmMxYzc2MjE5NWEyNjIwOTJmYzg5ZDE1NjQ1Y2U4MDQ3ZTg2OTI3ZjIxMzE1OGU3OGE2NWI', backgroundColor: '#F5F4F2', // Used only if backgroundImage is null copyBackgroundColor: '#F5F4F2', splitImageHalf: true, // LAYOUT copyAlign: 'left' } ]; // ============================================ // MODULE HTML GENERATOR // ============================================ function generateModuleHTML(cfg) { const alignMap = { left: 'flex-start', center: 'center', right: 'flex-end' }; const safeAlign = ['left','center','right'].includes(cfg.copyAlign) ? cfg.copyAlign : 'center'; const bgStyle = cfg.backgroundImage ? `background: url('${cfg.backgroundImage}') center/cover no-repeat;` : `background: ${cfg.backgroundColor}`; const shadowStyle = cfg.textShadowEnabled ? 'text-shadow: 0 1px 2px rgba(0,0,0,0.6);' : ''; // Split Image Half Layout if (cfg.splitImageHalf) { const splitImageStyle = `${cfg.backgroundImage ? `--split-image-url: url('${cfg.backgroundImage}');` : ''}`; const cardAttr = cfg.cardHref ? `data-card-href="${cfg.cardHref}"` : ''; const cardClass = cfg.cardHref ? ' rf-card-clickable' : ''; return `

${cfg.titleText.replace(/\n/g, '
')}

${cfg.bodyText ? `

${cfg.bodyText}

` : ''} ${cfg.ctaText && cfg.ctaText.trim() ? `${cfg.ctaText}` : ''} ${cfg.disclaimerText ? `
${cfg.disclaimerText}
` : ''}
`; } // Default horizontal layout const cardAttr = cfg.cardHref ? `data-card-href="${cfg.cardHref}"` : ''; const cardClass = cfg.cardHref ? ' rf-card-clickable' : ''; return `

${cfg.titleText.replace(/\n/g, '
')}

${cfg.bodyText ? `

${cfg.bodyText}

` : ''} ${cfg.ctaText && cfg.ctaText.trim() ? `${cfg.ctaText}` : ''} ${cfg.disclaimerText ? `
${cfg.disclaimerText}
` : ''}
`; } // PDP detection helper function isPDP() { try { const path = (window.location && window.location.pathname) || ''; // PDP URLs include "/p/" followed by a code return path.includes('/p/'); } catch (e) { return false; } } // Return cards whose urlMatches match a full path segment (not substring) function getActiveCards() { const href = (window.location && window.location.href || '').toLowerCase(); const path = (window.location && window.location.pathname || '').toLowerCase(); const segments = path.split('/').filter(Boolean); // path parts without empty strings const matchesSegment = (needle) => { if (!needle) return false; const n = String(needle).toLowerCase(); // exact segment match, or common category patterns return segments.includes(n) || path.endsWith('/' + n) || path.includes('/shop/' + n + '/') || href.includes('cgid=' + encodeURIComponent(n)); }; return marketingCards.filter(card => Array.isArray(card.urlMatches) && card.urlMatches.some(matchesSegment)); } // ============================================ // PRODUCT DETECTION // ============================================ let injected = false; function filterProductElements(elements) { return elements.filter(el => { const tag = el.tagName ? el.tagName.toLowerCase() : ''; if (tag === 'button' || tag === 'a') return false; const role = (el.getAttribute && el.getAttribute('role')) || ''; if (role === 'button' || role === 'link') return false; if (el.hasAttribute && el.hasAttribute('data-copilot-module')) return false; if (el.closest && el.closest('.add-to-cart, .product-cta, .product-actions, .pdp-add-to-cart, .quickbuy')) return false; return true; }); } function findProducts() { const selectors = [ '[data-product-code]', '[data-product-id]', '.product-item', '.product-card', '.product-tile', '.product', '.js-product', 'article.product', '.product-grid-item', '.product-list-item' ]; for (let selector of selectors) { const elements = document.querySelectorAll(selector); if (elements.length > 0) { console.log(`Found ${elements.length} products using: ${selector}`); return filterProductElements(Array.from(elements)); } } console.warn('No products found'); return []; } function getProductCode(el) { return el.getAttribute('data-product-code') || el.getAttribute('data-product-id') || el.getAttribute('data-sku') || el.querySelector('[data-product-code]')?.getAttribute('data-product-code') || el.querySelector('[data-product-id]')?.getAttribute('data-product-id') || el.querySelector('a[href*="/shop/"]')?.href.split('/p/')[1]?.split('?')[0] || null; } // ============================================ // INJECTION LOGIC // ============================================ function injectModule() { if (injected) return; // Guard: never inject on PDPs if (isPDP()) { console.warn('PDP detected; skipping marketing card injection.'); return; } const cards = getActiveCards(); if (!cards || cards.length === 0) { console.warn('No marketing card configured for this URL'); return; } // Only consider products inside .mdc-layout-grid__inner if present let products = []; const gridInner = document.querySelector('.mdc-layout-grid__inner'); if (gridInner) { // Find all product elements inside the grid products = filterProductElements(Array.from(gridInner.querySelectorAll('[data-product-code], [data-product-id], .product-item, .product-card, .product-tile, .product, .js-product, article.product, .product-grid-item, .product-list-item'))); } else { products = findProducts(); } if (products.length === 0) return; console.log(`${cards.length} marketing card(s) matched this URL`); // Log all found product codes and positions for debugging console.log('Product codes and positions found:'); products.forEach((p, i) => { const pos = p.getAttribute('data-position'); const code = getProductCode(p); console.log(` Index ${i + 1} | Position: ${pos} | Code: ${code || 'N/A'}`); }); // Try to inject each matching card let anyInjected = false; cards.forEach(card => { let placed = false; // Placement logic if (!placed && card.placement) { if (card.placement.toLowerCase() === 'start' && products.length > 0) { console.log('Inserting module at START (before first product)'); insertModule(products[0], 'before', card); placed = true; } else if (card.placement.toLowerCase() === 'end' && products.length > 0) { console.log('Inserting module at END (after last product)'); insertModule(products[products.length - 1], 'after', card); placed = true; } } // Fallbacks: by product code or position if (!placed) { for (let i = 0; i < products.length; i++) { const code = getProductCode(products[i]); if (card.insertAfterProductCode && code === card.insertAfterProductCode) { console.log(`Inserting module AFTER product code: ${code}`); insertModule(products[i], 'after', card); placed = true; break; } if (card.insertBeforeProductCode && code === card.insertBeforeProductCode) { console.log(`Inserting module BEFORE product code: ${code}`); insertModule(products[i], 'before', card); placed = true; break; } } } if (!placed && card.insertAtPosition) { let targetProduct = null; // Try to find by data-position attribute first targetProduct = Array.from(products).find(p => parseInt(p.getAttribute('data-position')) === card.insertAtPosition ); // If not found, fallback to Nth product in the array (1-based) if (!targetProduct && products.length >= card.insertAtPosition) { targetProduct = products[card.insertAtPosition - 1]; } // If still not found, fallback to last product in gridInner if (!targetProduct && products.length > 0) { targetProduct = products[products.length - 1]; } if (targetProduct) { console.log(`Inserting module after product (insertAtPosition=${card.insertAtPosition})`); insertModule(targetProduct, 'after', card); placed = true; } } if (!placed) { console.warn(`Target not found for card. Check insertAfterProductCode, insertBeforeProductCode, or insertAtPosition configuration.`); } else { anyInjected = true; } }); if (anyInjected) { injected = true; // Ensure any end-placed cards are positioned after the latest product set repositionEndCards(); } } function insertModule(target, position, cardConfig) { const wrapper = document.createElement('div'); wrapper.innerHTML = generateModuleHTML(cardConfig).trim(); const base = target.closest && target.closest('[data-product-code], [data-product-id], .product-item, .product-card, .product-tile, .product, .js-product, article.product, .product-grid-item, .product-list-item') || target; const baseTag = (base.tagName || '').toLowerCase(); const safeTag = (baseTag === 'button' || baseTag === 'a') ? 'div' : (baseTag || 'div'); const classList = (base.className || '') .split(/\s+/) .filter(Boolean) .filter(c => !/(^|-)btn($|-)|button|cta|add-to-cart|purchase|subscribe|link/i.test(c)) .join(' '); const container = document.createElement(safeTag); if (classList) container.className = classList; container.setAttribute('data-copilot-module', 'true'); if (cardConfig && cardConfig.placement) { container.setAttribute('data-copilot-placement', String(cardConfig.placement).toLowerCase()); } container.appendChild(wrapper.firstElementChild); if (position === 'after') { base.parentNode.insertBefore(container, base.nextSibling); } else { base.parentNode.insertBefore(container, base); } // Make entire card clickable if data-card-href is present const clickable = container.querySelector('.rf-card-clickable[data-card-href]'); if (clickable) { const href = clickable.getAttribute('data-card-href'); clickable.setAttribute('role', 'link'); clickable.setAttribute('tabindex', '0'); const navigate = () => { try { window.location.assign(href); } catch(e) { window.location.href = href; } }; clickable.addEventListener('click', (e) => { const insideAnchor = e.target.closest('a'); if (insideAnchor) return; // allow inner links like CTA/disclaimer navigate(); }); clickable.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); navigate(); } }); } console.log('Marketing module injected successfully!'); } // Reposition any cards configured with placement: 'End' after dynamic loads function repositionEndCards() { const endCards = Array.from(document.querySelectorAll('[data-copilot-module="true"][data-copilot-placement="end"]')); if (endCards.length === 0) return; // Determine current product list inside grid const gridInner = document.querySelector('.mdc-layout-grid__inner'); const productSelector = '[data-product-code], [data-product-id], .product-item, .product-card, .product-tile, .product, .js-product, article.product, .product-grid-item, .product-list-item'; let products = []; if (gridInner) { products = Array.from(gridInner.querySelectorAll(productSelector)); } else { products = Array.from(document.querySelectorAll(productSelector)); } products = products.filter(el => !el.hasAttribute('data-copilot-module')); if (products.length === 0) return; const lastProduct = products[products.length - 1]; endCards.forEach(card => { if (lastProduct.nextSibling !== card) { try { lastProduct.parentNode.insertBefore(card, lastProduct.nextSibling); } catch (e) {} } }); } function isModulePresent() { return document.querySelector('[data-copilot-module="true"]') !== null; } // ============================================ // INITIALIZATION - IMMEDIATE LOAD // ============================================ function init() { injectModule(); // Quick retries for fast page load if (!injected) { setTimeout(injectModule, 100); setTimeout(injectModule, 300); setTimeout(injectModule, 500); setTimeout(injectModule, 1000); } } // Run immediately init(); // Also run on DOMContentLoaded as backup if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } // Watch for dynamically loaded products const observer = new MutationObserver(() => { clearTimeout(window.moduleInjectionTimeout); window.moduleInjectionTimeout = setTimeout(() => { if (!isModulePresent()) { injected = false; injectModule(); } repositionEndCards(); }, 120); }); // Start observing immediately const startObserver = () => { const container = document.querySelector('.product-grid, .product-list, .products, main, body'); if (container) { observer.observe(container, { childList: true, subtree: true }); } }; startObserver(); setTimeout(startObserver, 500); })();