EC-CUBE 4で商品一覧ページやブロックを自作すると、公開ステータスが「非公開」「廃止」の商品まで表示されてしまいます。これを直す方法を2つ紹介します。どちらも数行の追記で済みます。
Twig側で絞り込むか、Controller側で絞り込むかの2通りあります。どちらか一方で構いません。
{% if Product.status.id == 1 %}
~~商品情報~~
{% endif %}
$products = $this->productRepository->findBy(
['Status' => 1],
['id' => 'DESC']
);
公開ステータスの「公開」は 1 です。Controller側で絞り込むほうが、無駄なデータを取り出さずに済みます。
これまで本サイトでは、条件に合った商品だけを表示するページやブロックの作り方を紹介してきました。
ところがこれらのコードのままだと、商品の公開状態(公開・非公開・廃止)に関係なく、すべての商品が表示されてしまいます。
商品管理で「サンプル_4」を非公開にしているのに……
自作ページを開くと、そのまま表示されてしまう
デフォルトで用意されている商品一覧ページは、非公開・廃止の商品が自動で非表示になります。修正が必要なのは自作したページ・ブロックだけです。
【動作環境】EC-CUBEのバージョン:4.3.0 / サーバー:XServer
非公開や廃止でも表示されてしまう理由
理由は単純で、自作したページに「公開状態を見て表示を切り替える」処理を入れていないからです。デフォルトの一覧ページには入っていますが、自分で作ったものには当然入っていません。
つまり、次のどちらかを足せば解決します。
- Twigテンプレート側で、公開状態が「公開」のときだけ表示する
ifを書く - Controller側で、商品を取り出すときの検索条件に「公開のもの」を足す
公開ステータスは3種類ある
商品の公開状態は、データベースの mtb_product_status というマスタに入っています。
mtb_product_status の中身(初期状態)
| 値 | 名称 | フロント画面での扱い |
|---|---|---|
| 1 | 公開 | 表示される |
| 2 | 非公開 | 表示されない |
| 3 | 廃止 | 表示されない |
今回はこのうち 「公開」=1 だけを通せばよい、ということになります。
「廃止」は削除の代わりです。商品情報は受注情報などに紐づいているため、消してしまうと過去の注文が壊れます。そのため物理的には消さず、廃止という状態にして表から見えなくする作りになっています。
EC-CUBE本体では、この3つの値に ProductStatus::DISPLAY_SHOW(1)・DISPLAY_HIDE(2)・DISPLAY_ABOLISHED(3)という名前が付けられています。Controller側で書く場合は、数字の 1 よりこの定数を使うほうが意図が伝わります。
【方法1】Twigテンプレートに if 文を足す
自動更新される新着商品一覧ページ のTwigテンプレートを例に修正します。
Controllerから渡された商品情報は Product に入っており、公開状態は Product.status で、その値は Product.status.id で取り出せます。したがって次のように囲めば、公開の商品だけが表示されます。
{% if Product.status.id == 1 %}
~~商品情報~~
{% endif %}
実際に、新着商品一覧のTwigテンプレート全体へ適用すると次のようになります。
{% extends 'default_frame.twig' %}
{% block main %}
<h1>新着商品ページ</h1>
<div class="ec-shelfRole">
<ul class="ec-shelfGrid">
{% for Product in Products %}
{# 公開状態が「公開」の場合のみ商品を表示 #}
{% if Product.status.id == 1 %}
<li class="ec-shelfGrid__item">
<a href="{{ url('product_detail', {'id': Product.id}) }}">
<p class="ec-shelfGrid__item-image">
<img src="{{ asset(Product.main_list_image|no_image_product, 'save_image') }}" alt="{{ Product.name }}">
</p>
<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>
</a>
</li>
{% endif %}
{% endfor %}
</ul>
</div>
{% endblock %}
先ほどと同じように「サンプル_4」を非公開にしてページを開くと、今度はきちんと消えています。
非公開にした「サンプル_4」が一覧から消えた
{% if %} や {% for %} の書き方は Twig まとめ(2) にまとめています。
【方法2】findBy に条件を足す
そもそもController側で商品を取り出すときに、公開の商品だけを取ってくるという手もあります。商品を検索する部分を次のように書き換えてください。
$products = $this->productRepository->findBy(
['Status' => 1],
['id' => 'DESC']
);
findBy() の第1引数には絞り込み条件を配列で渡せるので、そこへ ['Status' => 1] を加えました。第2引数はこれまでどおり並び順の指定です。
この方法なら公開状態が「公開」の商品だけがTwigへ渡るため、Twig側は一切変更しなくて構いません。
findBy() をはじめとするRepositoryのメソッドについては リポジトリでよく使われるメソッド解説 にまとめています。
どちらを使えばいい?
| 方法1(Twigのif) | 方法2(findByの条件) | |
|---|---|---|
| 直す場所 | Twigテンプレート | Controller |
| データベースから取る件数 | 全件(表示時に間引く) | 公開の商品のみ |
| 表示件数を絞っているとき | 件数が合わなくなる | 正しく揃う |
| 向いている場面 | Controllerを触りたくないとき | 基本はこちら |
「3件だけ表示」のように件数を絞っている場合は方法2を選んでください。方法1は取り出したあとに間引くため、取ってきた3件のうち2件が非公開だと1件しか並ばないということが起きます。
まとめ
商品の公開ステータスに応じて表示を切り替える方法を2つ紹介しました。
- 自作した一覧ページ・ブロックは、公開状態を見ていないため非公開の商品まで出てしまう
- 公開ステータスは 1=公開 / 2=非公開 / 3=廃止 の3種類
- Twig側なら
{% if Product.status.id == 1 %}で囲む - Controller側なら
findBy()の条件に['Status' => 1]を足す - 表示件数を絞っているならController側で対応する
商品が廃盤になったり、一時的に非公開にしたい場面はよくあります。応用すれば、商品ページに「完売」「SOLD OUT」と出すといったこともできます。ぜひ試してみてください。
EC-CUBEのカスタマイズに関する記事
- カスタマイズのまとめ
- 自動更新される新着商品一覧ページ / ブロックを作る方法
- 特定のタグを付けた商品のみを抽出し、一覧ページを作る方法
- リポジトリでよく使われるメソッド解説(find, findByなど)
- Twig まとめ(2) ~ if / for / set / with ~

