app/template/default/Product/list.twig line 1

Open in your IDE?
  1. {#
  2. This file is part of EC-CUBE
  3. Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
  4. http://www.ec-cube.co.jp/
  5. For the full copyright and license information, please view the LICENSE
  6. file that was distributed with this source code.
  7. #}
  8. {% extends 'default_frame.twig' %}
  9. {% set body_class = 'product_page' %}
  10. {# style #}
  11. {% block stylesheet %}
  12.     <link rel="stylesheet" href="{{ asset('assets/css/product-list.css') }}">
  13. {% endblock %}
  14. {% block javascript %}
  15. <script>
  16. (function() {
  17.     // Lấy URL hiện tại và tạo URLSearchParams
  18.     function getCurrentUrlParams() {
  19.         const urlParams = new URLSearchParams(window.location.search);
  20.         return urlParams;
  21.     }
  22.     // Cập nhật URL với category filters và reload
  23.     function updateCategoryFilters() {
  24.         const checkboxes = document.querySelectorAll('.filter-option__checkbox');
  25.         const urlParams = getCurrentUrlParams();
  26.         // Xóa tất cả category_filter[] cũ (có thể có nhiều giá trị)
  27.         const keysToDelete = [];
  28.         urlParams.forEach(function(value, key) {
  29.             if (key === 'category_filter[]' || key.startsWith('category_filter')) {
  30.                 keysToDelete.push(key);
  31.             }
  32.         });
  33.         keysToDelete.forEach(function(key) {
  34.             urlParams.delete(key);
  35.         });
  36.         // Thu thập category theo từng block tiêu chí.
  37.         // Trong cùng block là OR, giữa các block sẽ được backend xử lý là AND.
  38.         const selectedCategoriesByGroup = {};
  39.         checkboxes.forEach(function(checkbox) {
  40.             if (checkbox.checked) {
  41.                 const groupId = checkbox.dataset.groupId;
  42.                 if (!selectedCategoriesByGroup[groupId]) {
  43.                     selectedCategoriesByGroup[groupId] = [];
  44.                 }
  45.                 selectedCategoriesByGroup[groupId].push(checkbox.value);
  46.             }
  47.         });
  48.         Object.keys(selectedCategoriesByGroup).forEach(function(groupId) {
  49.             selectedCategoriesByGroup[groupId].forEach(function(categoryId) {
  50.                 urlParams.append('category_filter[' + groupId + '][]', categoryId);
  51.             });
  52.         });
  53.         // Reset về trang 1 khi filter
  54.         urlParams.set('pageno', '1');
  55.         // Tạo URL mới
  56.         const queryString = urlParams.toString();
  57.         const newUrl = queryString
  58.             ? window.location.pathname + '?' + queryString
  59.             : window.location.pathname;
  60.         // Reload page với query params mới
  61.         window.location.href = newUrl;
  62.     }
  63.     // Khôi phục trạng thái checkbox từ URL và xử lý nút search
  64.     document.addEventListener('DOMContentLoaded', function() {
  65.         const checkboxes = document.querySelectorAll('.filter-option__checkbox');
  66.         const searchButton = document.querySelector('.btn-search');
  67.         // Khôi phục trạng thái checkbox từ URL
  68.         const urlParams = getCurrentUrlParams();
  69.         const selectedCategories = [];
  70.         urlParams.forEach(function(value, key) {
  71.             if (key.startsWith('category_filter[')) {
  72.                 selectedCategories.push(value);
  73.             }
  74.         });
  75.         checkboxes.forEach(function(checkbox) {
  76.             // Set checked nếu category ID có trong URL
  77.             if (selectedCategories.includes(checkbox.value)) {
  78.                 checkbox.checked = true;
  79.             }
  80.             // Không lắng nghe sự kiện change trên checkbox nữa
  81.         });
  82.         // Lắng nghe sự kiện click trên nút search
  83.         if (searchButton) {
  84.             searchButton.addEventListener('click', function() {
  85.                 updateCategoryFilters();
  86.             });
  87.         }
  88.     });
  89. })();
  90. </script>
  91. {% endblock %}
  92. {% block main %}
  93.  <body>
  94.   <!-- breadcrumb section -->
  95.   <div class="breadcrumb-section">
  96.     <div class="container-1360 border-box px-40">
  97.       <nav class="breadcrumb">
  98.         <a href="{{ url('homepage') }}" class="breadcrumb__item text-black">ホーム</a>
  99.         <img src="{{ asset('assets/img/default/icons/icon-breadcrumb-arrow.svg') }}" alt=">" class="breadcrumb__separator">
  100.         <a href="{{ url('product_list') }}" class="breadcrumb__item text-black">商品一覧</a>
  101.       </nav>
  102.     </div>
  103.   </div>
  104.   <!-- product list section -->
  105.   <div class="container-1200">
  106.     <div class="product-list-wrapper">
  107.       <div class="product-list-left">
  108.         {% if searchable_categories is defined and searchable_categories|length > 0 %}
  109.           {% for group in searchable_categories %}
  110.             <div class="filter-group">
  111.               <div class="filter-group__header">{{ group.parent.name }}</div>
  112.               <div class="filter-group__options">
  113.                 {% if group.children|length > 0 %}
  114.                   {% for child in group.children %}
  115.                     <label class="filter-option">
  116.                       <input type="checkbox"
  117.                              class="filter-option__checkbox"
  118.                              name="category_filter[{{ group.parent.id }}][]"
  119.                              value="{{ child.id }}"
  120.                              data-category-id="{{ child.id }}"
  121.                              data-group-id="{{ group.parent.id }}">
  122.                       <span class="filter-option__label">{{ child.name }}</span>
  123.                     </label>
  124.                   {% endfor %}
  125.                 {% else %}
  126.                   {# Nếu parent category cũng có is_searchable và không có children, hiển thị parent #}
  127.                   <label class="filter-option">
  128.                     <input type="checkbox"
  129.                            class="filter-option__checkbox"
  130.                            name="category_filter[{{ group.parent.id }}][]"
  131.                            value="{{ group.parent.id }}"
  132.                            data-category-id="{{ group.parent.id }}"
  133.                            data-group-id="{{ group.parent.id }}">
  134.                     <span class="filter-option__label">{{ group.parent.name }}</span>
  135.                   </label>
  136.                 {% endif %}
  137.               </div>
  138.             </div>
  139.           {% endfor %}
  140.         {% endif %}
  141.         <button class="btn-primary btn-search w-100">
  142.             <span>検索する</span>
  143.             <svg class="btn-search-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
  144.             <rect width="24" height="24" rx="12" fill="black"/>
  145.             <path d="M16.252 12.001L16.249 12.0039L16.252 12.0068L11.7266 16.5312L10.5957 15.4004L13.1943 12.8027H7.72852V11.2031H13.1924L10.5957 8.60742L11.7266 7.47656L16.252 12.001Z" fill="#FBE800"/>
  146.             </svg>
  147.         </button>
  148.       </div>
  149.       <!-- bottom line -->
  150.       <div class="bottom-line container-mobile"></div>
  151.       <!-- Product List Right -->
  152.       <div class="product-list-right">
  153.         <div class="product-grid" id="product-grid">
  154.           {% if pagination.totalItemCount > 0 %}
  155.             {% for Product in pagination %}
  156.               <div class="product-item">
  157.                 <a href="{{ url('product_detail', {'id': Product.id}) }}" class="product-card-small">
  158.                   <div class="product-card-small__image">
  159.                     <img src="{{ asset(Product.main_list_image|no_image_product, 'save_image') }}" alt="{{ Product.name }}" {% if loop.index > 5 %} loading="lazy"{% endif %}>
  160.                     <div class="product-card-small__arrow">
  161.                         <img src="{{ asset('assets/img/default/icons/icon-heart.svg') }}" alt="Favorite" loading="lazy">
  162.                     </div>
  163.                   </div>
  164.                 </a>
  165.                 <div class="product-item__info">
  166.                   <a href="{{ url('product_detail', {'id': Product.id}) }}">
  167.                     <h4 class="product-item__title" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ Product.name }}">{{ Product.name }}</h4>
  168.                   </a>
  169.                   <div class="product-item__price">
  170.                     <span class="price-symbol">¥</span>
  171.                     <span class="price-amount">
  172.                       {% if Product.hasProductClass %}
  173.                         {% if Product.getPrice02IncTaxMin == Product.getPrice02IncTaxMax %}
  174.                           {{ Product.getPrice02IncTaxMin|number_format }}
  175.                         {% else %}
  176.                           {{ Product.getPrice02IncTaxMin|number_format }} ~ {{ Product.getPrice02IncTaxMax|number_format }}
  177.                         {% endif %}
  178.                       {% else %}
  179.                         {{ Product.getPrice02IncTaxMin|number_format }}
  180.                       {% endif %}
  181.                     </span>
  182.                     <span class="price-tax">(税込)</span>
  183.                   </div>
  184.                 </div>
  185.               </div>
  186.             {% endfor %}
  187.           {% else %}
  188.             <span>{{ 'front.product.search__product_not_found'|trans }}</span>
  189.           {% endif %}
  190.         </div>
  191.         <!-- Pagination -->
  192.         <div class="pagination-product-list-wrapper">
  193.           <div class="pagination-product-list" style="margin: 0 auto;">
  194.             {% include "Block/_pagination.twig" with {'pages': pagination.paginationData} %}
  195.           </div>
  196.         </div>
  197.       </div>
  198.     </div>
  199.   </div>
  200.  </body>
  201. {% endblock %}