// Wait for the DOM to be fully loaded document.addEventListener('DOMContentLoaded', function() { // Set up comment form placeholders const authorField = document.getElementById('author'); const emailField = document.getElementById('email'); const commentField = document.getElementById('comment'); if (authorField) authorField.placeholder = 'Your name'; if (emailField) emailField.placeholder = 'Your email'; if (commentField) commentField.placeholder = 'Write Your Review Here...'; }); // Breadcrumbs: URL color change document.addEventListener("DOMContentLoaded", function () { const breadcrumb = document.querySelector(".woocommerce-breadcrumb"); if (breadcrumb && breadcrumb.childNodes) { breadcrumb.childNodes.forEach(node => { if ( node.nodeType === Node.TEXT_NODE && node.textContent.trim().length > 0 ) { const span = document.createElement("span"); span.className = "current-product"; span.textContent = node.textContent.trim(); breadcrumb.replaceChild(span, node); } }); } }); jQuery(document).ready(function($) { console.log('Quick View Script Loaded'); // Helper function to find matching variation function findMatchingVariation(variations, attributes) { console.log('Finding variation with:', { variations: variations, selectedAttributes: attributes }); if (!variations || !Array.isArray(variations)) { console.error('Invalid variations data:', variations); return null; } // Convert attributes to lowercase and remove 'pa_' prefix for comparison const normalizedAttributes = {}; Object.entries(attributes).forEach(([key, value]) => { if (value) { // Remove 'pa_' prefix if it exists and convert to lowercase const normalizedKey = key.replace('pa_', '').toLowerCase(); normalizedAttributes[normalizedKey] = value.toLowerCase(); } }); console.log('Normalized selected attributes:', normalizedAttributes); const matchingVariation = variations.find(variation => { if (!variation || !variation.attributes) { console.log('Invalid variation:', variation); return false; } // Convert variation attributes to lowercase and remove 'pa_' prefix const normalizedVariationAttrs = {}; Object.entries(variation.attributes).forEach(([key, value]) => { const normalizedKey = key.replace('pa_', '').toLowerCase(); normalizedVariationAttrs[normalizedKey] = (value || '').toLowerCase(); }); console.log('Checking variation:', { variation_id: variation.variation_id, normalizedVariationAttrs, is_in_stock: variation.is_in_stock, has_image: !!(variation.image && variation.image.src) }); // Check if all selected attributes match the variation const matches = Object.entries(normalizedAttributes).every(([attribute, value]) => { const variationValue = normalizedVariationAttrs[attribute]; // If variation doesn't specify this attribute or it's empty, it's a wildcard match if (!variationValue || variationValue === '') { console.log(`Attribute ${attribute} is wildcard in variation`); return true; } const isMatch = variationValue === value; console.log(`Comparing ${attribute}: selected=${value} with variation=${variationValue} = ${isMatch}`); return isMatch; }); console.log(`Variation ${variation.variation_id} matches: ${matches}`); return matches; }); if (matchingVariation) { console.log('Found matching variation:', { variation_id: matchingVariation.variation_id, attributes: matchingVariation.attributes, is_in_stock: matchingVariation.is_in_stock, image_src: matchingVariation.image ? matchingVariation.image.src : 'No image' }); } else { console.log('No matching variation found'); } return matchingVariation; } // Function to update variation availability function updateVariationAvailability($form) { const selectedAttributes = {}; $form.find('select.variation-select').each(function() { const $select = $(this); const name = $select.attr('name'); const value = $select.val(); console.log(`Processing select: ${name} = ${value}`); if (value) { selectedAttributes[name] = value; } }); console.log('Selected attributes:', selectedAttributes); console.log('Available variations:', window.quickViewVariations); const $addToCartBtn = $form.find('.single_add_to_cart_button'); const $variationNotAvailable = $form.find('.variation-availability'); // If not all variations are selected const allSelected = areAllVariationsSelected($form); console.log('All variations selected:', allSelected); if (!allSelected) { $addToCartBtn.addClass('disabled').prop('disabled', true); $variationNotAvailable.html('Please select all options').show(); return; } // Find matching variation const matchingVariation = findMatchingVariation(window.quickViewVariations.data, selectedAttributes); console.log('Matching variation result:', matchingVariation); if (!matchingVariation) { $addToCartBtn.addClass('disabled').prop('disabled', true); $variationNotAvailable.html('This variation is not available').show(); return; } if (!matchingVariation.is_in_stock) { $addToCartBtn.addClass('disabled').prop('disabled', true); $variationNotAvailable.html('This variation is currently out of stock').show(); return; } // Update price if available if (matchingVariation.price_html) { $form.closest('.quick-view-modal').find('.product-price').html(matchingVariation.price_html); } // Update image if available if (matchingVariation.image && matchingVariation.image.src) { var $modal = $form.closest('.quick-view-modal'); console.log('Variation image update:', matchingVariation.image.src); console.log('Modal found:', $modal.length); console.log('Main image found:', $modal.find('.main-product-image').length); // Update the main image to show the variation $modal.find('.main-product-image').attr('src', matchingVariation.image.src); // Update the active thumbnail to match the variation image var $thumbnails = $modal.find('.flex-control-thumbs li'); $thumbnails.removeClass('flex-active'); // Find and activate the thumbnail that matches the variation image $thumbnails.each(function() { var $thumb = $(this); var thumbSrc = $thumb.find('img').attr('src'); if (thumbSrc === matchingVariation.image.src) { $thumb.addClass('flex-active'); } }); console.log('Variation image updated to:', matchingVariation.image.src); } // Enable add to cart button and store variation ID $addToCartBtn.removeClass('disabled').prop('disabled', false); $addToCartBtn.data('variation_id', matchingVariation.variation_id); $variationNotAvailable.hide(); console.log('Button enabled with variation ID:', matchingVariation.variation_id); } // Function to check if all variations are selected function areAllVariationsSelected($form) { let allSelected = true; $form.find('select.variation-select').each(function() { const value = $(this).val(); console.log(`Checking select value: ${$(this).attr('name')} = ${value}`); if (!value) { allSelected = false; return false; } }); return allSelected; } // Add Quick View buttons to products function addQuickViewButtons() { // Don't add buttons on single product pages if ($('body').hasClass('single-product')) { return; } console.log('Adding quick view buttons'); $('.product').each(function() { var $product = $(this); var $image = $product.find('a img'); var $container = $image.length ? $image.parent() : $product; // Only add if there isn't already a quick-view-btn and we're not on a single product if (!$container.find('.quick-view-btn').length && !$('body').hasClass('single-product')) { $container.css('position', 'relative'); // Get product URL from the first link in the product var productUrl = $product.find('a:first').attr('href') || '#'; // Create button wrapper var $buttonWrapper = $('
'); // Add Quick View button with improved styling $buttonWrapper.append(''); // Add buttons to container $container.append($buttonWrapper); // Ensure the container has proper positioning if ($container.css('position') === 'static') { $container.css('position', 'relative'); } } }); } // Debounce function function debounce(func, wait) { var timeout; return function() { var context = this, args = arguments; clearTimeout(timeout); timeout = setTimeout(function() { func.apply(context, args); }, wait); }; } // Initialize buttons and set up event listeners function initQuickView() { addQuickViewButtons(); // Handle pagination clicks $(document).on('click', '.woocommerce-pagination a', function() { setTimeout(addQuickViewButtons, 1000); }); // Handle WooCommerce specific events $('body').on('updated_wc_div', addQuickViewButtons); $('body').on('wc_fragments_refreshed', addQuickViewButtons); $('body').on('wc_fragments_loaded', addQuickViewButtons); $('body').on('wc_update_page', addQuickViewButtons); // Handle scroll events with debounce $(window).on('scroll', debounce(function() { addQuickViewButtons(); }, 250)); } // Initialize on document ready initQuickView(); // Handle AJAX completions $(document).ajaxComplete(function(event, xhr, settings) { setTimeout(addQuickViewButtons, 500); }); // Watch for DOM changes in the products container function setupObserver() { var productsContainer = $('.products')[0]; if (productsContainer) { var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (mutation.type === 'childList') { addQuickViewButtons(); } }); }); observer.observe(productsContainer, { childList: true, subtree: true }); } } // Set up the observer setupObserver(); // Handle Quick View button click $(document).on('click', '.quick-view-btn', function(e) { e.preventDefault(); e.stopImmediatePropagation(); e.stopPropagation(); console.log('Quick view button clicked', e); // Make sure the click didn't come from a child element if (e.target !== this) { return; } var $trigger = $(this); var $product = $trigger.closest('.product'); console.log('Product container found:', $product.length > 0); // Get product details var title = $product.find('.wp-block-post-title, .woocommerce-loop-product__title').first().text().trim(); if (!title) { title = $product.find('h2, h3').first().text().trim(); } var price = $product.find('.price').html() || ''; var mainImage = $product.find('img').first().attr('src'); // Get all product images including variations var images = []; $product.find('img').each(function() { var imgSrc = $(this).attr('src'); if (imgSrc && !images.includes(imgSrc)) { images.push(imgSrc); } }); console.log('Images collected from DOM:', images); // Store images globally for variation updates window.quickViewImages = images; // Get product ID from data attribute (numeric ID) var productId = $product.data('wp-context')?.productId || $product.data('product_id') || $product.data('id') || $product.attr('id')?.replace('product-', '') || $product.find('[data-product_id]').first().data('product_id'); // If we still don't have a numeric ID, try to extract it from the slug if (!productId || isNaN(productId)) { // Check if we have a slug and need to convert it to ID var slug = $product.attr('class')?.match(/post-(\d+)/); if (slug && slug[1]) { productId = slug[1]; } else { // Try to get from the product link as a last resort var productLink = $product.find('a[href*="product/"]').attr('href') || $product.find('a').filter(function() { return $(this).attr('href') && $(this).attr('href').includes('product/'); }).attr('href'); if (productLink) { var matches = productLink.match(/product\/([^\/]+)/); if (matches && matches[1]) { var slug = matches[1]; // If we got a slug, we'll need to make an AJAX request to get the ID // We'll handle this case in the AJAX call } } } } console.log('Product ID:', productId); console.log('Product element:', $product[0]); if (!productId) { console.error('Could not find product ID. Please check the product element structure.'); console.log('Available data attributes:', $product.data()); return; } // Check if we have a numeric ID or a slug var isNumericId = !isNaN(productId); console.log('Product ID type:', isNumericId ? 'Numeric ID' : 'Slug', productId); // Make AJAX call to get full product details $.ajax({ url: blynex_quick_view_params.ajax_url, type: 'POST', data: { action: 'get_product_details', product_id: productId, is_slug: isNumericId ? 0 : 1, // Tell the server if we're using a slug security: blynex_quick_view_params.ajax_nonce || '' }, success: function(response) { if (response.success) { console.log('AJAX Response:', response); var data = response.data; description = data.description; sku = data.sku; categories = data.categories; rating = data.rating; price = data.price || ''; // Log review count data for debugging console.log('Review count data:', { review_count: data.review_count, data_keys: Object.keys(data) }); // Store review count for use in the template var reviewCount = data.review_count || 0; // Process variations data var variations = data.variations || {}; console.log('Raw variations data:', variations); // Create variations HTML if product has variations var variationsHtml = ''; if (variations.attributes && Object.keys(variations.attributes).length > 0) { console.log('Processing variation attributes:', variations.attributes); variationsHtml = '