はじめに
Shopifyでセールやキャンペーンを実施する際、専用のページにおいて「商品を特定の日時から表示したい」「セール終了後は自動で商品を非表示にしたい」といったご要望をお持ちの店舗運営者様は多いのではないでしょうか。
たとえば、こんなシーンでお困りではありませんか?
-
タイムセールの準備:
深夜0時ちょうどにセール用のコレクションページに商品を表示させたいが、手動で表示を切り替えるのは現実的でない -
限定キャンペーン:
特定期間のみページに商品を表示し、期間終了後は自動で非表示にしたい -
季節商品の管理:
販売期間が決まっている商品を、特集ページに適切なタイミングで自動表示・非表示したい
通常、コレクションの商品グリッドは手動で表示/非表示を切り替える必要がありますが、今回ご紹介する方法を使えば事前に設定した日時で自動的に商品一覧の表示/非表示を切り替えることができます。
コーディングに不慣れな方でも、手順に沿って進めるだけですぐに実装できますので、ぜひ最後までご覧ください!
実装方法
1. メタフィールドの定義を設定
設定 > メタフィールドおよびメタオブジェクト でコレクションのメタフィールドを追加します。
「定義を追加する」から、名前に「商品表示制御(開始)」など任意の名称を入力し、その下にある「custom」をクリックして、ネームスペースとキーを「collection_schedule.start」と変更します。
「タイプを選択」で日付と時刻を選び保存すれば、1つ目のメタフィールドが作成されます。
終了日時用として2つ目のメタフィールドを追加し、名前を「商品表示制御(終了)」、ネームスペースとキーを「collection_schedule.end」で設定すればメタフィールドの定義設定は完了です。
(画像はクリックで拡大します)

