EC-CUBE2.13系のカスタマイズ事例です。
いよいよ 2018年9月末に EC-CUBE4系 がリリースされることになりましたね! 現在はEC-CUBE は3系が主流ですがベースとなっている Symfony のバージョンアップを考えると、まだまだ 2系が安心です。ただ、2系はプラグインが減ってしまっていて、カスタマイズ案件のリクエストが増えています。
今回はご要望の多い「2系の商品規格をラジオボタンに変更する事例」を取り上げます。過去にはオーナーズストアに無料のプラグインがあったのですが現在は見当たらなくなっています。EC-CUBE3系はプラグインが公開されています。
4系のリリース目前にして、はほとんど世の中に必要とされていないんじゃないかと思いますが、私的には必須ですし、結構複雑なので記録に残しておこうと思います。なお、いつものお約束ですが、こちらの内容は自己責任でご利用ください。EC-CUBE が壊れる可能性大ですが責任は負えません。(^^)
今回は特に、超上級編になります。この記事の方法でうまくいかない可能性もありますが、ご自身で解決できる方のみ挑戦してみてください。自信のないかたは有料にてカスタマイズをお引き受けしておりますので、ご連絡ください。
目次
商品を分類する EC-CUBE の 商品規格
商品規格とは何か
EC-CUBE では商品の分類を「規格」と呼んでいます。洋服でいえば、S・M・L などのサイズが「規格」にあたります。EC-CUBE では 一つの商品に対し二つまでの規格を組み合わせることができます。サイズが S・M・L の3種類で、色が赤と青の2種類なら、「サイズ」と「色」をそれぞれ規格として設定し、お客様が選べるようにできるわけです。
標準では、規格はドロップダウンリストボックス
規格は標準ではドロップダウンリストボックスになっています。
規格が2種類ある商品では、一つ目の規格を選ぶと、二つ目の規格のリストが作成されるのですが、パッと見た感じではどのような種類があるのか分かりません。
これをラジオボタンにして一覧の中から選んでもらえるようにするのが今回の目標です。
まず、テンプレート detail.tpl を変更
以下のファイルを開いて編集します。コードのバージョンは 2.13.1 ですが、2.13系なら大きく変わらないと思います。
\html\data\Smarty\templates\default\products\detail.tpl
セレクトボックスを削除する
セレクトボックスはいらないので削除します。
まず、「規格1」を表示している197行目「<select name=”classcategory_id1″ style=”<!–{$arrErr.classcategory_id1|sfGetErrorColor}–>”>」と199行目「</select>」の2行を削除します。
次に、「規格2」をまるごと削除します。削除する「規格2」は、206行目「{if $tpl_classcat_find2}」から219行目「{/if}」までになります。
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
<div class="cart_area clearfix"> <input type="hidden" name="mode" value="cart" /> <input type="hidden" name="product_id" value="<!--{$tpl_product_id}-->" /> <input type="hidden" name="product_class_id" value="<!--{$tpl_product_class_id}-->" id="product_class_id" /> <input type="hidden" name="favorite_product_id" value="" /> <!--{if $tpl_stock_find}--> <!--{if $tpl_classcat_find1}--> <div class="classlist"> <!--▼規格1--> <ul class="clearfix"> <li><!--{$tpl_class_name1|h}-->:</li> <li> <select name="classcategory_id1" style="<!--{$arrErr.classcategory_id1|sfGetErrorColor}-->"> //この行を削除 <!--{html_options options=$arrClassCat1 selected=$arrForm.classcategory_id1.value}--> </select> <!--{if $arrErr.classcategory_id1 != ""}--> <br /><span class="attention">※ <!--{$tpl_class_name1}-->を入力して下さい。</span> <!--{/if}--> </li> </ul> <!--▲規格1--> <!--{if $tpl_classcat_find2}--> //削除 ここから <!--▼規格2--> <ul class="clearfix"> <li><!--{$tpl_class_name2|h}-->:</li> <li> <select name="classcategory_id2" style="<!--{$arrErr.classcategory_id2|sfGetErrorColor}-->"> </select> <!--{if $arrErr.classcategory_id2 != ""}--> <br /><span class="attention">※ <!--{$tpl_class_name2}-->を入力して下さい。</span> <!--{/if}--> </li> </ul> <!--▲規格2--> <!--{/if}--> //削除 ここまで </div> <!--{/if}--> |
「規格1」と「規格2」を保管する input box を追加する
「規格1」と「規格2」を保持するため、次の3行を189行目以降に追加します。
1 2 3 |
<input type="hidden" name="classcategory_id" value="<!--{$tpl_classcategory_id}-->" id="classcategory_id"/> <input type="hidden" name="classcategory_id1" value="<!--{$tpl_classcategory_id1}-->" id="classcategory_id1"/> <input type="hidden" name="classcategory_id2" value="<!--{$tpl_classcategory_id2}-->" id="classcategory_id2"/> |
ラジオボタンを追加する
「html_options」を「html_radios」に変更するとラジオボタンになります。また、一つの選択肢に「規格1」と「規格2」の両方のコードを持たせる必要があるため、200行目は以下のように変更します。
1 |
<!--{html_radios name='classcategory_id' options=$arrClassCat1 selected=$arrForm.classcategory_id.value}--> |
202行目の「classcategory_id1」を「classcategory_id」に変更します(1 を取る)。
変更後の detail.tpl は以下のとおりです。
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
<div class="cart_area clearfix"> <input type="hidden" name="mode" value="cart" /> <input type="hidden" name="product_id" value="<!--{$tpl_product_id}-->" /> <input type="hidden" name="product_class_id" value="<!--{$tpl_product_class_id}-->" id="product_class_id" /> <input type="hidden" name="favorite_product_id" value="" /> <input type="hidden" name="classcategory_id" value="<!--{$tpl_classcategory_id}-->" id="classcategory_id"/> <input type="hidden" name="classcategory_id1" value="<!--{$tpl_classcategory_id1}-->" id="classcategory_id1" /> <input type="hidden" name="classcategory_id2" value="<!--{$tpl_classcategory_id2}-->" id="classcategory_id2" /> <!--{if $tpl_stock_find}--> <!--{if $tpl_classcat_find1}--> <div class="classlist"> <!--▼規格1--> <ul class="clearfix"> <li><!--{$tpl_class_name1|h}-->:</li> <li> <!--{html_radios options=$arrClassCat1 selected=$arrForm.classcategory_id.value}--> // classcategory_id1 を classcategory_id に変更し、name='classcategory_id' を追加 </select> <!--{if $arrErr.classcategory_id != ""}--> // classcategory_id1 を classcategory_id に変更 <br /><span class="attention">※ <!--{$tpl_class_name1}-->を入力して下さい。</span> <!--{/if}--> </li> </ul> <!--▲規格1--> </div> <!--{/if}--> |
最後に、このテンプレートの初め(23行目)に書かれている javascript を以下のように変更します。
1 2 3 4 5 6 7 8 9 10 |
<script type="text/javascript">//<![CDATA[ // 規格2に選択肢を割り当てる。 function fnSetClassCategories(form, classcat_id1_selected) { var $form = $(form); var product_id = $form.find('input[name=product_id]').val(); var $sele1 = $form.find('input[name=classcategory_id1]:checked'); var $sele2 = $form.find('input[name=classcategory_id1]:checked'); eccube.setClassCategories($form, product_id, $sele1, $sele2, classcat_id2_selected); } //]]></script> |
テンプレートの修正は以上になります。ここまででテンプレートを更新すると、商品詳細ページは以下のようになります。
このままでは、「選択してください」という項目ができてしまっていますし、味を選択して「カゴに入れる」ボタンをクリックしてもカート画面に遷移しません。
SC_Product クラスを変更する
規格のセレクトボックスは「data\class\SC_Product.php」内の「setProductsClassByProductIds」で作っています。
一つの選択肢に「規格1」+「規格2」+「商品価格」を表記するように修正します。
「data\class\SC_Product.php」を直接修正すると他に影響の出る可能性がありますので、以下の内容を「data\class_extends\SC_Product_Ex.php」を開き、貼り付けます。念のため、「setProductsClassByProductIds2」という名前に変更しておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
/** * 商品IDに紐づく商品規格を自分自身に設定する. * セレクトボックスではなくラジオボタンに変更 by Kasuga * * 引数の商品IDの配列に紐づく商品規格を取得し, 自分自身のフィールドに * 設定する. * * @param array $arrProductId 商品ID の配列 * @param boolean $has_deleted 削除された商品規格も含む場合 true; 初期値 false * @return void */ public function setProductsClassByProductIds2($arrProductId, $has_deleted = false) { foreach ($arrProductId as $productId) { $arrProductClasses = $this->getProductsClassFullByProductId($productId, $has_deleted); // 在庫数でソートする $stock_unlimited = array(); $stock_array = array(); foreach( $arrProductClasses as $value ) { $stock_unlimited[] = $value['stock_unlimited']; $stock_array[] = $value['stock']; } // ソートを実行 array_multisort( $stock_unlimited, SORT_DESC, $stock_array, SORT_DESC, $arrProductClasses); $classCats1 = array(); // 規格1クラス名 $this->className1[$productId] = isset($arrProductClasses[0]['class_name1']) ? $arrProductClasses[0]['class_name1'] : ''; // 規格2クラス名 $this->className2[$productId] = isset($arrProductClasses[0]['class_name2']) ? $arrProductClasses[0]['class_name2'] : ''; // 規格1が設定されている $this->classCat1_find[$productId] = $arrProductClasses[0]['classcategory_id1'] > 0; // 要変更ただし、他にも改修が必要となる // 規格2が設定されている $this->classCat2_find[$productId] = $arrProductClasses[0]['classcategory_id2'] > 0; // 要変更ただし、他にも改修が必要となる $this->stock_find[$productId] = false; $classCategories = array(); $classCategories['__unselected']['__unselected']['product_class_id'] = $arrProductClasses[0]['product_class_id']; // 商品種別 $classCategories['__unselected']['__unselected']['product_type'] = $arrProductClasses[0]['product_type_id']; $this->product_class_id[$productId] = $arrProductClasses[0]['product_class_id']; $this->product_type[$productId] = $arrProductClasses[0]['product_type_id']; foreach ($arrProductClasses as $arrProductsClass) { $arrClassCats2 = array(); // カテゴリID if ( strpos($arrProductsClass['classcategory_id1'], '-') ) { $mypos = strpos($arrProductsClass['classcategory_id1'], '-'); $classcategory_id1 = substr($arrProductsClass['classcategory_id1'],0,$mypos); $classcategory_id2 = substr($arrProductsClass['classcategory_id2'],$mypos); } else { $classcategory_id1 = $arrProductsClass['classcategory_id1']; $classcategory_id2 = $arrProductsClass['classcategory_id2']; } // 在庫 $stock_find_class = ($arrProductsClass['stock_unlimited'] || $arrProductsClass['stock'] > 0); $arrClassCats2['classcategory_id2'] = $classcategory_id2; // 規格2の名称 $arrClassCats2['name'] = $arrProductsClass['classcategory_name2'] . ($stock_find_class ? '' : ' (品切れ中)'); // 在庫 $arrClassCats2['stock_find'] = $stock_find_class; if ($stock_find_class) { $this->stock_find[$productId] = true; } // 価格 // TODO: ここでprice01,price02を税込みにしてよいのか? _inctax を付けるべき?要検証 $arrClassCats2['price01'] = strlen($arrProductsClass['price01']) ? number_format(SC_Helper_TaxRule_Ex::sfCalcIncTax($arrProductsClass['price01'], $productId, $arrProductsClass['product_class_id'])) : ''; $arrClassCats2['price02'] = strlen($arrProductsClass['price02']) ? number_format(SC_Helper_TaxRule_Ex::sfCalcIncTax($arrProductsClass['price02'], $productId, $arrProductsClass['product_class_id'])) : ''; // 規格名(1と2を結合)+ 価格 if (!in_array($classcategory_id1, $classCats1)) { $classCats1[$classcategory_id1 . '-' . $classcategory_id2] = $arrProductsClass['classcategory_name1'] . "(" . $arrProductsClass['classcategory_name2'] . ") " . $arrClassCats2['price02'] . "円" . ($classcategory_id2 == 0 && !$stock_find_class ? ' (品切れ中)' : ''); } // ポイント $arrClassCats2['point'] = number_format(SC_Utils_Ex::sfPrePoint($arrProductsClass['price02'], $arrProductsClass['point_rate'])); // 商品コード $arrClassCats2['product_code'] = $arrProductsClass['product_code']; // 商品規格ID $arrClassCats2['product_class_id'] = $arrProductsClass['product_class_id']; // 商品種別 $arrClassCats2['product_type'] = $arrProductsClass['product_type_id']; // #929(GC8 規格のプルダウン順序表示不具合)対応のため、2次キーは「#」を前置 if (!$this->classCat1_find[$productId]) { $classcategory_id1 = '__unselected2'; } $classCategories[$classcategory_id1]['#'] = array( 'classcategory_id2' => '', 'name' => '選択してください', ); $classCategories[$classcategory_id1]['#' . $classcategory_id2] = $arrClassCats2; } $this->classCategories[$productId] = $classCategories; // 規格1 $this->classCats1[$productId] = $classCats1; } } |
このクラスの呼び出し元を変更します。data\class\pages\products\LC_Page_Products_Detail.phpの122行目と669行目付近で、「setProductsClassByProductIds」を呼び出しているところを「setProductsClassByProductIds2」に変更します(2を追加)。
今回は変更場所が2個所だけなので、元ファイルを修正していますが、お好みにより「class_extends」をお使いください。
1 |
$objProduct->setProductsClassByProductIds2(array($product_id)); //setProductsClassByProductIds に 2 を追加 |
ここまでで、表示は次のようになります。
Javascript を変更して、カゴに入るようにする
商品を選択してカゴに入れるところは、Javascript を変更します。 html\js\eccube.js の eccube.checkStock 内 464行目付近に「classcat2.classcategory_id1 = classcat_id1;」を追加します。
1 2 3 4 5 6 7 8 9 |
// 商品一覧時 if (eccube.hasOwnProperty('productsClassCategories')) { classcat2 = eccube.productsClassCategories[product_id][classcat_id1]['#' + classcat_id2]; } // 詳細表示時 else { classcat2 = eccube.classCategories[classcat_id1]['#' + classcat_id2]; // 変更 classcat2.classcategory_id1 = classcat_id1; // 追加 } |
次に、526行目付近の「// 商品規格」の下に、「商品規格ID1」と「商品規格ID2」を追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// 商品規格ID1 var $classcategory_id1_dynamic = $form.find('[id^=classcategory_id1]'); if (classcat2 && typeof classcat2.classcategory_id1 !== 'undefined' && String(classcat2.classcategory_id1).length >= 1) { $classcategory_id1_dynamic.val(classcat2.classcategory_id1); } else { $classcategory_id1_dynamic.val(''); } // 商品規格ID2 var $classcategory_id2_dynamic = $form.find('[id^=classcategory_id2]'); if (classcat2 && typeof classcat2.classcategory_id2 !== 'undefined' && String(classcat2.classcategory_id2).length >= 1) { $classcategory_id2_dynamic.val(classcat2.classcategory_id2); } else { $classcategory_id2_dynamic.val(''); } |
さらに、適当な場所(559行目の「規格2選択時」の下あたりがお勧め)に以下を挿入します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// 規格2選択時(ラジオボタン) $('input[name=classcategory_id]') .change(function() { var $form = $(this).parents('form'); var product_id = $form.find('input[name=product_id]').val(); var cat12 = $form.find('input[name=classcategory_id]:checked').val(); var pos = cat12.indexOf('-'); if (pos > 0) { var $sele1 = cat12.substr(0,pos); var $sele2 = cat12.substr(pos+1); } eccube.checkStock($form, product_id, $sele1, $sele2); }); |
スタイルを整えて、カゴに入るか確認
最後にスタイルを整えます。各ラジオボタンには「<label>」タグが付きますので、<label>」タグのスタイルを「display:block」に変更します。
\html\user_data\packages\default\css\contents.css
512行目に「#detailrightbloc .cart_area」があるので、その下あたりに以下を追加します。
1 2 3 |
#detailrightbloc .cart_area label{ display : block; } |
以上で終了です。お疲れ様でした。
長野県駒ヶ根市在住。ネットショップ構築とネットショップ運営サポートをしています。このサイトでは、ユーザーさん向けに役立つIT情報や、技術情報のメモを公開しています。詳しいプロフィール