• Shopifyでデジタルコンテンツのサブスクリプション販売(定期購入)を実現する方法がわかる

  • 会員(サブスク加入者)と非会員で表示ページやコンテンツを切り分ける方法がわかる

  • 会員ページにダウンロード可能な画像・動画の一覧を設置する方法がわかる(コード付き)

画像やテンプレート、イラストなどのデジタルコンテンツを定期購買モデルで販売したいというニーズが増えています。

特に以下のような運用を希望する事業者が多く見られます:

  • ファンクラブのように、加入者だけがアクセスできる会員専用ページを用意したい

  • 会員専用ページ内の画像や動画を、会員が自由にダウンロードできるようにしたい

  • 非会員には、コンテンツを非公開にする/1点ごとの都度購入のみとする

しかし、Shopifyの標準機能や定期購買アプリ単体では、ページ表示の切り分けダウンロードコンテンツの設置はできません。

この記事では、定期購買アプリ+表示制御アプリ+カスタムセクションを組み合わせて、この運用を実現する方法をご紹介します。

以下の構成により、希望する運用が可能となります。

  1. 定期購買アプリ:会費のサブスク販売と、契約状態に応じた顧客タグの自動付与

  2. 表示制御アプリ(EasyLockdownなど):タグを持つ顧客だけに会員ページを表示

  3. カスタムセクション:会員ページ内にダウンロード可能な画像・動画一覧を設置

「月額会費」など、会員権を表す商品を作成します。

販売するのはデジタルコンテンツそのものではなく、"会員権(会費)"である点がこの構成のポイントです。コンテンツ自体は会員専用ページに設置します(3章で解説)。

作成した会費商品に定期購買プランを紐づけ、請求間隔(毎月など)や継続割引を設定します。

一般設定>タグ設定>顧客管理タグにて、以下2点の設定をONにします。

  • アクティブな定期購買契約が存在している場合に指定タグを付与

  • すべての定期購買契約が解約された場合に指定タグを付与

この設定により、アクティブな定期購買契約を持つ顧客には「Active_Subscriber」タグ(初期値。任意の名前に変更可能)が自動で付与され、すべての定期契約が解約されるとタグが外れます

顧客タグについての詳細はこちら

注意:

この動きが成立するのは、顧客の定期契約が「会費」1件のみの場合です。

会費以外の定期商品も販売しているストアでは、顧客が会費を解約しても他の定期契約が残っている限りタグは外れず、コンテンツを閲覧できる状態が続きます。このようなストア様には、「Active_Subscriber」タグによる表示/非表示の管理はお勧めしません。

EasyLockdownなどのShopifyアプリを使用し、特定のタグ(例:Active_Subscriber)を持つ顧客のみにページを表示できます。

非会員には非公開または別ページを表示可能です。

参考:EasyLockdownの導入・設定方法ガイド

会員専用ページの中に、画像や動画をダウンロードできる一覧を設置します。

ファンクラブのように「会員になれば、ページ内のコンテンツを自由にダウンロードできる」という運用であれば、この構成だけで完結します。

下記のカスタムセクションをテーマに追加することで実現できます。

  • 画像・動画をグリッド表示し、それぞれにダウンロードボタンを設置できる

  • コンテンツごとに表示期間を設定できる(例:「3月の限定コンテンツ」を期間終了後に自動で非表示 → 月替わりコンテンツの運用に便利です)

  • 保存時のファイル名を指定できる

  1. Shopify管理画面 > オンラインストア > テーマ > 「…」> コードを編集

  2. sections フォルダに download-media-list.liquid を新規作成し、下記コードを貼り付けて保存

  3. テーマエディタで会員専用ページを開き、セクション「ダウンロード画像・動画一覧」を追加

  4. ブロックを追加し、画像または動画を登録

Plaintext
{% liquid
  assign now_ts = 'now' | date: '%s'
%}

