Shopify

Shopify : planifiez vos contenus avec précision (sans app)

En tant qu’agence Shopify, nous avons rencontré un défi technique qui paraissait simple au début : comment planifier l’affichage de contenus à des dates précises (Black Friday, soldes, lancements produits) tout en tenant compte du système de cache de Shopify ?

Cet article vous présente une solution complète et technique pour automatiser l’affichage de vos blocs et sections Shopify en fonction de dates planifiées, tout en maîtrisant parfaitement le cache côté rendu.

Cette approche ne nécessite pas d’app Shopify payantes, elle est complètement gratuite.

Le défi du cache Shopify

Comment fonctionne le cache Shopify ?

Shopify utilise un système de cache agressif pour optimiser les performances de votre boutique. Lorsqu’un visiteur accède à une page, Shopify met en cache le rendu HTML pendant une durée variable (généralement entre 5 minutes et plusieurs heures).

Le problème : Si vous planifiez l’affichage d’une bannière Black Friday pour le 24 novembre à 00h00, mais que le cache a été généré le 23 novembre à 23h50, vos visiteurs continueront à voir l’ancienne version jusqu’à l’expiration du cache.

Les dates d’invalidation du cache

Shopify invalide automatiquement son cache dans plusieurs situations :

  • modification d’un produit
  • changement de prix
  • mise à jour du thème Shopify
  • modification de certains metafields

Notre solution exploite ce dernier point : en mettant à jour un metafield de la boutique à des dates précises, nous forçons Shopify à régénérer le cache exactement quand nous le souhaitons.

Architecture de la solution

Notre système repose sur trois composants :

  1. un Meta Object contenant une liste de dates d’invalidation
  2. un Shopify Flow qui s’exécute périodiquement pour mettre à jour le cache
  3. un Cloudflare Worker qui calcule intelligemment la prochaine date d’invalidation
  4. des sections/blocs Shopify avec logique conditionnelle basée sur les dates

Nous souhaitions utiliser uniquement Shopify flow pour le calcul de la prochaine date d’invalidation du cache mais Shopify bloque les fonctions sur les dates dans l’action Run Code, comme indiqué dans leur doc :

Exécution de code JavaScript dans Shopify

Mise en place technique

1. Créer le Meta Object pour les dates

Créez un Meta Object date_list avec un champ de type List of date and time :

{
  "name": "List date",
  "type": "date_list",
  "fields": [
    {
      "key": "name",
      "name": "Nom",
      "type": "single_line_text_field"
    },
    {
      "key": "date",
      "name": "Date",
      "type": "date_time"
    }
  ]
}

Ajoutez ensuite vos dates importantes :

  • 2025-11-24T00:00:00Z (Début Black Friday)
  • 2025-11-24T23:59:00Z (Fin Black Friday)
  • 2025-12-26T00:00:00Z (Début Soldes)
Shopify metaobject : Interface de saisie de date

2. Créer le metafield de cache

Créez un metafield au niveau boutique (Shop) pour stocker la date actuelle du cache :

{
  "namespace": "custom",
  "key": "date_invalidate_cache",
  "type": "date_time"
}
Shopify metafield : Définition de champ méta Shop

3. Déployer le Cloudflare Worker

Un worker permet d’éxécuter un petit bout de code en dehors de votre boutique Shopify.
Très pratique par palier aux limitations de Shopify et sans passer par une application gratuite ou payante.

Le worker calcule quelle est la prochaine date d’invalidation à utiliser :

