【EC-CUBE 4】自動更新される新着商品一覧ページ / ブロックを作る方法

新着商品ページとブロックを作成する方法
  • 新規登録した商品から順に表示される、商品一覧ページを作成するには?
  • 新着商品ブロックに、新規登録した商品が自動で表示されるようにしたい!

この記事では、新規登録した商品が順に並ぶ(= 商品IDが大きい順に並ぶ)商品一覧ページおよびブロックの作り方を紹介します。
EC-CUBE 4のカスタマイズを行いたい方の参考になればと思います!

【動作環境】
EC CUBEのバージョン:4.1.2
サーバー:Xserver
ブラウザ:Google Chrome

なおデバッグモードを設定しておくと、エラーが起きたときに詳細情報が表示されるようになります。
エラー箇所を探しやすくなるので、開発前に設定しておくのをオススメします。
デバッグモードの設定方法については こちらの記事 で解説しています。

目次

新着商品ページの作成

まず、新規ページの作り方を紹介します。

初期ページ(作成前)と完成ページ

初期ページ
初期ページ
編集前

「新着商品ページ」のタイトルのみ表示。

TwigとControllerのコードは以下に記載。

完成ページ
完成ページ
編集後

左 → 右へ商品IDの大きい順に、「商品の画像・ID・品名・価格」を表示。

手順やコードなどは本記事に掲載。

初期状態(ここからページを作成していきます)

必要最低限のControllerとTwigファイルを作成した状態からスタートします。
各コードは以下に載せておきますが、より詳しい作り方は こちらの記事 にまとめていますので、同じ状態からページを作成してみたい方は合わせてご確認ください。

URL

(ドメイン名)/sample

Twig

app/template/default/sample.twig

Controller

app/Customize/Controller/SamplePageController.php

sample.twig
{% extends 'default_frame.twig' %}

{% block main %}
<h1>新着商品ページ</h1>

{% endblock %}

「新着商品ページ」というタイトルのみ記載したシンプルなページ。

SamplePageController.php
<?php

namespace Customize\Controller;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Eccube\Controller\AbstractController;

class SamplePageController extends AbstractController
{
    /**
     * @Route("/sample", name="sample")
     * @Template("sample.twig")
     */
    public function index(Request $request)
    {
            return [];
    }
}

ページを表示するためだけのシンプルなController。URLからは「user_data」を消し、既存ページと同等に扱える設定にしています。

作成手順

  1. ControllerにRepositoryを利用したコードを記載し、ファイルサーバーにアップ。
  2. Twigを修正
  3. EC CUBE 管理画面にてキャッシュを削除。

Controllerの修正

SamplePageController.php
<?php

namespace Customize\Controller;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Eccube\Controller\AbstractController;
use Eccube\Repository\ProductRepository;

class SamplePageController extends AbstractController
{
    /**
     * @var ProductRepository
     */
    protected $productRepository;

    /**
     * @param ProductRepository $productRepository
     */
    public function __construct(ProductRepository $productRepository) {
        $this->productRepository = $productRepository;
    }

    /**
     * @Route("/sample", name="sample")
     * @Template("sample.twig")
     */
    public function index()
    {
        $products = $this->productRepository->findby([], ['id' => 'DESC']);

        return [
            'Products' => $products,
        ];
    }
}

商品データベースから、IDの大きい順に商品情報を取得してTwigに渡すController。ハイライトしている箇所が初期ページからの変更点。

初期状態からの変化点は以下の通り。

オレンジ部

Repository(リポジトリ)を操作するための決まり文句。
なお、Repositoryはデータベースを操作するための機能で、基本的な使い方は こちらの記事 を参照

緑部

まずRepositoryの機能である「findby()」という関数を使用し、その結果を$productsという変数に代入。

findby()の第1引数に空の配列([ ])、第2引数に[‘id’ => ‘DESC’]とすれば、『商品データベースの全データをIDの降順(大きい順)で取得』できる。
ちなみに、’DESC’ ではなく ‘ASC’ とすると昇順(小さい順)になる。

最後のreturnで、取得した商品情報(= $products)をTwigファイル内の ‘Products’ に渡す。
ControllerからTwigにデータを渡す仕組みについては、こちらの記事 を参照

Twigの修正

sample.twig
{% extends 'default_frame.twig' %}

