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 các category IDs đã được chọn
  37.         const selectedCategoryIds = [];
  38.         checkboxes.forEach(function(checkbox) {
  39.             if (checkbox.checked) {
  40.                 selectedCategoryIds.push(checkbox.value);
  41.             }
  42.         });
  43.         // Chỉ thêm category_filter[] nếu có ít nhất một checkbox được chọn
  44.         if (selectedCategoryIds.length > 0) {
  45.             selectedCategoryIds.forEach(function(categoryId) {
  46.                 urlParams.append('category_filter[]', categoryId);
  47.             });
  48.         }
  49.         // Reset về trang 1 khi filter
  50.         urlParams.set('pageno', '1');
  51.         // Tạo URL mới
  52.         const queryString = urlParams.toString();
  53.         const newUrl = queryString
  54.             ? window.location.pathname + '?' + queryString
  55.             : window.location.pathname;
  56.         // Reload page với query params mới
  57.         window.location.href = newUrl;
  58.     }
  59.     // Khôi phục trạng thái checkbox từ URL và xử lý nút search
  60.     document.addEventListener('DOMContentLoaded', function() {
  61.         const checkboxes = document.querySelectorAll('.filter-option__checkbox');
  62.         const searchButton = document.querySelector('.btn-search');
  63.         // Khôi phục trạng thái checkbox từ URL
  64.         const urlParams = getCurrentUrlParams();
  65.         const selectedCategories = urlParams.getAll('category_filter[]');
  66.         checkboxes.forEach(function(checkbox) {
  67.             // Set checked nếu category ID có trong URL
  68.             if (selectedCategories.includes(checkbox.value)) {
  69.                 checkbox.checked = true;
  70.             }
  71.             // Không lắng nghe sự kiện change trên checkbox nữa
  72.         });
  73.         // Lắng nghe sự kiện click trên nút search
  74.         if (searchButton) {
  75.             searchButton.addEventListener('click', function() {
  76.                 updateCategoryFilters();
  77.             });
  78.         }
  79.     });
  80. })();
  81. </script>
  82. {% endblock %}
  83. {% block main %}
  84.  <body>
  85.   <!-- breadcrumb section -->
  86.   <div class="breadcrumb-section">
  87.     <div class="container-1360 border-box px-40">
  88.       <nav class="breadcrumb">
  89.         <a href="#" class="breadcrumb__item text-black">ホーム</a>
  90.         <img src="{{ asset('assets/img/default/icons/icon-breadcrumb-arrow.svg') }}" alt=">" class="breadcrumb__separator">
  91.         <a href="#" class="breadcrumb__item text-black">商品一覧</a>
  92.       </nav>
  93.     </div>
  94.   </div>
  95.   <!-- product list section -->
  96.   <div class="container-1200">
  97.     <div class="product-list-wrapper">
  98.       <div class="product-list-left">
  99.         {% if searchable_categories is defined and searchable_categories|length > 0 %}
  100.           {% for group in searchable_categories %}
  101.             <div class="filter-group">
  102.               <div class="filter-group__header">{{ group.parent.name }}</div>
  103.               <div class="filter-group__options">
  104.                 {% if group.children|length > 0 %}
  105.                   {% for child in group.children %}
  106.                     <label class="filter-option">
  107.                       <input type="checkbox"
  108.                              class="filter-option__checkbox"
  109.                              name="category_filter[]"
  110.                              value="{{ child.id }}"
  111.                              data-category-id="{{ child.id }}">
  112.                       <span class="filter-option__label">{{ child.name }}</span>
  113.                     </label>
  114.                   {% endfor %}
  115.                 {% else %}
  116.                   {# Nếu parent category cũng có is_searchable và không có children, hiển thị parent #}
  117.                   <label class="filter-option">
  118.                     <input type="checkbox"
  119.                            class="filter-option__checkbox"
  120.                            name="category_filter[]"
  121.                            value="{{ group.parent.id }}"
  122.                            data-category-id="{{ group.parent.id }}">
  123.                     <span class="filter-option__label">{{ group.parent.name }}</span>
  124.                   </label>
  125.                 {% endif %}
  126.               </div>
  127.             </div>
  128.           {% endfor %}
  129.         {% endif %}
  130.         <button class="btn-primary btn-search w-100">
  131.             <span>検索する</span>
  132.             <svg class="btn-search-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
  133.             <rect width="24" height="24" rx="12" fill="black"/>
  134.             <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"/>
  135.             </svg>
  136.         </button>
  137.       </div>
  138.       <!-- bottom line -->
  139.       <div class="bottom-line container-mobile"></div>
  140.       <!-- Product List Right -->
  141.       <div class="product-list-right">
  142.         <div class="product-grid" id="product-grid">
  143.           {% if pagination.totalItemCount > 0 %}
  144.             {% for Product in pagination %}
  145.               <div class="product-item">
  146.                 <a href="{{ url('product_detail', {'id': Product.id}) }}" class="product-card-small">
  147.                   <div class="product-card-small__image">
  148.                     <img src="{{ asset(Product.main_list_image|no_image_product, 'save_image') }}" alt="{{ Product.name }}" {% if loop.index > 5 %} loading="lazy"{% endif %}>
  149.                     <div class="product-card-small__arrow">
  150.                         <img src="{{ asset('assets/img/default/icons/icon-heart.svg') }}" alt="Favorite" loading="lazy">
  151.                     </div>
  152.                   </div>
  153.                 </a>
  154.                 <div class="product-item__info">
  155.                   <a href="{{ url('product_detail', {'id': Product.id}) }}">
  156.                     <h4 class="product-item__title">{{ Product.name }}</h4>
  157.                   </a>
  158.                   <div class="product-item__price">
  159.                     <span class="price-symbol">¥</span>
  160.                     <span class="price-amount">
  161.                       {% if Product.hasProductClass %}
  162.                         {% if Product.getPrice02Min == Product.getPrice02Max %}
  163.                           {{ Product.getPrice02IncTaxMin|price }}
  164.                         {% else %}
  165.                           {{ Product.getPrice02IncTaxMin|price }} ~ {{ Product.getPrice02IncTaxMax|price }}
  166.                         {% endif %}
  167.                       {% else %}
  168.                         {{ Product.getPrice02IncTaxMin|price }}
  169.                       {% endif %}
  170.                     </span>
  171.                     <span class="price-tax">(税込)</span>
  172.                   </div>
  173.                 </div>
  174.               </div>
  175.             {% endfor %}
  176.           {% else %}
  177.             <span>{{ 'front.product.search__product_not_found'|trans }}</span>
  178.           {% endif %}
  179.         </div>
  180.         <!-- Pagination -->
  181.         <div class="pagination-product-list-wrapper">
  182.           <div class="pagination-product-list" style="margin: 0 auto;">
  183.             {% include "Block/_pagination.twig" with {'pages': pagination.paginationData} %}
  184.           </div>
  185.         </div>
  186.       </div>
  187.     </div>
  188.   </div>
  189.  </body>
  190. {% endblock %}