現在、商品の metafield で設定した販売開始時刻と、Liquid テーマ内で取得する現在時刻を比較することで、商品の販売可能期間を制限する機能を実現できないか調査、検証を行なっております。
検証を進めていく中で、Liquid テーマで取得した現在時刻が画面を更新しても更新されない、また、metafield を変更すると固定されていた現在時刻が再更新されるという事象が確認できました。
こちらについて、自分の環境でたまたま発生した現象なのか、shopify の仕様なのかの判断ができておらず、その点について確認させていただきたいです。
前提
前提としまして、今回の検証は以下のコードを Liquid ファイル内に設置し、商品ページ上に Liquid テーマが描画されたタイミングの時刻が表示される状態で行っております。
{{ ‘now’ | date: ‘%Y-%M-%d %H:%M:%S’ }}
また、metafield の変更は1分に1度、毎分40秒ごろに metafield 変更のAPIを実行する cron をローカルPCで動かして変更しております。
参考動画
今回確認したい仕様について、検証時の動画を下記リンクにアップしております。こちらも参考にしていただければと思います。(再生している動画を画面収録したものなので画質が悪いのですが、ご了承ください)
https://www.loom.com/share/c6a7d529ab284b97b1fc635548868156
質問
検証の結果、shopify のテーマ表示には下記のような仕様があるのかと推測しました。
これらの仕様について、shopify としてそのような仕様があるのかどうか、ご確認いただきたいです。
- shopify テーマを一度表示すると、しばらくの間その時の情報がキャッシュされ、再度画面を表示した際にはキャッシュされた画面が表示される
- 上記のキャッシュはブラウザによるキャッシュではなく shopify サーバーによりキャッシュされている
- キャッシュされる断面は shopify 管理者アカウントへのログイン状況や、使用端末(PC、スマホ)により異なる
- ストア内の何らかの metafield に変更があるとキャッシュが破棄され、画面が再描画される
- 3番の画面の再描画は即時 metafield の変更が反映されてから即時行われるのではなく、毎分00秒と30秒のタイミングで再描画が行われる
以下、上記のような仕様があると判断した根拠を記載します。
- liquid テーマに現在時刻を表示するコードを配置することで、画面描画時の時刻を画面上から確認できる状態を作り、検証しました。
その結果、一度画面を描画し時刻が表示されると、画面を更新してもしばらく(30分以上)その時間が表示され続けることから、liquid ファイルのレンダリング結果をどこかしらでキャッシュしているものと判断しました。
- リンクを添付した動画のように、複数ブラウザを並べて画面に表示される現在時刻を確認し、検証しました。
その結果、最初に描画が完了したブラウザに表示される時刻が、その後に画面更新した他のブラウザにも表示されました。これにより、ブラウザによるキャッシュではないと判断しました。
また、動画には収録できておりませんが別のPCでも同じページを確認してみましたが、こちらでも最初に描画したブラウザと同じ時刻が表示されました。
3番の metafield の変更によって画面の再描画が行われることからも、shopify でキャッシュをとっているものと考えております。(metafield が変更されたことを察知できるのは shopify 自身しかいないため)
- 複数のブラウザ、端末で上記検証をしていると、固定される現在時刻をいくつかのパターンでグループに分類できることができることに気付き、思い至りました。グループ内のあるブラウザで画面が再描画されると、同じグループないの別のブラウザもその時刻で固定されて表示されるのが確認できました。
現在確認しているのは下記の3パターンです。
a. shopify 管理者アカウントでログイン中のブラウザ
b. スマホ
c. その他のPCブラウザ
- こちらもリンクを添付した動画にある通りですが、metafield を変更してしばらくすると、10分以上前の時間で固定されていた画面上の現在時刻が再描画されるのを確認しております。
こちらは動画には入っておりませんが、metafield の変更を1分間隔で定期的に行うと、画面の再描画も同じスパンで行われることが確認できております。
- こちらについては推測の部分もあるのですが、上記の検証をしている中で、画面の再描画が行われるタイミングに偏りがあるように感じ、思い至りました。
00秒、30秒という時間は、
例えば、35秒付近で metafield を変更した場合も、55秒付近で metafield を変更した場合も、どちらも次の00秒あたりで画面が再描画されることから推測した値です。
以上、かなりの長文となってしまいましたが、よろしくお願いいたします。
1 Like
すいません、記述量が多いので、ざっくり読み飛ばして、まずは回答しますが、キャッシュ云々の部分はおいておいて、まず、Liquidのnow およびdateの仕様を誤解されているようですので、結論から言うと、試されようとしていることは、そのままですと期待する結果にはならないかと思います。
(フォーラムに投稿される場合は、回答を得やすいように、なるべく的を絞って、原因究明の対象が複数に渡る場合、例えば、今回の場合は、now | date の仕様と、Metafiledのキャッシュの可能性、の2つに分けて、短く投稿された方がよろしいかと思います)
{{ ‘now’ | date: ‘%Y-%M-%d %H:%M:%S’ }}
は、現在時刻ではなく、テーマ内のそのページで表示されているobjectの更新日時などになります。
https://shopify.dev/api/liquid/objects/date
https://shopify.github.io/liquid/filters/date/
Input
This page was last updated at {{ "now" | date: "%Y-%m-%d %H:%M" }}.
Output
This page was last updated at 2021-04-28 17:52.
検証していませんが、親オブジェクトを指定しない場合は、上記のようにそのページの更新時間になるようです。おそらく、キャッシュ的動作を認識されているのは、この前提条件を間違えていらっしゃるからかと思います。
Liquidの仕組みは、まずShopify側のテーマにアクセスがあると、テーマ内のLiquidコードがShopifyによってパースされて、該当する各データの値や条件分岐に沿って、結果がHTMLに埋め込まれて送信されます。基本的に、その時のサーバー上のShopifyのマスターデータの中身を返すものですので、独自にキャッシュするなどは考えにくいです。
現在、商品の metafield で設定した販売開始時刻と、Liquid テーマ内で取得する現在時刻を比較する
ことで、商品の販売可能期間を制限する機能を実現できないか調査、検証を行なっております。
いくつかやり方がありますが、APIを使わず、テーマ内で済ませる場合は、現在時刻をブラウザのJavaScriptで拾って、JSの変数に格納、一方、Metafieldsの値も、JSの変数に格納して、比較はJS内で行うのがシンプルかと思います。(タイムゾーンをShopifyの設定と、JSのコード内で合わせる必要がありますが)
以下がイメージのコードです。
const now = new Date(new Date().toLocaleString({ timeZone: ‘Asia/Tokyo’ }));
const metafield_date = Date.parse(‘{{ product.metafields.my_date }}’);
if (now.getTime() > metafield_date.getTime() ) {
// Do something…
}
これでも、実際の結果が期待と異なる、依然としてデータがキャッシュされているような気がする場合は、追加でご投稿ください。
ご確認、コメントありがとうございます。
また、返信が遅くなってしまい申し訳ありません。
now の仕様について、承知しました。
ご指摘の通り、完全に仕様を勘違いして検証していました。
ただ、やはり now で得られる時間が固定されてしまうのには変わりないので、どういった条件でページが生成されるのか、という観点で再度調査を行おうと思います。
ご教示いただいている javascript での現在時刻の取得、検証ですが、
javascript ですと使用している端末の時間設定に影響されてしまうことから、チーム内で検討した結果見送りとなった背景があります。
liquid による制御ができれば、より強固な販売期間設定が可能になると想定しているため、もう少し liquid で実現する方向で調査を進めてみます。
ありがとうございました。
1 Like
ご確認ありがとうございます。
ただ、やはり now で得られる時間が固定されてしまうのには変わりないので、どういった条件でページが生成されるのか、という観点で再度調査を行おうと思います。
もし結果がわかれば、こちらにご共有いただければと思います。 ただ、上記の私のコメントにあるように、pageの更新日時であるとしたら、pageを変更しないうちは固定になる気がするのですがいかがでしょうか?
ちなみに、もしサーバーサイドの日時で処理したいのであれば、テーマだけの完結ではなくなりますが、パートナーのカスタムアプリを使って、app proxiesを使えば、対象のストアのデータとサーバーの現在日時を比較して、その制御をテーマ側にLiquidに返すことも可能です。
https://shopify.dev/apps/online-store/app-proxies
サーバーを巻き込むのであれば、Liquidだけではなくて、サーバーサイドの実装も必要かと思います。(Liquidはそもそもデザイン制御言語なのでサーバーサイドの処理は想定していません)
以下でapp proxyについて解説しているので、よろしければご参照ください。
https://www.youtube.com/watch?v=w31mCsEWGhQ&list=PLkR3LRtxAZfqujVTfvuHGpNgVTdbrwJRK&index=12