{% block main %}
    <h1>新着商品ページ</h1>
    <div class="ec-shelfRole">
      <ul class="ec-shelfGrid">
          {% for Product in Products %}
              <li class="ec-shelfGrid__item">
                {# 商品画像の表示 #}
                <p class="ec-shelfGrid__item-image">
                    <img src="{{ asset(Product.main_list_image|no_image_product, 'save_image') }}" alt="{{ Product.name }}">
                </p>
                {# 商品IDの表示 #}
                <p>ID: {{ Product.id }}</p>
                {# 商品名の表示 #}
                <p>{{ Product.name }}</p>
                {# 価格の表示 #}
                <p class="price02-default">
                    {% if Product.hasProductClass %}
                        {% if Product.getPrice02Min == Product.getPrice02Max %}
                            {{ Product.getPrice02IncTaxMin|price }}
                        {% else %}
                            {{ Product.getPrice02IncTaxMin|price }} ~ {{ Product.getPrice02IncTaxMax|price }}
                        {% endif %}
                    {% else %}
                        {{ Product.getPrice02IncTaxMin|price }}
                    {% endif %}
                </p>
              </li>
          {% endfor %}
      </ul>
    </div>
{% endblock %}

「<h1>新着商品ページ</h1>」から「{% endblock %}」までのコードを追記。{{ Products }}にはControllerから渡された商品情報がIDの大きい順に格納されている。

長々と複雑そうなコードが書いてありますが、ほとんどがデフォルトで用意されている「商品一覧ページ」からの引用です。

前述のControllerの通り、「Products」にはすべての商品情報がIDの大きい順で格納されてます。
その商品データを、for文を用いて「Product」として一つずつ取り出し、

  • Product.main_list_image →【メイン画像】
  • Product.id → 【商品ID】
  • Product.name →【商品名】
  • Product.getPrice →【価格】

を順々に表示しているというわけです。

キャッシュを削除

ここまでで準備完了です。
管理画面からキャッシュを削除して、ページにアクセスしてみましょう。

キャッシュ管理からキャッシュを削除できます。

冒頭でお見せしたような一覧ページが表示されればOKです!

新着商品ページ

新着商品ブロックの作成

次に、新規ブロックの作り方を紹介します。
デフォルトのレイアウトでは、新着商品ブロックはトップページに表示されていますので、TOPページの画面を見ながら修正します。

初期ブロック(作成前)と完成ブロック

初期ブロック
新着商品ブロックの初期状態
編集前

デフォルトではTOPページにこのような画面が表示されているはずです。

新しく商品登録を行っても、手動でTwigを修正しない限り表示される商品は変わりません。

TwigとControllerのコードは以下に記載。

完成ブロック
完成後の新着商品ブロック
編集後

新着商品(IDの大きい順)が左 → 右へ表示される。

またこの状態で新しく商品登録を行うと、自動的に新しい商品に入れ替わっていきます。

手順やコードなどは本記事に掲載。

初期状態の新着商品ブロック(new_item.twig)は以下のようになっています。

new_item.twig
{#
This file is part of EC-CUBE

Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.

http://www.ec-cube.co.jp/

For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
#}

<div class="ec-role">
    <div class="ec-newItemRole">
        <div class="ec-newItemRole__list">
            <div class="ec-newItemRole__listItem">
                <div class="ec-newItemRole__listItemHeading ec-secHeading--tandem">
                    <span class="ec-secHeading__en">{{ 'NEW ITEM'|trans }}</span>
                    <span class="ec-secHeading__line"></span>
                    <span class="ec-secHeading__ja">{{ '新着商品'|trans }}</span>
                    <a class="ec-inlineBtn--top" href="{{ url('product_list') }}">{{ 'more'|trans }}</a>
                </div>
            </div>
            <div class="ec-newItemRole__listItem">
                <a href="{{ url('product_detail', {'id': '1'}) }}">
                    <img src="{{ asset('cube-1.png', 'save_image') }}">
                    <p class="ec-newItemRole__listItemTitle">{{ '彩のジェラート"CUBE"'|trans }}</p>
                    <p class="ec-newItemRole__listItemPrice">{{ '¥1,200(税込)'|trans }}</p>
                </a>
            </div>
            <div class="ec-newItemRole__listItem">
                <a href="{{ url('product_detail', {'id': '2'}) }}">
                    <img src="{{ asset('sand-1.png', 'save_image') }}">
                    <p class="ec-newItemRole__listItemTitle">{{ 'チェリーアイスサンド'|trans }}</p>
                    <p class="ec-newItemRole__listItemPrice">{{ '¥800(税込)'|trans }}</p>
                </a>
            </div>
            <div class="ec-newItemRole__listItem">
                <a href="{{ url('product_detail', {'id': '1'}) }}">
                    <img src="{{ asset(''|no_image_product , 'save_image') }}">
                    <p class="ec-newItemRole__listItemTitle">{{ '彩のジェラート"CUBE" NEO'|trans }}</p>
                    <p class="ec-newItemRole__listItemPrice">{{ '¥600(税込)'|trans }}</p>
                </a>
            </div>
        </div>
    </div>
</div>

3種類の商品それぞれを直接Twigに記載している。そのため、内容を変えるにはこちらのコードを都度修正する必要がある。

作成手順

  1. src/Eccube/Controller下にあるTopControllerを、app/Customize/Controller下に複製
  2. 複製したTopControllerに、Repositoryを利用したコードを記載
  3. 新着商品ブロックのTwigを修正
  4. EC CUBE 管理画面にてキャッシュを削除

TopControllerの複製

TopControllerをapp下に複製する

前述の新規ページ作成ではControllerを新規に作成しましたが、トップページのControllerはすでに用意されているので、そちらを「app/Customize/Controller」下に複製してそちらを修正します。

src下のControllerを直接修正してもできますが、後で元に戻せなくなったりEC Cubeのアップデート等で不具合が出たりする可能性があるため、オススメできません。

コピーしたTopControllerを修正

基本的には新規ページ作成時と同じですが、namespace と use の部分も変更する点に注意。

TopController.php
<?php

/*
 * This file is part of EC-CUBE
 *
 * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
 *
 * http://www.ec-cube.co.jp/
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Customize\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\Routing\Annotation\Route;
use Eccube\Controller\AbstractController;
use Eccube\Repository\ProductRepository;


class TopController extends AbstractController
{
    /**
     * @var ProductRepository
     */
    protected $productRepository;

    /**
     * @param ProductRepository $productRepository
     */
    public function __construct(ProductRepository $productRepository) {
        $this->productRepository = $productRepository;
    }

    /**
     * @Route("/", name="homepage", methods={"GET"})
     * @Template("index.twig")
     */
    public function index()
    {
      $products = $this->productRepository->findby([], ['id' => 'DESC'], 3);

      return [
          'Products' => $products,
      ];
    }
}

商品データベースから、IDの大きい順に商品情報を3つ取得してTwigに渡すController。ハイライトしている箇所が変更点。

初期状態からの変化点は以下の通り。

赤部

srcからappへControllerを複製したら必ず変更・追記する内容。
これを忘れるとエラーになります。

オレンジ部

Repository(リポジトリ)を操作するための決まり文句。
なお、Repositoryはデータベースを操作するための機能で、基本的な使い方は こちらの記事 を参照

緑部

まずRepositoryの機能である「findby()」という関数を使用し、その結果を$productsという変数に代入。

findby()の第1引数に空の配列([ ])、第2引数に[‘id’ => ‘DESC’]、第3引数に数字(3)を指定すれば、『商品データベースをIDの降順(大きい順)で3件取得』できる。
ちなみに、第2引数を ‘DESC’ ではなく ‘ASC’ とすると昇順(小さい順)になり、第3引数の数字を変えれば取得できる商品件数が変わる。

最後のreturnで、取得した商品情報(= $products)をTwigファイル内の ‘Products’ に渡す。
ControllerからTwigにデータを渡す仕組みについては、こちらの記事 を参照

新着商品ブロックのTwigを修正

sample.twig
<div class="ec-role">
    <div class="ec-newItemRole">
        <div class="ec-newItemRole__list">
            <div class="ec-newItemRole__listItem">
                <div class="ec-newItemRole__listItemHeading ec-secHeading--tandem">
                    <span class="ec-secHeading__en">{{ 'NEW ITEM'|trans }}</span>
                    <span class="ec-secHeading__line"></span>
                    <span class="ec-secHeading__ja">{{ '新着商品'|trans }}</span>
                    <a class="ec-inlineBtn--top" href="{{ url('product_list') }}">{{ 'more'|trans }}</a>
                </div>
            </div>
            {# ここから #}
            <div class="ec-newItemRole__listItem">
                <a href="{{ url('product_detail', {'id': Products[0].id}) }}">
                    <img src="{{ asset(Products[0].main_list_image|no_image_product, 'save_image') }}" alt="{{ Products[0].name }}">
                    <p class="ec-newItemRole__listItemTitle">{{ Products[0].name }}</p>
                    <p class="ec-newItemRole__listItemPrice">
                        {% if Products[0].hasProductClass %}
                            {% if Products[0].getPrice02Min == Products[0].getPrice02Max %}
                                {{ Products[0].getPrice02IncTaxMin|price }}
                            {% else %}
                                {{ Products[0].getPrice02IncTaxMin|price }} ~ {{ Products[0].getPrice02IncTaxMax|price }}
                            {% endif %}
                        {% else %}
                            {{ Products[0].getPrice02IncTaxMin|price }}
                        {% endif %}
                    </p>
                </a>
            </div>
            {# ここまでを以下使い回し #}
            <div class="ec-newItemRole__listItem">
                <a href="{{ url('product_detail', {'id': Products[1].id}) }}">
                    <img src="{{ asset(Products[1].main_list_image|no_image_product, 'save_image') }}" alt="{{ Products[1].name }}">
                    <p class="ec-newItemRole__listItemTitle">{{ Products[1].name }}</p>
                    <p class="ec-newItemRole__listItemPrice">
                        {% if Products[1].hasProductClass %}
                            {% if Products[1].getPrice02Min == Products[1].getPrice02Max %}
                                {{ Products[1].getPrice02IncTaxMin|price }}
                            {% else %}
                                {{ Products[1].getPrice02IncTaxMin|price }} ~ {{ Products[1].getPrice02IncTaxMax|price }}
                            {% endif %}
                        {% else %}
                            {{ Products[1].getPrice02IncTaxMin|price }}
                        {% endif %}
                    </p>
                </a>
            </div>
            <div class="ec-newItemRole__listItem">
                <a href="{{ url('product_detail', {'id': Products[2].id}) }}">
                    <img src="{{ asset(Products[2].main_list_image|no_image_product, 'save_image') }}" alt="{{ Products[2].name }}">
                    <p class="ec-newItemRole__listItemTitle">{{ Products[2].name }}</p>
                    <p class="ec-newItemRole__listItemPrice">
                        {% if Products[2].hasProductClass %}
                            {% if Products[2].getPrice02Min == Products[2].getPrice02Max %}
                                {{ Products[2].getPrice02IncTaxMin|price }}
                            {% else %}
                                {{ Products[2].getPrice02IncTaxMin|price }} ~ {{ Products[2].getPrice02IncTaxMax|price }}
                            {% endif %}
                        {% else %}
                            {{ Products[2].getPrice02IncTaxMin|price }}
                        {% endif %}
                    </p>
                </a>
            </div>
        </div>
    </div>
</div>

{{ Products }}にはControllerから渡された商品情報がIDの大きい順に3つ格納されている。

長々と複雑そうなコードが書いてありますが、基本的には初期ブロックのコードを一部修正したのみ。

前述のControllerの通り、「Products」にはIDの大きい順で商品情報が3つ、配列で格納されています。

  • Products[0] → 商品IDが一番大きい商品
  • Products[1] → 商品IDが二番目に大きい商品
  • Products[2] → 商品IDが三番目に大きい商品

各商品を表示する部分は、でハイライトした間のコードを3つ並べただけです。
長々として面倒であれば、「for文」で回してもOKです。

キャッシュを削除

ここまでで準備完了です。
管理画面からキャッシュを削除して、ページにアクセスしてみましょう。

キャッシュ管理からキャッシュを削除できます。

以下のように、商品登録の新しい順(=商品IDの大きい順)に商品が表示されればOKです!

完成後の新着商品ブロック
新着商品ページ

ここで作成した新着商品ブロックをトップページ以外でも使おうとすると、エラーもしくは意図しない表示になる可能性が高いです。

トップページはControllerを修正し、Twigの「Products」に新着商品情報が格納されるようになっていますが、他ページではそのようなControllerになっていないためです。もし他のページでも同様に使いたい場合は、トップページ以外のControllerも同じように修正してください。

まとめ

以上、新着商品の一覧ページとブロックの作り方を紹介しました。

トップページには新着商品を表示させておきたい方も多いと思います。登録のたびに商品を入れ替えるというのもアリですが、頻繁に商品が入れ替わるような場合は今回のような設定をしておくと便利です。

また、応用すれば「古い商品順に表示させる」といったことも可能になりますので(あまりそのような使い方はしないかもしれませんが)、本格的なカスタマイズをお考えの方はぜひトライしてみてください!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

ノベルティグッズのECサイトを運営する中小企業役員。
本ブログを通じ、販促向けの最新/ロングセラー商品紹介やWebサイト制作に役立つ技術情報を発信しています。

目次