2. 指定した日時で表示が切り替わるようコードを変更
手順1で作成したメタフィールドによって表示が制御されるようにするため、商品グリッドのセクションのコードを変更します。
管理画面のオンラインストアで「カスタマイズ」ボタン横の三点リーダーをクリックし、「コードを編集」を開きます。
画面上部の検索窓に「main-collection-product-grid.liquid」と入力し、該当のLiquidファイルを開きます。
※バックアップのため、既存のコード全体を事前にどこかへコピペしておくか、あらかじめテーマ自体を複製しておくことをお勧めいたします。
下記コードを全てコピーし、開いたLiquidファイル全体を上書きして保存します。
{{ 'template-collection.css' | asset_url | stylesheet_tag }}
{{ 'component-card.css' | asset_url | stylesheet_tag }}
{{ 'component-price.css' | asset_url | stylesheet_tag }}
{% if section.settings.image_shape == 'blob' %}
{{ 'mask-blobs.css' | asset_url | stylesheet_tag }}
{%- endif -%}
{%- unless section.settings.quick_add == 'none' -%}
{{ 'quick-add.css' | asset_url | stylesheet_tag }}
{%- endunless -%}
{%- if section.settings.quick_add == 'standard' -%}
<script src="{{ 'quick-add.js' | asset_url }}" defer="defer"></script>
<script src="{{ 'product-form.js' | asset_url }}" defer="defer"></script>
{%- endif -%}
{%- if section.settings.quick_add == 'bulk' -%}
<script src="{{ 'quick-add-bulk.js' | asset_url }}" defer="defer"></script>
<script src="{{ 'quantity-popover.js' | asset_url }}" defer="defer"></script>
<script src="{{ 'price-per-item.js' | asset_url }}" defer="defer"></script>
<script src="{{ 'quick-order-list.js' | asset_url }}" defer="defer"></script>
{%- endif -%}
{%- style -%}
.section-{{ section.id }}-padding {
padding-top: {{ section.settings.padding_top | times: 0.75 | round: 0 }}px;
padding-bottom: {{ section.settings.padding_bottom | times: 0.75 | round: 0 }}px;
}
@media screen and (min-width: 750px) {
.section-{{ section.id }}-padding {
padding-top: {{ section.settings.padding_top }}px;
padding-bottom: {{ section.settings.padding_bottom }}px;
}
}
:root {
--discountrate-bg-color: {{ section.settings.color_discountbk }};
--discountrate-txt-color: {{ section.settings.color_discount }};
}
{%- endstyle -%}
<!-- 商品表示開始・終了日時取得 -->
{% assign current_time = 'now' | date: '%s' %}
{% assign collection_start_time = collection.metafields.collection_schedule.start | date: '%s' %}
{% assign collection_end_time = collection.metafields.collection_schedule.end | date: '%s' %}
{% if current_time > collection_start_time %}
{% assign displayable = true %}
{% if current_time > collection_end_time %}
{% assign displayable = false %}
{% endif %}
{% endif %}
{% if displayable %} <!-- 商品表示中 -->
<div class="section-{{ section.id }}-padding gradient color-{{ section.settings.color_scheme }}">
{%- paginate collection.products by section.settings.products_per_page -%}
{% comment %} Sort is the first tabbable element when filter type is vertical {% endcomment %}
{%- if section.settings.enable_sorting and section.settings.filter_type == 'vertical' -%}
<facet-filters-form class="facets facets-vertical-sort page-width small-hide">
<form class="facets-vertical-form" id="FacetSortForm">
<div class="facet-filters sorting caption">
<div class="facet-filters__field">
<h2 class="facet-filters__label caption-large text-body">
<label for="SortBy">{{ 'products.facets.sort_by_label' | t }}</label>
</h2>
<div class="select">
{%- assign sort_by = collection.sort_by | default: collection.default_sort_by -%}
<select
name="sort_by"
class="facet-filters__sort select__select caption-large"
id="SortBy"
aria-describedby="a11y-refresh-page-message"
>
{%- for option in collection.sort_options -%}
<option
value="{{ option.value | escape }}"
{% if option.value == sort_by %}
selected="selected"
{% endif %}
>
{{ option.name | escape }}
</option>
{%- endfor -%}
</select>
<span class="svg-wrapper">
{{- 'icon-caret.svg' | inline_asset_content -}}
</span>
</div>
</div>
</div>
<div class="product-count-vertical light" role="status">
<h2 class="product-count__text text-body">
<span id="ProductCountDesktop">
{%- if collection.results_count -%}
{{
'templates.search.results_with_count'
| t: terms: collection.terms, count: collection.results_count
}}
{%- elsif collection.products_count == collection.all_products_count -%}
{{ 'products.facets.product_count_simple' | t: count: collection.products_count }}
{%- else -%}
{{
'products.facets.product_count'
| t: product_count: collection.products_count, count: collection.all_products_count
}}
{%- endif -%}
</span>
</h2>
{%- render 'loading-spinner' -%}
</div>
</form>
</facet-filters-form>
{%- endif -%}
<div class="{% if section.settings.filter_type == 'vertical' %} facets-vertical page-width{% endif %}">
{{ 'component-facets.css' | asset_url | stylesheet_tag }}
<script src="{{ 'facets.js' | asset_url }}" defer="defer"></script>
{%- if section.settings.enable_filtering or section.settings.enable_sorting -%}
<aside
aria-labelledby="verticalTitle"
class="facets-wrapper{% unless section.settings.enable_filtering %} facets-wrapper--no-filters{% endunless %}{% if section.settings.filter_type != 'vertical' %} page-width{% endif %}"
id="main-collection-filters"
data-id="{{ section.id }}"
>
{% render 'facets',
results: collection,
enable_filtering: section.settings.enable_filtering,
enable_sorting: section.settings.enable_sorting,
filter_type: section.settings.filter_type,
paginate: paginate
%}
</aside>
{%- endif -%}
<div
class="product-grid-container{% if settings.animations_reveal_on_scroll %} scroll-trigger animate--slide-in{% endif %}"
id="ProductGridContainer"
{% if settings.animations_reveal_on_scroll %}
data-cascade
{% endif %}
>
{%- if collection.products.size == 0 -%}
<div class="collection collection--empty page-width" id="product-grid" data-id="{{ section.id }}">
<div class="loading-overlay gradient"></div>
<div class="title-wrapper center">
<h2 class="title title--primary">
{{ 'sections.collection_template.empty' | t -}}
<br>
{{
'sections.collection_template.use_fewer_filters_html'
| t: link: collection.url, class: 'underlined-link link'
}}
</h2>
</div>
</div>
{%- else -%}
<div
class="collection{% if section.settings.filter_type != 'vertical' %} page-width{% endif %}"
>
<div class="loading-overlay gradient"></div>
<ul
id="product-grid"
data-id="{{ section.id }}"
class="
grid product-grid grid--{{ section.settings.columns_mobile }}-col-tablet-down
grid--{{ section.settings.columns_desktop }}-col-desktop
{% if section.settings.quick_add == 'bulk' %} collection-quick-add-bulk{% endif %}
"
>
{% assign skip_card_product_styles = false %}
{%- for product in collection.products -%}
{% assign lazy_load = false %}
{%- if forloop.index > 2 -%}
{%- assign lazy_load = true -%}
{%- endif -%}
<li
class="grid__item{% if settings.animations_reveal_on_scroll %} scroll-trigger animate--slide-in{% endif %}"
{% if settings.animations_reveal_on_scroll %}
data-cascade
style="--animation-order: {{ forloop.index }};"
{% endif %}
>
{% render 'card-product',
card_product: product,
media_aspect_ratio: section.settings.image_ratio,
image_shape: section.settings.image_shape,
show_secondary_image: section.settings.show_secondary_image,
show_vendor: section.settings.show_vendor,
show_rating: section.settings.show_rating,
show_discount: section.settings.show_discount,
color_discountbk: section.settings.color_discountbk,
color_discount: section.settings.color_discount,
lazy_load: lazy_load,
skip_styles: skip_card_product_styles,
quick_add: section.settings.quick_add,
section_id: section.id
%}
</li>
{%- assign skip_card_product_styles = true -%}
{%- endfor -%}
</ul>
{%- if paginate.pages > 1 -%}
{% render 'pagination', paginate: paginate, anchor: '' %}
{%- endif -%}
</div>
{%- endif -%}
</div>
</div>
{%- endpaginate -%}
{% if section.settings.image_shape == 'arch' %}
{{ 'mask-arch.svg' | inline_asset_content }}
{%- endif -%}
</div>
{% endif %}
{% schema %}
{
"name": "t:sections.main-collection-product-grid.name",
"class": "section",
"settings": [
{
"type": "range",
"id": "products_per_page",
"min": 8,
"max": 36,
"step": 4,
"default": 16,
"label": "t:sections.main-collection-product-grid.settings.products_per_page.label"
},
{
"type": "range",
"id": "columns_desktop",
"min": 1,
"max": 6,
"step": 1,
"default": 4,
"label": "t:sections.main-collection-product-grid.settings.columns_desktop.label"
},
{
"type": "select",
"id": "columns_mobile",
"default": "2",
"label": "t:sections.main-collection-product-grid.settings.columns_mobile.label",
"options": [
{
"value": "1",
"label": "t:sections.main-collection-product-grid.settings.columns_mobile.options__1.label"
},
{
"value": "2",
"label": "t:sections.main-collection-product-grid.settings.columns_mobile.options__2.label"
}
]
},
{
"type": "color_scheme",
"id": "color_scheme",
"label": "t:sections.all.colors.label",
"info": "t:sections.all.colors.has_cards_info",
"default": "scheme-1"
},
{
"type": "header",
"content": "t:sections.main-collection-product-grid.settings.header__3.content"
},
{
"type": "select",
"id": "image_ratio",
"options": [
{
"value": "adapt",
"label": "t:sections.main-collection-product-grid.settings.image_ratio.options__1.label"
},
{
"value": "portrait",
"label": "t:sections.main-collection-product-grid.settings.image_ratio.options__2.label"
},
{
"value": "square",
"label": "t:sections.main-collection-product-grid.settings.image_ratio.options__3.label"
}
],
"default": "adapt",
"label": "t:sections.main-collection-product-grid.settings.image_ratio.label"
},
{
"type": "select",
"id": "image_shape",
"options": [
{
"value": "default",
"label": "t:sections.all.image_shape.options__1.label"
},
{
"value": "arch",
"label": "t:sections.all.image_shape.options__2.label"
},
{
"value": "blob",
"label": "t:sections.all.image_shape.options__3.label"
},
{
"value": "chevronleft",
"label": "t:sections.all.image_shape.options__4.label"
},
{
"value": "chevronright",
"label": "t:sections.all.image_shape.options__5.label"
},
{
"value": "diamond",
"label": "t:sections.all.image_shape.options__6.label"
},
{
"value": "parallelogram",
"label": "t:sections.all.image_shape.options__7.label"
},
{
"value": "round",
"label": "t:sections.all.image_shape.options__8.label"
}
],
"default": "default",
"label": "t:sections.all.image_shape.label"
},
{
"type": "checkbox",
"id": "show_secondary_image",
"default": false,
"label": "t:sections.main-collection-product-grid.settings.show_secondary_image.label"
},
{
"type": "checkbox",
"id": "show_vendor",
"default": false,
"label": "t:sections.main-collection-product-grid.settings.show_vendor.label"
},
{
"type": "checkbox",
"id": "show_rating",
"default": false,
"label": "t:sections.main-collection-product-grid.settings.show_rating.label",
"info": "t:sections.main-collection-product-grid.settings.show_rating.info"
},
{
"type": "select",
"id": "quick_add",
"default": "none",
"label": "t:sections.main-collection-product-grid.settings.quick_add.label",
"options": [
{
"value": "none",
"label": "t:sections.main-collection-product-grid.settings.quick_add.options.option_1"
},
{
"value": "standard",
"label": "t:sections.main-collection-product-grid.settings.quick_add.options.option_2"
},
{
"value": "bulk",
"label": "t:sections.main-collection-product-grid.settings.quick_add.options.option_3"
}
]
},
{
"type": "header",
"content": "t:sections.main-collection-product-grid.settings.header__1.content"
},
{
"type": "checkbox",
"id": "enable_filtering",
"default": true,
"label": "t:sections.main-collection-product-grid.settings.enable_filtering.label",
"info": "t:sections.main-collection-product-grid.settings.enable_filtering.info"
},
{
"type": "select",
"id": "filter_type",
"options": [
{
"value": "horizontal",
"label": "t:sections.main-collection-product-grid.settings.filter_type.options__1.label"
},
{
"value": "vertical",
"label": "t:sections.main-collection-product-grid.settings.filter_type.options__2.label"
},
{
"value": "drawer",
"label": "t:sections.main-collection-product-grid.settings.filter_type.options__3.label"
}
],
"default": "horizontal",
"label": "t:sections.main-collection-product-grid.settings.filter_type.label"
},
{
"type": "checkbox",
"id": "enable_sorting",
"default": true,
"label": "t:sections.main-collection-product-grid.settings.enable_sorting.label"
},
{
"type": "header",
"content": "t:sections.all.padding.section_padding_heading"
},
{
"type": "range",
"id": "padding_top",
"min": 0,
"max": 100,
"step": 4,
"unit": "px",
"label": "t:sections.all.padding.padding_top",
"default": 36
},
{
"type": "range",
"id": "padding_bottom",
"min": 0,
"max": 100,
"step": 4,
"unit": "px",
"label": "t:sections.all.padding.padding_bottom",
"default": 36
},
{
"type": "select",
"id": "show_discount",
"options": [
{
"value": "percent",
"label": "パーセント(●% OFF)"
},
{
"value": "yen",
"label": "通貨(〇〇 OFF)"
},
{
"value": "none",
"label": "非表示"
}
],
"default": "percent",
"label": "ディスカウント"
},
{
"type": "color",
"id": "color_discountbk",
"label": "ディスカウントバッジ背景カラー ",
"default": "#FCE2B2"
},
{
"type": "color",
"id": "color_discount",
"label": "ディスカウントバッジ文字カラー",
"default": "#D11515"
}
]
}
{% endschema %}
手順1でメタフィールドのネームスペースとキーを本記事と異なるものに設定した場合は、46,47行目にある「collection.metafields.collection_schedule.start」「collection.metafields.collection_schedule.end」のcollection_schedule.start/end部分を、ご自身で設定した内容に変更してください。

3. 商品の表示期間を設定
セール用のコレクションなど、商品の表示/非表示を制御したいコレクションのメタフィールドに、表示の開始・終了日時を設定します。
これにより、表示の開始前および終了後のコレクションページでは商品一覧が表示されず、表示期間中は通常通り商品が表示されるようになります。
まとめ
いかがでしたか?
コレクションページの商品の表示期間を自動制御できるようにすることで、値引き商品を適切なタイミングで露出させられたり、異なる期間設定で複数キャンペーンを並行して自動運用できたりなど、店舗運営者の皆様にとって多くのメリットが生まれます。
エンドユーザーにとっても分かりやすくなるため、顧客体験の向上にも繋がります。
この仕組みを応用すれば、幅広い施策での応用も可能です。
より戦略的かつ効率的な店舗運営が実現できるようになりますので、セールやキャンペーンの運用でお悩みの際はぜひご活用くださいね。
実装やその後の運用でお困りのことがございましたら、お気軽にお問い合わせください!