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

この記事では、新規登録した商品が順に表示される(商品IDが大きい順に表示される)商品一覧ページおよびブロックの作り方を紹介します。

EC-CUBEでは、デフォルトで『新着商品』ブロック(new_item.twig)が用意されています。
しかし、このTwigテンプレートを見ると単に特定のIDの商品を掲載しているだけなので、管理者が都度商品を変更しなければなりません。

本記事での実装は、そんな手間をかけず自動で掲載商品が更新されていく方法を紹介しています。

【動作環境】
EC CUBEのバージョン:4.2.1
サーバー:Xserver

開発前にデバッグモードの設定をお薦めします

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

カスタマイズ後は、デバッグモードの解除を忘れないように。

目次

【自動更新】新着商品ページの作成

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

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

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

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

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

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

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

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

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

必要最低限のControllerとTwigテンプレートを作成した状態からスタートします。

各コードは以下に載せておきますが、より詳しい作り方は こちらの記事 にまとめています。
同じ状態からページを作成してみたい方は合わせてご確認ください。


URL

(ドメイン名)/sample

Twig

app/template/default/sample.twig

Controller

app/Customize/Controller/SamplePageController.php

{% extends 'default_frame.twig' %}

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

{% endblock %}
<?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 [];
    }
}

作成手順

  1. Controllerの修正
    • Repositoryを使って商品IDの大きい順に商品を抽出し、変数に格納する。
      Repositoryについては こちらの記事 を参照ください。
  2. Twigを修正
    • Controllerで抽出・格納した商品を受け取り、格納順に表示する。
  3. EC CUBE 管理画面にてキャッシュを削除。

STEP

Controllerの修正

<?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;  // データベースのdtb_Productテーブルから情報を取得するためのリポジトリ。

class SamplePageController extends AbstractController
{
    // ProductRepositoryのプロパティを宣言。
    /**
    /**
     * @var ProductRepository
     */
    protected $productRepository;

    // コンストラクタメソッド。このクラスがインスタンス化されるときに自動的に呼び出される。
    // ProductRepositoryを引数として受け取り、それをクラスのプロパティに格納する。
    /**
     * @param ProductRepository $productRepository
     */
    public function __construct(ProductRepository $productRepository) {
        $this->productRepository = $productRepository;
    }

    /**
     * @Route("/sample", name="sample")
     * @Template("sample.twig")
     */
    public function index()
    {
        // ProductRepositoryを使って、全商品をIDの大きい順(降順)で取得。
        $products = $this->productRepository->findby([], ['id' => 'DESC']);

        // 取得した商品データをTwigテンプレートに渡す。
        return [
            'Products' => $products,
        ];
    }
}
Repositoryのメソッドについて

Repositoryにはfindby()というメソッドが用意されています。

findby()の第1引数に空の配列([ ])、第2引数に[‘id’ => ‘DESC’]とすると、
『商品テーブルの全データをIDの降順(大きい順)で取得』できます。

ちなみに、’DESC’ ではなく ‘ASC’ とすると昇順(小さい順)で取得できます。
Repositoryの機能について、より詳しい説明は以下記事を参照ください。

STEP

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 %}

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

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

Product.main_list_image

メイン画像

Product.id

商品ID

Product.name

商品名

Product.getPrice

価格

を順々に表示しています。

Twigテンプレートの書き方については以下記事を参照ください。

STEP

キャッシュを削除

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

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

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

新着商品ページ

【自動更新】新着商品ブロックの作成

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

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

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

デフォルトの新着商品ブロックはこのような表示になっています。

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

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

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

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

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

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

初期状態の新着商品ブロック(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を使って商品IDの大きい順に商品を抽出し、変数に格納する。
      Repositoryについては こちらの記事 を参照ください。
  3. 新着商品ブロックのTwigを修正
    • Controllerで抽出・格納した商品を受け取り、格納順に表示する。
  4. EC CUBE 管理画面にてキャッシュを削除
STEP

TopControllerの複製

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

TopControllerをapp下に複製する

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

STEP

コピーしたTopControllerを修正

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

<?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;  // データベースのdtb_Productテーブルから情報を取得するためのリポジトリ。

class TopController extends AbstractController
{
    // ProductRepositoryのプロパティを宣言。
    /**
     * @var ProductRepository
     */
    protected $productRepository;

    // コンストラクタメソッド。このクラスがインスタンス化されるときに自動的に呼び出される。
    // ProductRepositoryを引数として受け取り、それをクラスのプロパティに格納する。
    /**
     * @param ProductRepository $productRepository
     */
    public function __construct(ProductRepository $productRepository) {
        $this->productRepository = $productRepository;
    }

    /**
     * @Route("/", name="homepage", methods={"GET"})
     * @Template("index.twig")
     */
    public function index()
    {
      // ProductRepositoryを使って、IDの大きい順(降順)に3件取得。
      $products = $this->productRepository->findby([], ['id' => 'DESC'], 3);

      // 取得した商品データをTwigテンプレートに渡す。
      return [
          'Products' => $products,
      ];
    }
}
Repositoryのメソッドについて

Repositoryにはfindby()というメソッドが用意されています。

findby()の第1引数に空の配列[ ]、第2引数に['id' => 'DESC']、第3引数にと3すると、
『商品テーブルのデータをIDの降順(大きい順)で3件取得』できます。

Repositoryの機能について、より詳しい説明は以下記事を参照ください。

STEP

新着商品ブロックの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>

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

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

Products[0]

商品IDが1番目に大きい商品

Products[1]

商品IDが2番目に大きい商品

Products[2]

商品IDが3番目に大きい商品

各商品を表示する部分は、{# ここから #}{# ここまでを以下使い回し #}で囲われたコードを3つ並べただけです。

長々として面倒であれば、「for文」で回してもOKです。

STEP

キャッシュを削除

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

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

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

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

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

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

もし他のページでも同様に使いたい場合は、トップページ以外のControllerも同じように修正してください。

まとめ

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

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

また、応用すれば「古い商品順に表示させる」といったことも可能になります。(あまりそのような使い方はしないかもしれませんが。)

本格的なカスタマイズをお考えの方はぜひトライしてみてください!

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