app/template/default/Product/detail.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. {% block stylesheet %}
  11.     <style>
  12.         .slick-slider {
  13.             margin-bottom: 30px;
  14.         }
  15.         .slick-dots {
  16.             position: absolute;
  17.             bottom: -45px;
  18.             display: block;
  19.             width: 100%;
  20.             padding: 0;
  21.             list-style: none;
  22.             text-align: center;
  23.         }
  24.         .slick-dots li {
  25.             position: relative;
  26.             display: inline-block;
  27.             width: 20px;
  28.             height: 20px;
  29.             margin: 0 5px;
  30.             padding: 0;
  31.             cursor: pointer;
  32.         }
  33.         .slick-dots li button {
  34.             font-size: 0;
  35.             line-height: 0;
  36.             display: block;
  37.             width: 20px;
  38.             height: 20px;
  39.             padding: 5px;
  40.             cursor: pointer;
  41.             color: transparent;
  42.             border: 0;
  43.             outline: none;
  44.             background: transparent;
  45.         }
  46.         .slick-dots li button:hover,
  47.         .slick-dots li button:focus {
  48.             outline: none;
  49.         }
  50.         .slick-dots li button:hover:before,
  51.         .slick-dots li button:focus:before {
  52.             opacity: 1;
  53.         }
  54.         .slick-dots li button:before {
  55.             content: " ";
  56.             line-height: 20px;
  57.             position: absolute;
  58.             top: 0;
  59.             left: 0;
  60.             width: 12px;
  61.             height: 12px;
  62.             text-align: center;
  63.             opacity: .25;
  64.             background-color: black;
  65.             border-radius: 50%;
  66.         }
  67.         .slick-dots li.slick-active button:before {
  68.             opacity: .75;
  69.             background-color: black;
  70.         }
  71.         .slick-dots li button.thumbnail img {
  72.             width: 0;
  73.             height: 0;
  74.         }
  75.     </style>
  76. {% endblock %}
  77. {% block javascript %}
  78.     <script>
  79.         eccube.classCategories = {{ class_categories_as_json(Product)|raw }};
  80.         // 規格2に選択肢を割り当てる。
  81.         function fnSetClassCategories(form, classcat_id2_selected) {
  82.             var $form = $(form);
  83.             var product_id = $form.find('input[name=product_id]').val();
  84.             var $sele1 = $form.find('select[name=classcategory_id1]');
  85.             var $sele2 = $form.find('select[name=classcategory_id2]');
  86.             eccube.setClassCategories($form, product_id, $sele1, $sele2, classcat_id2_selected);
  87.         }
  88.         {% if form.classcategory_id2 is defined %}
  89.         fnSetClassCategories(
  90.             $('#form1'), {{ form.classcategory_id2.vars.value|json_encode|raw }}
  91.         );
  92.         {% elseif form.classcategory_id1 is defined %}
  93.         eccube.checkStock($('#form1'), {{ Product.id }}, {{ form.classcategory_id1.vars.value|json_encode|raw }}, null);
  94.         {% endif %}
  95.     </script>
  96.     <script>
  97.         $(function() {
  98.             // bfcache無効化
  99.             $(window).bind('pageshow', function(event) {
  100.                 if (event.originalEvent.persisted) {
  101.                     location.reload(true);
  102.                 }
  103.             });
  104.             // Core Web Vital の Cumulative Layout Shift(CLS)対策のため
  105.             // img タグに width, height が付与されている.
  106.             // 630px 未満の画面サイズでは縦横比が壊れるための対策
  107.             // see https://github.com/EC-CUBE/ec-cube/pull/5023
  108.             $('.ec-grid2__cell').hide();
  109.             var removeSize = function () {
  110.                 $('.slide-item').height('');
  111.                 $('.slide-item img')
  112.                     .removeAttr('width')
  113.                     .removeAttr('height')
  114.                     .removeAttr('style');
  115.             };
  116.             var slickInitial = function(slick) {
  117.                 $('.ec-grid2__cell').fadeIn(1500);
  118.                 var baseHeight = $(slick.target).height();
  119.                 var baseWidth = $(slick.target).width();
  120.                 var rate = baseWidth / baseHeight;
  121.                 $('.slide-item').height(baseHeight * rate); // 余白を削除する
  122.                 // transform を使用することでCLSの影響を受けないようにする
  123.                 $('.slide-item img')
  124.                     .css(
  125.                         {
  126.                             'transform-origin': 'top left',
  127.                             'transform': 'scaleY(' + rate + ')',
  128.                             'transition': 'transform .1s'
  129.                         }
  130.                     );
  131.                 // 正しいサイズに近くなったら属性を解除する
  132.                 setTimeout(removeSize, 500);
  133.             };
  134.             $('.item_visual').on('init', slickInitial);
  135.             // リサイズ時は CLS の影響を受けないため属性を解除する
  136.             $(window).resize(removeSize);
  137.             $('.item_visual').slick({
  138.                 dots: false,
  139.                 arrows: false,
  140.                 responsive: [{
  141.                     breakpoint: 768,
  142.                     settings: {
  143.                         dots: true
  144.                     }
  145.                 }]
  146.             });
  147.             $('.slideThumb').on('click', function() {
  148.                 var index = $(this).attr('data-index');
  149.                 $('.item_visual').slick('slickGoTo', index, false);
  150.             })
  151.         });
  152.     </script>
  153.     <script>
  154.         $(function() {
  155.             $('.add-cart').on('click', function(event) {
  156.                 {% if form.classcategory_id1 is defined %}
  157.                 // 規格1フォームの必須チェック
  158.                 if ($('#classcategory_id1').val() == '__unselected' || $('#classcategory_id1').val() == '') {
  159.                     $('#classcategory_id1')[0].setCustomValidity('{{ '項目が選択されていません'|trans }}');
  160.                     return true;
  161.                 } else {
  162.                     $('#classcategory_id1')[0].setCustomValidity('');
  163.                 }
  164.                 {% endif %}
  165.                 {% if form.classcategory_id2 is defined %}
  166.                 // 規格2フォームの必須チェック
  167.                 if ($('#classcategory_id2').val() == '__unselected' || $('#classcategory_id2').val() == '') {
  168.                     $('#classcategory_id2')[0].setCustomValidity('{{ '項目が選択されていません'|trans }}');
  169.                     return true;
  170.                 } else {
  171.                     $('#classcategory_id2')[0].setCustomValidity('');
  172.                 }
  173.                 {% endif %}
  174.                 // 個数フォームのチェック
  175.                 if ($('#quantity').val() < 1) {
  176.                     $('#quantity')[0].setCustomValidity('{{ '1以上で入力してください。'|trans }}');
  177.                     return true;
  178.                 } else {
  179.                     $('#quantity')[0].setCustomValidity('');
  180.                 }
  181.                 event.preventDefault();
  182.                 $form = $('#form1');
  183.                 $.ajax({
  184.                     url: $form.attr('action'),
  185.                     type: $form.attr('method'),
  186.                     data: $form.serialize(),
  187.                     dataType: 'json',
  188.                     beforeSend: function(xhr, settings) {
  189.                         // Buttonを無効にする
  190.                         $('.add-cart').prop('disabled', true);
  191.                     }
  192.                 }).done(function(data) {
  193.                     // レスポンス内のメッセージをalertで表示
  194.                     $.each(data.messages, function() {
  195.                         $('#ec-modal-header').text(this);
  196.                     });
  197.                     $('.ec-modal').show()
  198.                     // カートブロックを更新する
  199.                     $.ajax({
  200.                         url: "{{ url('block_cart') }}",
  201.                         type: 'GET',
  202.                         dataType: 'html'
  203.                     }).done(function(html) {
  204.                         $('.ec-headerRole__cart').html(html);
  205.                     });
  206.                 }).fail(function(data) {
  207.                     alert('{{ 'カートへの追加に失敗しました。'|trans }}');
  208.                 }).always(function(data) {
  209.                     // Buttonを有効にする
  210.                     $('.add-cart').prop('disabled', false);
  211.                 });
  212.             });
  213.         });
  214.         $('.ec-modal-wrap').on('click', function(e) {
  215.             // モーダル内の処理は外側にバブリングさせない
  216.             e.stopPropagation();
  217.         });
  218.         $('.ec-modal-overlay, .ec-modal, .ec-modal-close, .ec-inlineBtn--cancel').on('click', function() {
  219.             $('.ec-modal').hide()
  220.         });
  221.     </script>
  222.     <script type="application/ld+json">
  223.     {
  224.         "@context": "https://schema.org/",
  225.         "@type": "Product",
  226.         "name": "{{ Product.name }}",
  227.         "image": [
  228.             {% for img in Product.ProductImage %}
  229.                 "{{ app.request.schemeAndHttpHost }}{{ asset(img, 'save_image') }}"{% if not loop.last %},{% endif %}
  230.             {% else %}
  231.                 "{{ app.request.schemeAndHttpHost }}{{ asset(''|no_image_product, 'save_image') }}"
  232.             {% endfor %}
  233.         ],
  234.         "description": "{{ Product.description_list | default(Product.description_detail) | replace({'\n': '', '\r': ''}) | slice(0,300) }}",
  235.         {% if Product.code_min %}
  236.         "sku": "{{ Product.code_min }}",
  237.         {% endif %}
  238.         "offers": {
  239.             "@type": "Offer",
  240.             "url": "{{ url('product_detail', {'id': Product.id}) }}",
  241.             "priceCurrency": "{{ eccube_config.currency }}",
  242.             "price": {{ Product.getPrice02IncTaxMin ? Product.getPrice02IncTaxMin : 0}},
  243.             "availability": "{{ Product.stock_find ? "InStock" : "OutOfStock" }}"
  244.         }
  245.     }
  246.     </script>
  247.     <script>
  248.         $(function() {
  249.         $('.input-group').on('click', '.btn', function() {
  250.             var $input = $(this).closest('.input-group').find('input');
  251.             var value = parseInt($input.val());
  252.             if ($(this).hasClass('btn-plus')) {
  253.             value = value + 1;
  254.             } else {
  255.             if (value > 1) {
  256.                 value = value - 1;
  257.             }
  258.             }
  259.             $input.val(value);
  260.         });
  261.         });
  262.     </script>
  263. {% endblock %}
  264. {% block breadcrumb %}
  265. {# パンくず #}
  266. <div class="breadcrumb-root">
  267.     {% if Product.ProductCategories is not empty %}
  268.     <div class="breadcrumb-wrapper container">
  269.         <ul>
  270.             {% set product_categories_length =  Product.ProductCategories|length %}
  271.             {% for ProductCategory in Product.ProductCategories %}
  272.                 {% if loop.index == product_categories_length %}
  273.                     <li>
  274.                         <a href="{{ url('homepage') }}">
  275.                             トップ
  276.                         </a>
  277.                         <svg width="5" height="8" viewBox="0 0 5 8" fill="none" xmlns="http://www.w3.org/2000/svg">
  278.                             <path d="M0.90918 1L3.63645 4L0.90918 7" stroke="#1A1A1A" stroke-linecap="round" stroke-linejoin="round"/>
  279.                         </svg>
  280.                         {% for Category in ProductCategory.Category.path %}
  281.                             <a href="{{ url('product_list') }}?category_id={{ Category.id }}">{{ Category.name }}</a> {%- if loop.last == false %}
  282.                             <svg width="5" height="8" viewBox="0 0 5 8" fill="none" xmlns="http://www.w3.org/2000/svg">
  283.                                 <path d="M0.90918 1L3.63645 4L0.90918 7" stroke="#1A1A1A" stroke-linecap="round" stroke-linejoin="round"/>
  284.                             </svg>
  285.                             {% endif -%}
  286.                         {% endfor %}
  287.                         <svg width="5" height="8" viewBox="0 0 5 8" fill="none" xmlns="http://www.w3.org/2000/svg">
  288.                             <path d="M0.90918 1L3.63645 4L0.90918 7" stroke="#1A1A1A" stroke-linecap="round" stroke-linejoin="round"/>
  289.                         </svg>
  290.                             
  291.                         <span>{{ Product.code_max }}</span>
  292.                     </li>
  293.                     {% endif %}
  294.                 {% endfor %}
  295.                 </ul>
  296.             </div>
  297.         {% endif %}
  298.     </div>
  299. {% endblock %}
  300. {# コンテンツ #}
  301. {% block main %}
  302.     <div class="ec-productRole">
  303.         <div class="ec-grid2">
  304.             <div class="ec-grid2__cell product-detail-page-left mb-10 mb-md-0">
  305.                 <div class="ec-sliderItemRole">
  306.                     <div class="item_visual">
  307.                         {% for ProductImage in Product.ProductImage %}
  308.                             <div class="slide-item"><img src="{{ asset(ProductImage, 'save_image') }}" alt="{{ loop.first ? Product.name : '' }}" width="550" height="550"{% if loop.index > 1 %} loading="lazy"{% endif %}></div>
  309.                         {% else %}
  310.                             <div class="slide-item"><img src="{{ asset(''|no_image_product, 'save_image') }}" alt="{{ loop.first ? Product.name : '' }}" width="550" height="550"></div>
  311.                         {% endfor %}
  312.                     </div>
  313.                     <div class="item_nav">
  314.                         {% for ProductImage in Product.ProductImage %}
  315.                             <div class="slideThumb" data-index="{{ loop.index0 }}"><img src="{{ asset(ProductImage, 'save_image') }}" alt="" width="133" height="133" loading="lazy"></div>
  316.                         {% endfor %}
  317.                     </div>
  318.                 </div>
  319.             </div>
  320.             <div class="product-detail-page-right">
  321.                 <div class="ec-productRole__profile">
  322.                     {# 会社名 from ProductDetailContoroller #}
  323.                     {% if company_name %}
  324.                     <div class="px-5 px-md-0">
  325.                         <p class="product-detail-page-company-name">
  326.                             {{ company_name }}
  327.                         </p>
  328.                     </div>
  329.                     {% endif %}
  330.                     {% if Product.description_list %}
  331.                     <div class="px-5 px-md-0">
  332.                         <p class="product-detail-page-description-list">
  333.                             {{ Product.description_list|striptags }}
  334.                         </p>                    
  335.                     </div>
  336.                     {% endif %}
  337.                     {# 商品名 from ProductDetailContoroller  #}
  338.                     <div class="px-5 px-md-0">
  339.                     {% if formated_product_name %}
  340.                         <h2 class="product-detail-page-product-name">
  341.                             {{ formated_product_name }}
  342.                         </h2>
  343.                     {% else %}
  344.                         <h2 class="product-detail-page-product-name">{{ Product.name }}</h2>
  345.                     {% endif %}
  346.                     </div>
  347.                     {# 送料無料 #}
  348.                     <div class="px-5 px-md-0">
  349.                         <div class="product-detail-page-badge-container">
  350.                             {# 送料無料条件よりも商品価格が上だったら表示 9,800 #}
  351.                             {% if Product.getPrice02IncTaxMin > BaseInfo.delivery_free_amount  %}
  352.                                 <spam class="product-detail-page-badge bg-primary-blue">送料無料</spam>
  353.                             {% endif %}
  354.                         </div>
  355.                     </div>
  356.                     {# 販売価格 #}
  357.                     <div class="px-5 px-md-0">
  358.                         <p class="product-detail-page-price-label">販売価格 (税込)</p>
  359.                         <div class="product-detail-page-price">
  360.                             <p class="product-detail-page-price__number">
  361.                                 {% if Product.hasProductClass -%}
  362.                                     {% if Product.getPrice02IncTaxMin == Product.getPrice02IncTaxMax %}
  363.                                         {{ Product.getPrice02IncTaxMin|number_format }}
  364.                                     {% else %}
  365.                                         {{ Product.getPrice02IncTaxMin|number_format }} ~ {{ Product.getPrice02IncTaxMax|number_format }}
  366.                                     {% endif %}
  367.                                 {% else %}
  368.                                     {{ Product.getPrice02IncTaxMin|number_format }}
  369.                                 {% endif %}
  370.                             </p>
  371.                             <p class="product-detail-page-price__yen">
  372.                                 円
  373.                             </p>
  374.                             {# 送料無料条件よりも商品価格が上だったら #}
  375.                             {% if Product.getPrice02IncTaxMin > BaseInfo.delivery_free_amount  %}
  376.                             {# <p class="product-detail-page-price__freeship">
  377.                                 送料無料
  378.                             </p> #}
  379.                             {% endif %}
  380.                         </div>
  381.                     </div>
  382.                     {# 発送日目安を表示したい #}
  383.                     <div>
  384.                         {# 在庫数 #}
  385.                         {% if Product.stock_min %} 
  386.                         <div class="product-detail-page-bos">
  387.                             <span class="product-detail-page-bos__label">
  388.                                 在庫数
  389.                             </span>
  390.                             <span class="product-detail-page-bos__stock">
  391.                                 残り{{ Product.stock_min|escape }}
  392.                             </span>
  393.                         </div>
  394.                         {% endif %}
  395.                         <form action="{{ url('product_add_cart', {id:Product.id}) }}" method="post" id="form1" name="form1">
  396.                                 {% if Product.stock_find %}
  397.                                     {% if form.classcategory_id1 is defined %}
  398.                                     <div class="product-detail-page-bos">
  399.                                         <div class="d-flex align-items-center">
  400.                                             <div class="product-detail-page-bos__label">
  401.                                                 {{ form_label(form.classcategory_id1) }}
  402.                                             </div>
  403.                                         </div>
  404.                                         <div>
  405.                                             <div>
  406.                                                 <div class="input-group">
  407.                                                     {{ form_widget(form.classcategory_id1) }}
  408.                                                     {{ form_errors(form.classcategory_id1) }}
  409.                                                 </div>
  410.                                             </div>
  411.                                         </div>
  412.                                     </div>
  413.                                     {% endif %}
  414.                                     {% if form.classcategory_id2 is defined %}
  415.                                     <div class="product-detail-page-bos">
  416.                                         <div class="d-flex align-items-center">
  417.                                             <div class="product-detail-page-bos__label">
  418.                                                 {{ form_label(form.classcategory_id2) }}
  419.                                             </div>
  420.                                         </div>
  421.                                         <div>
  422.                                             <div>
  423.                                                 <div class="input-group">
  424.                                                     {{ form_widget(form.classcategory_id2) }}
  425.                                                     {{ form_errors(form.classcategory_id2) }}
  426.                                                 </div>
  427.                                             </div>
  428.                                         </div>
  429.                                     </div>
  430.                                     {% endif %}
  431.                                     
  432.                                 {# 発送日目安 #}
  433.                                 {% if deliveryDuration_id and deliveryDuration_name %}
  434.                                 <div class="product-detail-page-bos">
  435.                                     <div class="product-detail-page-bos__label" style="white-space: nowrap">
  436.                                         発送日目安
  437.                                     </div>
  438.                                     <div>
  439.                                         <div>
  440.                                             <span>{{ deliveryDuration_name }}</span>
  441.                                         </div>
  442.                                     </div>
  443.                                 </div>
  444.                                 {% endif %}
  445.                                     <div class="product-detail-page-bos">
  446.                                         <div class="product-detail-page-bos__label">
  447.                                             数量
  448.                                         </div>
  449.                                         <div>
  450.                                             <div>
  451.                                                 <div class="input-group">
  452.                                                     <span class="input-group-btn">
  453.                                                         <button class="btn btn-default btn-minus" type="button">-</button>
  454.                                                     </span>
  455.                                                     {{ form_widget(form.quantity, {'attr': {'class': 'input-quantity', 'min': '1'}}) }}
  456.                                                     {{ form_errors(form.quantity) }}
  457.                                                     <span class="input-group-btn">
  458.                                                         <button class="btn btn-default btn-plus" type="button">+</button>
  459.                                                     </span>
  460.                                                 </div>
  461.                                             </div>
  462.                                         </div>
  463.                                     </div>
  464.                                 {% endif %}
  465.                                 
  466.                             {# カートに入れる #}
  467.                             <div class="mt-md-8">
  468.                                 {% if Product.stock_find %}
  469.                                     <button type="submit" class="button w-100">
  470.                                         {{ 'カートに入れる'|trans }}
  471.                                     </button>
  472.                                     {% else %}
  473.                                     <button type="button" class="button w-100" disabled="disabled">
  474.                                         {{ 'ただいま品切れ中です。'|trans }}
  475.                                     </button>
  476.                                 {% endif %}
  477.                             </div>
  478.                             {{ form_rest(form) }}
  479.                         </form>
  480.                         {# お気に入りに追加 #}
  481.                         <div class="mt-7 mt-md-6">
  482.                             {{ include('Block/button-favorite.twig') }}
  483.                         </div>
  484.                     </div>
  485.                     
  486.                     <div class="ec-modal">
  487.                         <div class="ec-modal-overlay">
  488.                             <div class="ec-modal-wrap">
  489.                                 <span class="ec-modal-close"><span class="ec-icon"><img src="{{ asset('assets/icon/cross-dark.svg') }}" alt=""/></span></span>
  490.                                 <div id="ec-modal-header" class="text-center">{{ 'カートに追加しました。'|trans }}</div>
  491.                                 <div class="ec-modal-box">
  492.                                     <div class="ec-role">
  493.                                         <span class="ec-inlineBtn--cancel">{{ 'お買い物を続ける'|trans }}</span>
  494.                                         <a href="{{ url('cart') }}" class="ec-inlineBtn--action">{{ 'カートへ進む'|trans }}</a>
  495.                                     </div>
  496.                                 </div>
  497.                             </div>
  498.                         </div>
  499.                     </div>
  500.                 </div>
  501.             </div>
  502.         </div>
  503.     </div> {# .ec-productRole #}
  504.     
  505.     {# 商品詳細 フリースペース #}
  506.     {% if Product.freearea or Product.description_detail %}
  507.         <div class="mt-12">
  508.             <h3 class="product-detail-page-description-heading">商品説明</h3>
  509.             <div>
  510.                 <div class="product-detail-page-description-container">{{ Product.description_detail|raw}}
  511.                 </div>
  512.                 <div class="product-detail-page-description-container">
  513.                     {{ include(template_from_string(Product.freearea)) }}
  514.                 </div>
  515.             </div>
  516.         </div>
  517.     {% endif %}
  518.     <div>
  519.         {% if Product.code_min is not empty %}
  520.             <div class="product-detail-page-product-code">
  521.                 {{ '商品番号'|trans }}: <span class="product-code-default">{{ Product.code_min }}{% if Product.code_min != Product.code_max %} ~ {{ Product.code_max }}{% endif %}</span>
  522.             </div>
  523.         {% endif %}
  524.     </div>
  525.     <div class="d-none d-md-block mt-15">
  526.         {{ include('Block/large-banners.twig') }}
  527.     </div>
  528.     <div class="mt-15">
  529.         {{ include('Block/recommend_list.twig', {label: 'おすすめ当店在庫品', category_id: 32}) }}
  530.     </div>
  531.     <div class="d-none d-md-block mt-15">
  532.         {{ include('Block/recommend_list.twig', {label: 'ブレーカおすすめ商品', category_id: 14}) }}
  533.     </div>
  534.     <div class="d-none d-md-block mt-20">
  535.         {{ include('Block/category_list.twig', {label: 'カテゴリーから探す', href_label: 'すべてのカテゴリーを見る'}) }}
  536.     </div>
  537.     <div class="d-none d-md-block mt-15">
  538.         {{ include('Block/makers.twig', ignore_missing = true) }}
  539.     </div>
  540. {% endblock %}