ambreramos Posted September 19, 2024 Share Posted September 19, 2024 Bonjour, je travaille actuellement sur un site sous Prestashop 1.7.8.8, sur lequel j'aimerais faire en sorte que sur toute fiche produit comportant des déclinaisons, l'utilisateur puisse sélectionner plusieurs déclinaisons ainsi que leur quantité, et que le tout s'ajoute au panier lors du clic sur le bouton "Ajouter au panier". J'ai trouvé ce tutoriel dont la majorité semble être fonctionnelle, mais il me reste quelques soucis quant à la sélection multiple ainsi qu'à l'ajout au panier. Voici à quoi ressemble actuellement ma page de produit : Je ne peux toujours pas sélectionner plusieurs produits (par conséquent, je ne peux pas non plus entrer plusieurs quantités) et lorsque j'essaie de réaliser l'une de ces deux actions, un refresh Ajax réinitialise toutes les entrées. Au niveau de l'ajout au panier, je pense que mon problème vient également de l'impossibilité de sélection multiple : peu importe pour quelle déclinaison j'entre une quantité, disons 20, cela m'ajoutera bien 20 entrées dans le panier, mais avec la déclinaison par défaut et non celle que j'ai sélectionné. J'ai aussi un problème d'affichage : seul le champ d'entrée de quantité apparaît, mais pas les boutons + et - à côté... Voici tous les fichiers que j'ai modifié pour en arriver là : themes/classic/templates/catalog/_partials/product-add-to-cart.tpl : {** * Copyright since 2007 PrestaShop SA and Contributors * PrestaShop is an International Registered Trademark & Property of PrestaShop SA * * NOTICE OF LICENSE * * This source file is subject to the Academic Free License 3.0 (AFL-3.0) * that is bundled with this package in the file LICENSE.md. * It is also available through the world-wide-web at this URL: * https://opensource.org/licenses/AFL-3.0 * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to [email protected] so we can send you a copy immediately. * * DISCLAIMER * * Do not edit or add to this file if you wish to upgrade PrestaShop to newer * versions in the future. If you wish to customize PrestaShop for your * needs please refer to https://devdocs.prestashop.com/ for more information. * * @author PrestaShop SA and Contributors <contact@prestashop.com> * @copyright Since 2007 PrestaShop SA and Contributors * @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0) *} <div class="product-add-to-cart js-product-add-to-cart"> {if !$configuration.is_catalog} <span class="control-label">{l s='Quantity' d='Shop.Theme.Catalog'}</span> {if $product.id_product_attribute > 0} {block name='product_quantity'} <div class="product-quantity clearfix"> <div class="add"> <button class="btn btn-primary add-to-cart" data-button-action="multi-add-to-cart" type="submit" {if !$product.add_to_cart_url} disabled {/if} > <i class="material-icons shopping-cart"></i> {l s='Add to cart' d='Shop.Theme.Actions'} </button> </div> {hook h='displayProductActions' product=$product} </div> {/block} {block name='product_availability'} <span id="product-availability" class="js-product-availability"> {if $product.show_availability && $product.availability_message} {if $product.availability == 'available'} <i class="material-icons rtl-no-flip product-available"></i> {elseif $product.availability == 'last_remaining_items'} <i class="material-icons product-last-items"></i> {else} <i class="material-icons product-unavailable"></i> {/if} {$product.availability_message} {/if} </span> {/block} {block name='product_minimal_quantity'} <p class="product-minimal-quantity js-product-minimal-quantity"> {if $product.minimal_quantity > 1} {l s='The minimum purchase order quantity for the product is %quantity%.' d='Shop.Theme.Checkout' sprintf=['%quantity%' => $product.minimal_quantity] } {/if} </p> {/block} {else} <!-- Si le produit n'a pas d'attribut, le bouton reste standard --> {block name='product_quantity'} <div class="product-quantity clearfix"> <div class="qty"> <input type="number" name="qty" id="quantity_wanted" inputmode="numeric" pattern="[0-9]*" {if $product.quantity_wanted} value="{$product.quantity_wanted}" min="{$product.minimal_quantity}" {else} value="1" min="1" {/if} class="input-group" aria-label="{l s='Quantity' d='Shop.Theme.Actions'}" > </div> <div class="add"> <button class="btn btn-primary add-to-cart" data-button-action="add-to-cart" type="submit" {if !$product.add_to_cart_url} disabled {/if} > <i class="material-icons shopping-cart"></i> {l s='Add to cart' d='Shop.Theme.Actions'} </button> </div> {hook h='displayProductActions' product=$product} </div> {/block} {/if} {/if} </div> themes/classic/templates/catalog/_partials/product-variants.tpl : {** * Copyright since 2007 PrestaShop SA and Contributors * PrestaShop is an International Registered Trademark & Property of PrestaShop SA * * NOTICE OF LICENSE * * This source file is subject to the Academic Free License 3.0 (AFL-3.0) * that is bundled with this package in the file LICENSE.md. * It is also available through the world-wide-web at this URL: * https://opensource.org/licenses/AFL-3.0 * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to [email protected] so we can send you a copy immediately. * * DISCLAIMER * * Do not edit or add to this file if you wish to upgrade PrestaShop to newer * versions in the future. If you wish to customize PrestaShop for your * needs please refer to https://devdocs.prestashop.com/ for more information. * * @author PrestaShop SA and Contributors <contact@prestashop.com> * @copyright Since 2007 PrestaShop SA and Contributors * @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0) *} <div class="product-variants js-product-variants"> {foreach from=$groups key=id_attribute_group item=group} {if !empty($group.attributes)} <div class="clearfix product-variants-item"> <span class="control-label">{$group.name}{l s=': ' d='Shop.Theme.Catalog'} {foreach from=$group.attributes key=id_attribute item=group_attribute} {if $group_attribute.selected}{$group_attribute.name}{/if} {/foreach} </span> {if $group.group_type == 'select'} <select class="form-control form-control-select" id="group_{$id_attribute_group}" aria-label="{$group.name}" data-product-attribute="{$id_attribute_group}" name="group[{$id_attribute_group}]"> {foreach from=$group.attributes key=id_attribute item=group_attribute} <option value="{$id_attribute}" title="{$group_attribute.name}"{if $group_attribute.selected} selected="selected"{/if}>{$group_attribute.name}</option> {/foreach} </select> <div class="num"> <span type="button" class="reduc btn btn-md"><i class="icon-minus" id="reduc"></i></span> <input type="text" class="multi_product_quantity" value="0"/> <span type="button" class="add btn btn-md"><i class="icon-plus" id="add"></i></span> </div> {elseif $group.group_type == 'color'} <ul id="group_{$id_attribute_group}"> {foreach from=$group.attributes key=id_attribute item=group_attribute} <li class="float-xs-left input-container"> <label aria-label="{$group_attribute.name}"> <input class="input-color" type="radio" data-product-attribute="{$id_attribute_group}" name="group[{$id_attribute_group}]" value="{$id_attribute}" title="{$group_attribute.name}"{if $group_attribute.selected} checked="checked"{/if}> <span {if $group_attribute.texture} class="color texture" style="background-image: url({$group_attribute.texture})" {elseif $group_attribute.html_color_code} class="color" style="background-color: {$group_attribute.html_color_code}" {/if} ><span class="attribute-name sr-only">{$group_attribute.name}</span></span> </label> <div class="num"> <span type="button" class="reduc btn btn-md"><i class="icon-minus" id="reduc"></i></span> <input type="text" class="multi_product_quantity" value="0"/> <span type="button" class="add btn btn-md"><i class="icon-plus" id="add"></i></span> </div> </li> {/foreach} </ul> {elseif $group.group_type == 'radio'} <ul id="group_{$id_attribute_group}"> {foreach from=$group.attributes key=id_attribute item=group_attribute} <li class="input-container float-xs-left"> <label> <input class="input-radio" type="radio" data-product-attribute="{$id_attribute_group}" name="group[{$id_attribute_group}]" value="{$id_attribute}" title="{$group_attribute.name}"{if $group_attribute.selected} checked="checked"{/if}> <span class="radio-label">{$group_attribute.name}</span> </label> <div class="num"> <span type="button" class="reduc btn btn-md"><i class="icon-minus" id="reduc"></i></span> <input type="text" class="multi_product_quantity" value="0"/> <span type="button" class="add btn btn-md"><i class="icon-plus" id="add"></i></span> </div> </li> {/foreach} </ul> {/if} </div> {/if} {/foreach} </div> themes/classic/assets/js/custom.js : $(document).ready(function () { // Object to hold selected quantities per attribute combination let selectedQuantities = {}; // Function to store quantity in memory function updateSelectedQuantities($input, idAttributeGroup, idAttribute) { const quantity = parseInt($input.val(), 10); if (!selectedQuantities[idAttributeGroup]) { selectedQuantities[idAttributeGroup] = {}; } selectedQuantities[idAttributeGroup][idAttribute] = quantity; } // Function to restore quantity from memory function restoreSelectedQuantities() { $('.multi_product_quantity').each(function () { const $input = $(this); const idAttributeGroup = $input.closest('.product-variants-item').find('[data-product-attribute]').attr('data-product-attribute'); const idAttribute = $input.closest('.product-variants-item').find('[data-product-attribute]').val(); if (selectedQuantities[idAttributeGroup] && selectedQuantities[idAttributeGroup][idAttribute] !== undefined) { $input.val(selectedQuantities[idAttributeGroup][idAttribute]); } }); } // Function to reset default combination from being added function resetDefaultCombination() { $('input[name="group[default]"]').prop('checked', false); } // Increment quantity and update memory $(".icon-plus").each(function () { $(this).click(function () { const $input = $(this).parent().prev(); // The quantity input field let quantity = parseInt($input.val(), 10); quantity++; $input.val(quantity); const idAttributeGroup = $(this).closest('.product-variants-item').find('[data-product-attribute]').attr('data-product-attribute'); const idAttribute = $(this).closest('.product-variants-item').find('[data-product-attribute]').val(); updateSelectedQuantities($input, idAttributeGroup, idAttribute); // Check the corresponding color, radio, or select input var attributeInput = $(this).closest('.product-variants-item').find('.input-color, .input-radio, select'); if (quantity > 0 && attributeInput.length > 0) { attributeInput.prop('checked', true).trigger('change'); } // Reset the default combination resetDefaultCombination(); }); }); // Decrement quantity and update memory $(".icon-minus").each(function () { $(this).click(function () { const $input = $(this).parent().next(); // The quantity input field let quantity = parseInt($input.val(), 10); if (quantity > 0) { quantity--; $input.val(quantity); const idAttributeGroup = $(this).closest('.product-variants-item').find('[data-product-attribute]').attr('data-product-attribute'); const idAttribute = $(this).closest('.product-variants-item').find('[data-product-attribute]').val(); updateSelectedQuantities($input, idAttributeGroup, idAttribute); // Uncheck the color, radio, or select input if quantity is 0 if (quantity === 0) { var attributeInput = $(this).closest('.product-variants-item').find('.input-color, .input-radio, select'); if (attributeInput.length > 0) { attributeInput.prop('checked', false).trigger('change'); } } } // Reset the default combination resetDefaultCombination(); }); }); // Handle changes in dropdowns or radio buttons and restore quantities $('.product-variants-item select, .product-variants-item .input-radio').change(function () { restoreSelectedQuantities(); }); // Handle multi-add-to-cart button const $body = $('body'); $body.on('click', '[data-button-action="multi-add-to-cart"]', (event) => { event.preventDefault(); // Prevent the default form submission const $form = $(event.target.form); const actionURL = $form.attr('action'); // Find all quantity inputs with value > 0 var wantedItems = $('.multi_product_quantity').filter(function () { return parseInt($(this).val(), 10) > 0; }); if (wantedItems.length === 0) { alert("Please select at least one product with quantity."); return; } // Prevent default combination from being added resetDefaultCombination(); // Collect all requests let requests = wantedItems.map(function (index, item) { var $item = $(item); var quantity = parseInt($item.val(), 10); if (quantity > 0) { // Get the associated product attribute (color, radio, or select) var attributeInput = $item.closest('.product-variants-item').find('.input-color, .input-radio, select'); if (attributeInput.length > 0) { var idProduct = document.getElementsByName('id_product')[0].value; var idProductAttribute = attributeInput.val(); var group = attributeInput.attr('data-product-attribute'); // Build the query string for this combination var query = `${$form.serialize()}&add=1&action=update&id_product=${idProduct}&qty=${quantity}&group[${group}]=${idProductAttribute}&ipa=${idProductAttribute}`; // Return the AJAX request promise return $.post(actionURL, query, null, 'json'); } } }).get(); // Execute all requests $.when.apply($, requests) .done(function () { prestashop.emit('updateCart', { reason: {}, resp: arguments, }); // Optionally, refresh the page after all requests are completed setTimeout(function () { location.reload(); // Refresh the page after a delay }, 2000); // Adjust the delay as needed }) .fail(function (resp) { prestashop.emit('handleError', { eventType: 'addProductToCart', resp }); }); }); }); et également, ces quelques lignes dans themes/classic/assets/css/theme.css : .num{ padding-left:10px; display: inline-block; float: right; } .icon-plus .icon-minus{ color: black !important; font-size: 1.5rem; } Si quelqu'un peut m'aider ou m'expliquer comment résoudre ces problèmes, c'est avec grand plaisir Link to comment Share on other sites More sharing options...
Mikatypics Posted October 12, 2024 Share Posted October 12, 2024 Bonjour Je cherches à faire la même chose pour ma boutique. (voir fichier joint) Je suis d'ailleurs étonné qu'aucun module (ou alors j'ai mal cherché) ne propose d'ajouter cette fonction. Merci pour le lien vers le tuto, je vais tenter de le mettre en place sur mon dev et je tacherais de vous faire un retour, si ça peut aider ! Link to comment Share on other sites More sharing options...
Mikatypics Posted October 23, 2024 Share Posted October 23, 2024 Je n'ai pas réussi non plus à obtenir quelque chose de satisfaisant. Et toujours à la recherche d'un module à la fois simple et efficace, comme la capture d'écran si dessus. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now