<section class="download-media-list page-width">
  <div class="download-media-list__inner">
    {% for block in section.blocks %}
      {% assign show_block = true %}

      {% if block.settings.start_at != blank %}
        {% assign start_ts = block.settings.start_at | date: '%s' %}
        {% if now_ts < start_ts %}
          {% assign show_block = false %}
        {% endif %}
      {% endif %}

      {% if block.settings.end_at != blank %}
        {% assign end_ts = block.settings.end_at | date: '%s' %}
        {% if now_ts > end_ts %}
          {% assign show_block = false %}
        {% endif %}
      {% endif %}

      {% if show_block %}
        {% assign media_type = '' %}
        {% assign download_url = '' %}

        {% if block.settings.video != blank %}
          {% assign media_type = 'video' %}
          {% if block.settings.download_url != blank %}
            {% assign download_url = block.settings.download_url %}
          {% else %}
            {% assign mp4_source = block.settings.video.sources | where: 'format', 'mp4' | sort: 'height' | last %}
            {% if mp4_source %}
              {% assign download_url = mp4_source.url %}
            {% endif %}
          {% endif %}
        {% elsif block.settings.image != blank %}
          {% assign media_type = 'image' %}
          {% if block.settings.download_url != blank %}
            {% assign download_url = block.settings.download_url %}
          {% else %}
            {% assign download_url = block.settings.image | image_url: width: 2000 %}
          {% endif %}
        {% endif %}

        {% if media_type != blank %}
          <div class="download-media-card" {{ block.shopify_attributes }}>
            {% if media_type == 'video' %}
              <div
                class="download-media-card__media js-download-media"
                data-download-url="{{ download_url }}"
                data-file-name="{{ block.settings.file_name | escape }}"
              >
                {{
                  block.settings.video
                  | video_tag:
                    controls: true,
                    autoplay: false,
                    loop: false,
                    muted: false,
                    image_size: '1200x'
                }}
              </div>
            {% elsif media_type == 'image' %}
              <img
                src="{{ block.settings.image | image_url: width: 1200 }}"
                alt="{{ block.settings.alt | escape }}"
                class="download-media-card__image js-download-media"
                data-download-url="{{ download_url }}"
                data-file-name="{{ block.settings.file_name | escape }}"
                loading="lazy"
                width="{{ block.settings.image.width }}"
                height="{{ block.settings.image.height }}"
              >
            {% endif %}

            {% if block.settings.show_button %}
              <button
                type="button"
                class="download-media-card__button js-download-button"
                data-download-url="{{ download_url }}"
                data-file-name="{{ block.settings.file_name | escape }}"
              >
                {{ block.settings.button_label | default: 'ダウンロード' }}
              </button>
            {% endif %}
          </div>
        {% endif %}
      {% endif %}
    {% endfor %}
  </div>
</section>