export default {
  async fetch(request, env, ctx) {
    if (request.method !== "POST") {
      return new Response("Method Not Allowed", { status: 405 });
    }

    try {
      const body = await request.json();
      const { dates, cache_date, timezoneOffset } = body;

      // Validation
      if (!dates || !Array.isArray(dates) || !('cache_date' in body) || !('timezoneOffset' in body)) {
        return new Response(JSON.stringify({ error: "Missing required fields" }), {
          status: 400,
          headers: { "Content-Type": "application/json" },
        });
      }

      // Helpers
      const parseDate = (dateStr) => new Date(dateStr).getTime();
      const toMinute = (ts) => Math.floor(ts / 60000) * 60000;
      const parseOffset = (offsetStr) => {
        if (!offsetStr) return 0;
        const sign = offsetStr.startsWith("-") ? -1 : 1;
        const hours = parseInt(offsetStr.slice(1, 3), 10);
        const minutes = parseInt(offsetStr.slice(3, 5), 10);
        return sign * (hours * 60 + minutes) * 60 * 1000;
      };

      const now = Date.now();
      const offsetMs = timezoneOffset ? parseOffset(timezoneOffset) : 0;

      // Convertir cache_date (Local Time) en UTC
      let cacheDateTimestamp = cache_date ? parseDate(cache_date) : 0;
      if (cache_date && timezoneOffset) {
        cacheDateTimestamp -= offsetMs;
      }

      // Filtrer les dates valides (entre cache_date et now)
      const validDates = dates.filter((dateStr) => {
        const timestamp = parseDate(dateStr);
        return toMinute(timestamp) >= toMinute(cacheDateTimestamp) && toMinute(timestamp) <= toMinute(now);
      });

      if (validDates.length === 0) {
        return new Response(null, { status: 204 });
      }

      // Trouver la date la plus proche de now
      validDates.sort((a, b) => parseDate(b) - parseDate(a));
      const closestDate = validDates[0];

      // Si identique à cache_date, pas de mise à jour
      if (toMinute(parseDate(closestDate)) === toMinute(cacheDateTimestamp)) {
        return new Response(null, { status: 204 });
      }

      return new Response(JSON.stringify({ cache_date: closestDate }), {
        headers: { "Content-Type": "application/json" },
      });

    } catch (e) {
      return new Response(JSON.stringify({ error: e.message }), {
        status: 500,
        headers: { "Content-Type": "application/json" },
      });
    }
  },
};

Déployez ce worker sur Cloudflare et notez l’URL.

4. Configurer le Shopify Flow

Créez un Flow qui s’exécute toutes les 10 minutes :

Trigger : Scheduled (Every 10 minutes)

Action 1 – Get metaobject data : Récupérer toutes les entrées de la définition date_list

Action 2 – Send HTTP request :

Method: POST
URL: https://votre-worker.workers.dev
Body:
{
  "dates": [
    {% for item in getMetaobjects %}
    "{{ item.date.value | date: '%Y-%m-%dT%H:%M:%SZ' }}"{% unless forloop.last %},{% endunless %}
    {% endfor %}
  ],
  "cache_date": "{{ shop.metafields.custom.date_invalidate_cache | date: '%Y-%m-%dT%H:%M:%SZ' }}",
  "timezoneOffset": "{{ shop.timezone | date: '%z' }}"
}

Condition : If Status code equals 200

Action 3 – Run code :

export default function main(input) {
  const data = JSON.parse(input.sendHttpRequest.body);

  return {
    cache_date: data.cache_date
  };
}

Output type:
{
  cache_date: String!
}

Action 4 – Update shop metafield :

  • Namespace: custom
  • Key: date_invalidate_cache
  • Value: {{ runCode.cache_date }}

Voici le flow complet :

Shopify flow : Cache Shopify à invalider

5. Utiliser les dates dans vos sections Shopify

Maintenant que le cache est géré, créez des sections avec des champs de dates.

Créez un fichier de section sections/scheduled-banner.liquid :

Schema de section complet :

{% schema %}
{
  "name": "Bannière planifiée",
  "tag": "section",
  "class": "section-scheduled-banner",
  "settings": [
    {
      "type": "header",
      "content": "Contenu"
    },
    {
      "type": "text",
      "id": "title",
      "label": "Titre",
      "default": "Black Friday : -50% sur tout !"
    },
    {
      "type": "richtext",
      "id": "description",
      "label": "Description",
      "default": "<p>Profitez de nos offres exceptionnelles</p>"
    },
    {
      "type": "image_picker",
      "id": "background_image",
      "label": "Image de fond"
    },
    {
      "type": "url",
      "id": "cta_link",
      "label": "Lien du bouton"
    },
    {
      "type": "text",
      "id": "cta_text",
      "label": "Texte du bouton",
      "default": "Découvrir les offres"
    },
    {
      "type": "header",
      "content": "Planification"
    },
    {
      "type": "paragraph",
      "content": "Sélectionnez une date de début et de fin dans votre liste de dates. La section s'affichera automatiquement entre ces deux dates."
    },
    {
      "type": "metaobject",
      "id": "date_from",
      "label": "Date de début",
      "metaobject_type": "date_list"
    },
    {
      "type": "metaobject",
      "id": "date_to",
      "label": "Date de fin",
      "metaobject_type": "date_list"
    },
    {
      "type": "header",
      "content": "Style"
    },
    {
      "type": "color",
      "id": "background_color",
      "label": "Couleur de fond",
      "default": "#000000"
    },
    {
      "type": "color",
      "id": "text_color",
      "label": "Couleur du texte",
      "default": "#ffffff"
    },
    {
      "type": "range",
      "id": "padding_top",
      "min": 0,
      "max": 100,
      "step": 4,
      "unit": "px",
      "label": "Espacement haut",
      "default": 40
    },
    {
      "type": "range",
      "id": "padding_bottom",
      "min": 0,
      "max": 100,
      "step": 4,
      "unit": "px",
      "label": "Espacement bas",
      "default": 40
    }
  ],
  "presets": [
    {
      "name": "Bannière planifiée"
    }
  ]
}
{% endschema %}

