ShopifyでFullCalendar(無料)を使って営業日カレンダーを表示する

ShopifyでFullCalendar(無料)を使って営業日カレンダーを表示する

Shopifyに営業日カレンダーを表示したいと思い調べてみたところ、Googleカレンダーを使用する、もしくは有料アプリでどうにかする、という記事がほとんどだった。
とくに、体験・アクティビティ系などの予約カレンダーのような、商品を販売するための高機能のアプリが多く、単純に営業日のスケジュールをカレンダーのUIで表示したいだけなんだよ!だからわざわざ課金もしたくないんだよ!というニーズにマッチするものが見つからなかった。

Googleカレンダーの場合、iframeでの埋め込みは簡単なのだけど、中身のコードにアクセスすることはできないので、CSSで見た目を調整したり、表示する要素のカスタマイズをしたりはできない。
かといって、有料アプリを使うほど重要でもないしな…と悩んでいたら、FullCalendarを使ってGoogleカレンダーを自由にスタイリングするというような記事が見つかった。
ところが、それらの記事の多くは「FullCalendarでスタイリングしたGoogleカレンダーをサイトに表示する方法」であって、Shopifyでは使えるのかどうか、というところがはっきりする記事がなかなか見つからない。

というわけで、実装してみた方が早いのでやった。

結論、できた。

GoogleカレンダーとFullCalendarの導入

導入方法はたくさんのサイトで紹介されているのでそれを参照して設定。

Dawnテーマに挿入した完成画像

できあがりはこんな感じです。フッタの上に入れてみました。

Shopifyストアに実装したコード

theme.liquidのheadに記述するスクリプト


<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fullcalendar@5.3.2/main.min.css">
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@5.3.2/main.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@5.3.2/locales/ja.js"></script>

<script>

  document.addEventListener('DOMContentLoaded', function() {
    var calendarEl = document.getElementById('calendar');
  
    var calendar = new FullCalendar.Calendar(calendarEl, {
  
      googleCalendarApiKey: 'APIキー',
      eventSources: [
        {
          googleCalendarId: 'カレンダーID',//自分で作成したカレンダー
          display: 'background',
          className: 'gcal-event'
        },
        {
          googleCalendarId: 'ja.japanese#holiday@group.v.calendar.google.com',//日本の祝日カレンダー
          display: 'background',
          className: 'gcal-event'
        }
      ],
      initialView: 'dayGridMonth',//デフォルトを月表示にする
      headerToolbar: {
        left: '',
        center: 'title',
        right: 'prev,today,next'//ボタンの並び順
      },
      buttonText: {
        today: '今月',
        month: ''
      },
      locale: 'ja',//日本語表示設定
      dayCellContent: function (e) {
        e.dayNumberText = e.dayNumberText.replace('', '');//日付のセルから日を削除
      },
      fixedWeekCount: false,//6週間表示をやめる
      contentHeight: 300,//カレンダー本体の高さ
      aspectRatio: 1//カレンダーサイズのアスペクト比
    });
  
    calendar.render();

});

JSやCSSの読み込みはheadもしくはbodyの最後に記述することが多いのだけど、今回は営業日カレンダーなので、すべてのページのフッタ、もしくはサイドメニューやメインコンテンツ内などに表示されることを想定し、theme.liquidのheadで読み込むようにした。

eventSources

eventSourcesで指定したGoogleカレンダーのイベント情報を取ってくることができる。
複数のカレンダーを指定することが可能なので、自分で作成したカレンダーと、Googleカレンダーに用意されている「日本の祝日」のカレンダーの両方のイベントを表示できる。

classNameキーを指定するとイベントのセルにclassをつけることもできるので、CSSやらなにやらでそのセルにアクセスしたい場合はつけておくと楽。
イベントをどう表示するかをdisplayキーで指定できるので、セルを塗りつぶして色をつけたい場合は値をbackgroundにする。
ちなみにcolorキーを追加して直接セルの色を指定することもできるんだけど、テーマで用意しているCSSのカスタムプロパティを使ったりなんだりすることを考えると、スタイリングは別途CSSファイルでまとめて管理したほうが良いと思う。

このあたりの設定オプションはめちゃくちゃ種類があって充実しているので、公式ドキュメントを見ると(自分では使わなくても)めちゃ面白い。

dayCellContent

ここでひとつ注意。

      dayCellContent: function (e) {
        e.dayNumberText = e.dayNumberText.replace('', '');
      },

上記はロケールを日本語にした場合に日付につく「日」が不要だな〜って場合に、それを削除するための処理。

最初、2023年2月7日にアップデートされた最新版のパッケージ(v6.1.4)をダウンロードしてきて試していたら、ここが動かなかった。
だいぶ前に「日付が空になるで」っていうissueが立ってたのを見つけたがopenのまま。でも、v5系は動いているらしい。
ということでCDNでv5系のソースを持ってきている。
CDNを使いたくない場合はGitHubから以前のバージョンをダウンロードしてきて、アセットに格納し読み込めばOK。

あちこちのサイトで紹介されているコードなのに動かないな〜と思ったら、バージョンを変えたりして試せばいける場合があるよ!がんばれ!諦めるな!

描画するターゲットDOMのHTML

カレンダーのレンダリングに必要なターゲット要素としては下記のみで大丈夫なんだけど、

<div id="calendar"></div>

表示する位置などは適宜テーマファイルの中で好きなように調整。

<div class="grid page-width top-spacing-small">
  <div class="col-6">
    <div id="calendar"></div>
  </div>
</div>

それにしてもclass名がgridのコンポーネントの中身がflexだったり、かと思えばほんとにgridで組まれているコンポーネントがあったりと、CSS設計としてはなんだかややこしいよなぁという印象を持ちながらずっと作業してる。

自前のスタイリング用CSS

#calendar {
  width: 300px;
}

#calendar h2 {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 1rem;
}

#calendar table {
  background: var(--color-body-background);
}

#calendar table a {
  color: var(--color-base);
}

#calendar .fc-event-title {
  display: none;
}

#calendar th,
#calendar td,
#calendar .fc-col-header,
#calendar .fc-scrollgrid-sync-table {
  margin: 0;
  padding: 0;
}

#calendar .fc-daygrid-day-events {
  display: none;
}

#calendar a {
  pointer-events: none;
  text-decoration: none;
}

#calendar .fc-bg-event {
  background: var(--gradient-base-background-2)!important;
  opacity: 1!important;
}

Shopifyで注意すること

とくにないかも…
クロスオリジンが禁止されてるのではとか懸念はしてたけど、実際やってみたらShopifyCLIを使ったローカル開発環境でも、閲覧パスワードがかかった開発ストアでも、パスワードを外した本番ストアでも、ちゃんと表示された。

ただ、JSの読み込みタイミングかネットワークの都合かなにかで、Googleカレンダーのイベントが読み込めないなど、不安定になることがあった。headで読み込んでいると安定しているように思うので、レンダリングのブロッキングには注意したほうがいいかも。
(まあこれはShopifyの注意事項じゃないんだけども)