<style>
  .download-media-list {
    padding-top: 40px;
    padding-bottom: 40px;
  }

  .download-media-list__inner {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 20px;
  }

  .download-media-card {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }

  .download-media-card__image,
  .download-media-card__media video {
    display: block;
    width: 100%;
    height: auto;
    border-radius: 12px;
  }

  .download-media-card__image,
  .download-media-card__media {
    cursor: pointer;
  }

  .download-media-card__button {
    display: inline-flex;
    justify-content: center;
    align-items: center;
    padding: 12px 16px;
    border: 0;
    border-radius: 10px;
    cursor: pointer;
    background: #111;
    color: #fff;
    font-size: 14px;
    line-height: 1.4;
  }

  @media screen and (max-width: 989px) {
    .download-media-list__inner {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }

  @media screen and (max-width: 749px) {
    .download-media-list__inner {
      grid-template-columns: 1fr;
    }
  }
</style>

<script>
  (function () {
    async function handleDownload(url, fileName) {
      if (!url) return;

      try {
        const res = await fetch(url, { mode: 'cors' });
        const blob = await res.blob();

        const blobUrl = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = blobUrl;
        a.download = fileName || 'download';
        document.body.appendChild(a);
        a.click();
        a.remove();

        URL.revokeObjectURL(blobUrl);
      } catch (error) {
        window.open(url, '_blank');
      }
    }

    document.addEventListener('click', function (event) {
      const button = event.target.closest('.js-download-button');
      if (button) {
        handleDownload(button.dataset.downloadUrl, button.dataset.fileName);
        return;
      }

      const media = event.target.closest('.js-download-media');
      if (media) {
        if (event.target.tagName.toLowerCase() === 'video') return;
        handleDownload(media.dataset.downloadUrl, media.dataset.fileName);
      }
    });
  })();
</script>

{% schema %}
{
  "name": "ダウンロード画像・動画一覧",
  "tag": "section",
  "class": "section",
  "max_blocks": 20,
  "settings": [],
  "blocks": [
    {
      "type": "media_item",
      "name": "画像・動画",
      "settings": [
        {
          "type": "image_picker",
          "id": "image",
          "label": "画像"
        },
        {
          "type": "video",
          "id": "video",
          "label": "動画"
        },
        {
          "type": "text",
          "id": "alt",
          "label": "altテキスト(画像用)"
        },
        {
          "type": "url",
          "id": "download_url",
          "label": "ダウンロードURL",
          "info": "未入力の場合、画像は表示画像のURL、動画は動画ファイル(mp4)のURLを使用します"
        },
        {
          "type": "text",
          "id": "file_name",
          "label": "保存ファイル名",
          "default": "download",
          "info": "拡張子まで含めて指定してください(例:image.jpg、video.mp4)"
        },
        {
          "type": "checkbox",
          "id": "show_button",
          "label": "ダウンロードボタンを表示する",
          "default": true
        },
        {
          "type": "text",
          "id": "button_label",
          "label": "ボタン文言",
          "default": "ダウンロード"
        },
        {
          "type": "text",
          "id": "start_at",
          "label": "表示開始日時",
          "info": "例: 2026-03-23 00:00:00 +0900(時差まで含めて指定してください)"
        },
        {
          "type": "text",
          "id": "end_at",
          "label": "表示終了日時",
          "info": "例: 2026-03-31 23:59:59 +0900(時差まで含めて指定してください)"
        }
      ]
    }
  ],
  "presets": [
    {
      "name": "ダウンロード画像・動画一覧"
    }
  ]
}
{% endschema %}
  • ページの表示は会員限定にできますが、画像・動画ファイルのURL自体を知っている場合は、誰でもファイルにアクセスできます(Shopifyにアップロードしたメディアファイルの仕様です)

  • ダウンロード回数の制限(毎月10点までなど)は、このセクションでは行えません

  • 表示期間の判定はページ表示時に行われるため、キャッシュの状況により切り替わりに数分のずれが生じる場合があります

  • カスタムセクションの追加はテーマのコード編集を伴います。作業前にテーマの複製(バックアップ)をお勧めします

ダウンロード回数の制限や月ごとのリセット、より厳密なアクセス制御などが必要な場合は、別途アプリをご検討いただくか、弊社構築チームでのカスタマイズ対応もご相談可能です。ご希望がございましたらお気軽にご連絡ください。

参考:アプリを検討される場合は、下記の記事が参考になります。

Shopifyを活用したデジタルコンテンツ販売|始め方やアプリ、事例を解説

Shopifyでデジタルコンテンツ販売を始める方法を徹底解説!初心者向けの手順やおすすめアプリ、成功事例を紹介。デジタル商品の在庫管理不要や配送コスト削減などのメリットを活かし、効率的にビジネスを成長させましょう。

Tsun Inc.

Tsun Inc.

Shopifyで購入回数を毎月3回までに制限する方法|Shopifyアプリも紹介

Shopifyストアで会員1人あたりの月間購入回数を3回までに制限する方法を解説。RuffRuff注文制限アプリとShopify Flowを組み合わせた具体的な設定手順を画像付きで紹介。会員限定販売の実施方法や新規会員登録時の自動タグ付与など、実用的なノウハウを提供します。

Tsun Inc.

Tsun Inc.