Liquid de la section :

{% liquid
  assign now = 'now' | date: '%s' | times: 1
  assign cache_date = shop.metafields.custom.date_invalidate_cache.value | date: '%s' | times: 1
  assign date_from = section.settings.date_from.date.value | date: '%s' | times: 1
  assign date_to = section.settings.date_to.date.value | date: '%s' | times: 1

  assign show_section = false
  if now >= date_from and now <= date_to and cache_date >= date_from
    assign show_section = true
  endif
%}

{% if show_section %}
  <div class="scheduled-banner">
    <h2>{{ section.settings.title }}</h2>
    <!-- Votre contenu Black Friday ici -->
  </div>
{% endif %}
Gestion de la visibilité de section

Cas d’usage concrets

Bannière Black Friday automatique

Créez une bannière qui s’affiche automatiquement du 24 au 27 novembre :

  1. Créez deux entrées dans votre Meta Object « List date » :
  • Nom : « Début Black Friday », Date : 2025-11-24T00:00:00Z
  • Nom : « Fin Black Friday », Date : 2025-11-27T23:59:00Z
  1. Dans votre section, sélectionnez ces dates comme date_from et date_to
  2. Le cache sera invalidé automatiquement à minuit le 24 novembre et à minuit le 28 novembre

Compte à rebours des soldes

{% liquid
  assign soldes_start = section.settings.date_from.date.value | date: '%s' | times: 1
  assign now = 'now' | date: '%s' | times: 1
  assign cache_date = shop.metafields.custom.date_invalidate_cache.value | date: '%s' | times: 1
  assign diff = soldes_start | minus: now
%}

{% if diff > 0 and cache_date < soldes_start %}
  <div class="countdown" data-timestamp="{{ soldes_start }}">
    Les soldes commencent dans <span class="countdown-timer"></span>
  </div>
{% endif %}

Rotation de visuels saisonniers

Planifiez vos visuels pour toute l’année :

{% assign seasonal_banners = section.blocks | where: "type", "seasonal_banner" %}

{% for block in seasonal_banners %}
  {% liquid
    assign now = 'now' | date: '%s' | times: 1
    assign cache_date = shop.metafields.custom.date_invalidate_cache.value | date: '%s' | times: 1
    assign start = block.settings.date_from.date.value | date: '%s' | times: 1
    assign end = block.settings.date_to.date.value | date: '%s' | times: 1
  %}

  {% if now >= start and now <= end and cache_date >= start %}
    <img src="{{ block.settings.image | image_url }}" alt="{{ block.settings.alt }}">
    {% break %}
  {% endif %}
{% endfor %}

Avantages de cette approche

Pour votre Shopify theme

  1. Performance optimale : le cache Shopify reste actif, garantissant des temps de chargement rapides
  2. Précision temporelle : vos contenus s’affichent exactement aux dates prévues
  3. Flexibilité : modifiez vos dates sans toucher au code du thème

Pour votre équipe marketing

  1. Autonomie : Planifiez vos campagnes des semaines à l’avance
  2. Fiabilité : Plus de risque d’oublier d’activer une bannière
  3. Prévisualisation : Testez vos visuels en modifiant temporairement les dates

Pour vos performances

  1. Pas d’app tierce : Solution native utilisant Shopify Flow
  2. Serverless : Le Cloudflare Worker est gratuit jusqu’à 100 000 requêtes/jour
  3. Scalable : Fonctionne quelle que soit la taille de votre boutique

Conclusion

Cette solution technique permet de combiner le meilleur des deux mondes : la performance du cache Shopify et la précision de la planification automatisée.

En tant qu’agence Shopify, nous utilisons ce système pour tous nos clients ayant des besoins de planification de contenu. Il est particulièrement efficace pour :

  • Les campagnes saisonnières (Black Friday, Noël, Soldes)
  • Les lancements de produits
  • Les promotions flash
  • Les événements récurrents

Besoin d’aide pour implémenter cette solution ? Notre agence Shopify PrestaRocket vous accompagne dans l’optimisation technique de votre boutique. Contactez-nous