Migration de Shopify Scripts vers Functions : tutoriel de code 2026

Migration de Shopify Scripts vers Functions : tutoriel de code 2026

Migration de Shopify Scripts vers Functions : tutoriel de code 2026

Comment migrer les scripts Shopify vers les fonctions : le tutoriel complet du code (édition 2026) — en-tête de l’article de blog Revize

Nous sommes le 16 avril 2026. Hier — le 15 avril — Shopify a définitivement verrouillé le Script Editor. Vous ne pouvez plus créer ni publier de nouveau Script. L'arrêt de l'exécution intervient dans 75 jours, le 30 juin 2026.

Si vous êtes un développeur Shopify Plus — ou l'agence qui gère une boutique Plus — et que vous avez repoussé cette migration au « prochain sprint » ces douze derniers mois, vous avez un problème. Pas un problème cosmétique. Un problème du type « votre tunnel de paiement plante à minuit le 1er juillet ». La plupart des boutiques Plus ont accumulé entre 5 et 20 Scripts au fil des ans, chacun gérant silencieusement une règle de réduction, un masquage de livraison ou une passerelle de paiement que personne ne se souvient avoir codée.

Ce guide est le manuel technique de migration que nous aurions aimé avoir en janvier. Il traite du code réel, pas seulement de la stratégie. À la fin de votre lecture, vous saurez comment échafauder une Function avec la Shopify CLI, écrire la logique en Rust ou JavaScript pour les réductions, les personnalisations de livraison et de paiement, la tester en toute sécurité sur un sous-ensemble de clients ciblé, et la déployer en production sans perturber votre checkout actuel.

Débarrassons votre boutique des Scripts et installons-y les Functions.



Developer migrating Shopify Scripts to Shopify Functions modules

Réponse rapide : Scripts → Functions en 60 secondes

La migration en un paragraphe : Les Shopify Scripts (code Ruby dans le Script Editor, réservés à Plus) sont remplacés par les Shopify Functions (modules WebAssembly écrits en Rust ou JavaScript, disponibles pour tous les forfaits). Vous générez une Function avec shopify app generate extension, écrivez une requête run.graphql qui récupère les données de panier nécessaires, écrivez un fichier run.rs ou run.js qui renvoie les opérations (réductions, modes de livraison masqués, etc.), puis déployez avec shopify app deploy et l'activez via l'Admin ou une mutation GraphQL. Les Functions s'exécutent sous forme de WASM compilé avec une latence inférieure à 5 ms, fonctionnent sur tous les forfaits et constituent l'unique voie de personnalisation prise en charge par Shopify à l'avenir.

Ce qui change réellement le 30 juin

Avant de toucher au code, actons les dates. Il y en a deux, et toutes deux sont cruciales.


Date

Événement

Action requise

15 avril 2026 (passé)

Script Editor en lecture seule. Aucun nouveau Script. Aucune modification des Scripts existants.

Les Scripts existants s'exécutent encore. Migrez maintenant ou figez votre logique.

30 juin 2026

Tous les Shopify Scripts cessent de s'exécuter. Définitivement.

Votre Function de remplacement doit être active avant cette date.

La migration est binaire. Soit votre Function est déployée d'ici le 30 juin et votre checkout continue de fonctionner, soit elle ne l'est pas — et chaque panier concerné appliquera par défaut les tarifs standards, les frais de livraison de base et l'ensemble des modes de paiement activés. Pas de demi-mesure. Le Script s'exécute ou ne s'exécute pas, et après le 30 juin, il ne s'exécutera plus.

Astuce : Allez dans Settings → Checkout → Customizations Report dans votre admin Shopify. Vous y trouverez la liste de chaque Script actif sur votre boutique, son rôle et le type de Function de remplacement recommandé. Commencez par là.

Functions vs Scripts : Ce qui a réellement changé


Critère

Shopify Scripts (obsolète)

Shopify Functions (remplacement)

Langage

Ruby DSL (propre à Shopify)

Rust, JavaScript, TypeScript

Environnement d'exécution

Ruby sandboxé sur l'infrastructure Shopify

WebAssembly (WASM) — exécution < 5ms

Forfaits compatibles

Plus uniquement

Tous les forfaits (les apps personnalisées nécessitent Plus ; les apps publiques sont ouvertes)

Éditeur

Script Editor intégré à l'admin

IDE local + Shopify CLI

Gestion des versions

Aucune — modifications en direct

Compatible Git — contrôle de version complet

Tests

Manuels dans le checkout

Développement local avec shopify app dev, liens d'aperçu

Déploiement

Clic sur "Enregistrer" dans l'admin

shopify app deploy depuis le terminal

Cibles

Articles du panier, expédition, paiements

Discounts, Cart Transform, Validation, Delivery Customization, Payment Customization, Order Routing, Fulfillment Constraints, et plus

Le changement d'architecture est fondamental. Les Scripts consistaient à « bricoler du Ruby dans une zone de texte ». Les Functions consistent à « écrire une véritable application, la versionner, la tester localement, la déployer via un pipeline CI digne de ce nom ». La courbe d'apprentissage est plus raide. C'est aussi la dernière migration que vous aurez à faire pour la logique de checkout dans un avenir prévisible — les Functions représentent l'engagement à long terme de Shopify, contrairement aux Scripts qui se sont avérés être une solution temporaire.

Associer vos Scripts au bon type de Function

Chaque Script actuel correspond à exactement une API de Function. Voici la table de correspondance à garder sous les yeux.


Ancien type de Script

Rôle

Nouvelle API de Function

Cible (Target)

Line Item Script

Appliquer des remises à des produits / clients / conditions de panier spécifiques

Cart & Checkout Discounts API

cart.lines.discounts.generate.run

Shipping Script (remise)

Livraison gratuite ou réduite selon des règles de panier

Cart & Checkout Discounts API

cart.delivery-options.discounts.generate.run

Shipping Script (masquer / renommer / réordonner)

Masquer un tarif au-dessus de X $, renommer "Standard" en "Gratuit dès 50 $"

Delivery Customization API

cart.delivery-options.transform.run

Payment Script

Masquer PayPal pour le B2B, masquer le paiement à la livraison au-dessus de 500 $, réordonner les modes de paiement

Payment Customization API

cart.payment-methods.transform.run

Script de modification de panier (rare)

Créer des lots de produits, remplacer des articles

Cart Transform API

cart.transform.run

Script de blocage du checkout

Refuser le panier si la combinaison de SKU est non valide

Cart & Checkout Validation API

cart.validations.generate.run

Si vous avez dix Scripts, vous développerez probablement entre trois et cinq Functions — plusieurs Scripts se résument souvent à une seule Function dotée d'une logique de branchement plus propre.



Shopify Functions unifying discounts, delivery, and payment customizations

Prérequis : Configurer votre environnement de développement local

Avant de générer une Function, vous devez installer trois outils en local. Exécutez ces vérifications dans votre terminal.

1. Node.js 18+


node --version
# Doit être >= 18.0.0
node --version
# Doit être >= 18.0.0

Si la version est plus ancienne, installez-la via nvm ou téléchargez-la sur nodejs.org.

2. Shopify CLI 3+


npm install -g @shopify/cli@latest
shopify version
# Doit afficher 3.x ou plus
npm install -g @shopify/cli@latest
shopify version
# Doit afficher 3.x ou plus

3. Toolchain Rust (uniquement si vous écrivez vos Functions en Rust)


curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup target add wasm32-wasip1
cargo --version
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup target add wasm32-wasip1
cargo --version

Les Functions en JavaScript n'ont pas besoin de Rust. Choisissez un langage pour votre équipe et tenez-vous-y — mélanger les deux ajoute des coûts de maintenance.

4. Une boutique de développement

Connectez-vous à votre tableau de bord Partner et créez une nouvelle boutique de développement, ou utilisez-en une existante. Vous y déploierez vos Functions avant de les passer en production.

Générer votre première Function

La CLI s'occupe de l'essentiel du code de base. Dans n'importe quel répertoire :


# Créer une nouvelle application Shopify (ignorez si vous en avez déjà une)
shopify app init my-checkout-functions
cd my-checkout-functions

# Générer une extension de type Function
shopify app generate extension
# Créer une nouvelle application Shopify (ignorez si vous en avez déjà une)
shopify app init my-checkout-functions
cd my-checkout-functions

# Générer une extension de type Function
shopify app generate extension

La CLI vous guide à travers différentes questions. Pour une Function de réduction, vous choisiriez :

  • Type : Function

  • Modèle : discount (ou cart_checkout_validation, delivery_customization, payment_customization, etc.)

  • Langage : Rust ou JavaScript

  • Nom : par exemple volume-discount-fn

Cela crée le répertoire extensions/volume-discount-fn/ contenant :


extensions/volume-discount-fn/
├── shopify.extension.toml      # Config de la Function cibles, build, version
├── src/
├── cart_lines_discounts_generate_run.graphql   # Requête d'entrée
└── cart_lines_discounts_generate_run.rs        # Logique de la Function
├── Cargo.toml                  # Dépendances Rust (Rust uniquement)
└── README.md
extensions/volume-discount-fn/
├── shopify.extension.toml      # Config de la Function cibles, build, version
├── src/
├── cart_lines_discounts_generate_run.graphql   # Requête d'entrée
└── cart_lines_discounts_generate_run.rs        # Logique de la Function
├── Cargo.toml                  # Dépendances Rust (Rust uniquement)
└── README.md

Les trois fichiers que vous modifierez en permanence sont le .toml (config), le .graphql (entrée) et le .rs / .js (logique). C'est tout.

Tutoriel 1 : Remplacer un Line Item Script (Remise sur volume)

Supposons que votre ancien Script appliquait une remise de 10 % sur le sous-total de la commande dès que le panier contenait au moins 5 articles d'une collection spécifique. Voici l'équivalent sous forme de Function.

Étape 1.1 : La configuration (shopify.extension.toml)


api_version = "2026-01"

[[extensions]]
name = "volume-discount-fn"
handle = "volume-discount-fn"
type = "function"

[[extensions.targeting]]
target = "cart.lines.discounts.generate.run"
input_query = "src/cart_lines_discounts_generate_run.graphql"
export = "cart_lines_discounts_generate_run"

[extensions.build]
command = "cargo build --target=wasm32-wasip1 --release"
path = "target/wasm32-wasip1/release/volume-discount-fn.wasm"
watch = ["src/**/*.rs"]
api_version = "2026-01"

[[extensions]]
name = "volume-discount-fn"
handle = "volume-discount-fn"
type = "function"

[[extensions.targeting]]
target = "cart.lines.discounts.generate.run"
input_query = "src/cart_lines_discounts_generate_run.graphql"
export = "cart_lines_discounts_generate_run"

[extensions.build]
command = "cargo build --target=wasm32-wasip1 --release"
path = "target/wasm32-wasip1/release/volume-discount-fn.wasm"
watch = ["src/**/*.rs"]

Étape 1.2 : La requête d'entrée (src/cart_lines_discounts_generate_run.graphql)


query Input {
  cart {
    lines {
      id
      quantity
      cost {
        subtotalAmount {
          amount
        }
      }
      merchandise {
        ... on ProductVariant {
          product {
            inAnyCollection(ids: ["gid://shopify/Collection/123456789"])
          }
        }
      }
    }
  }
  discount {
    discountClasses
  }
}
query Input {
  cart {
    lines {
      id
      quantity
      cost {
        subtotalAmount {
          amount
        }
      }
      merchandise {
        ... on ProductVariant {
          product {
            inAnyCollection(ids: ["gid://shopify/Collection/123456789"])
          }
        }
      }
    }
  }
  discount {
    discountClasses
  }
}

Astuce : Les Functions ne voient que les données que vous demandez. Limitez le GraphQL au strict minimum — chaque champ ignoré garantit une exécution plus rapide et moins coûteuse.

Étape 1.3 : La logique (src/cart_lines_discounts_generate_run.rs)


use super::schema;
use shopify_function::prelude::*;
use shopify_function::Result;

#[shopify_function]
fn cart_lines_discounts_generate_run(
    input: schema::cart_lines_discounts_generate_run::Input,
) -> Result<schema::CartLinesDiscountsGenerateRunResult> {
    // Arrêter si la classe de remise ne correspond pas
    let has_order_discount = input
        .discount()
        .discount_classes()
        .contains(&schema::DiscountClass::Order);

    if !has_order_discount {
        return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
    }

    // Sommer les quantités d'articles de la collection cible
    let qualifying_qty: i64 = input
        .cart()
        .lines()
        .iter()
        .filter(|line| {
            if let schema::Merchandise::ProductVariant(v) = line.merchandise() {
                *v.product().in_any_collection()
            } else {
                false
            }
        })
        .map(|line| *line.quantity())
        .sum();

    if qualifying_qty < 5 {
        return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
    }

    // Appliquer 10 % de réduction sur le sous-total de la commande
    Ok(schema::CartLinesDiscountsGenerateRunResult {
        operations: vec![schema::CartOperation::OrderDiscountsAdd(
            schema::OrderDiscountsAddOperation {
                selection_strategy: schema::OrderDiscountSelectionStrategy::First,
                candidates: vec![schema::OrderDiscountCandidate {
                    targets: vec![schema::OrderDiscountCandidateTarget::OrderSubtotal(
                        schema::OrderSubtotalTarget {
                            excluded_cart_line_ids: vec![],
                        },
                    )],
                    message: Some("Volume discount: 10% off".to_string()),
                    value: schema::OrderDiscountCandidateValue::Percentage(
                        schema::Percentage { value: Decimal(10.0) }
                    ),
                    conditions: None,
                    associated_discount_code: None,
                }],
            },
        )],
    })
}
use super::schema;
use shopify_function::prelude::*;
use shopify_function::Result;

#[shopify_function]
fn cart_lines_discounts_generate_run(
    input: schema::cart_lines_discounts_generate_run::Input,
) -> Result<schema::CartLinesDiscountsGenerateRunResult> {
    // Arrêter si la classe de remise ne correspond pas
    let has_order_discount = input
        .discount()
        .discount_classes()
        .contains(&schema::DiscountClass::Order);

    if !has_order_discount {
        return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
    }

    // Sommer les quantités d'articles de la collection cible
    let qualifying_qty: i64 = input
        .cart()
        .lines()
        .iter()
        .filter(|line| {
            if let schema::Merchandise::ProductVariant(v) = line.merchandise() {
                *v.product().in_any_collection()
            } else {
                false
            }
        })
        .map(|line| *line.quantity())
        .sum();

    if qualifying_qty < 5 {
        return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
    }

    // Appliquer 10 % de réduction sur le sous-total de la commande
    Ok(schema::CartLinesDiscountsGenerateRunResult {
        operations: vec![schema::CartOperation::OrderDiscountsAdd(
            schema::OrderDiscountsAddOperation {
                selection_strategy: schema::OrderDiscountSelectionStrategy::First,
                candidates: vec![schema::OrderDiscountCandidate {
                    targets: vec![schema::OrderDiscountCandidateTarget::OrderSubtotal(
                        schema::OrderSubtotalTarget {
                            excluded_cart_line_ids: vec![],
                        },
                    )],
                    message: Some("Volume discount: 10% off".to_string()),
                    value: schema::OrderDiscountCandidateValue::Percentage(
                        schema::Percentage { value: Decimal(10.0) }
                    ),
                    conditions: None,
                    associated_discount_code: None,
                }],
            },
        )],
    })
}

Étape 1.4 : Tester, déployer, activer


# Développement local avec rechargement à chaud
shopify app dev

# Lorsque vous êtes prêt, déployez
shopify app deploy

# Dans le panneau GraphiQL qui s'ouvre (appuyez sur `g` dans le terminal de dev),
# créez la remise automatique qui utilise votre Function :
# Développement local avec rechargement à chaud
shopify app dev

# Lorsque vous êtes prêt, déployez
shopify app deploy

# Dans le panneau GraphiQL qui s'ouvre (appuyez sur `g` dans le terminal de dev),
# créez la remise automatique qui utilise votre Function :
mutation {
  discountAutomaticAppCreate(
    automaticAppDiscount: {
      title: "Volume Discount (5+ collection items)"
      functionHandle: "volume-discount-fn"
      discountClasses: [ORDER]
      startsAt: "2026-04-16T00:00:00Z"
    }
  ) {
    automaticAppDiscount { discountId }
    userErrors { field message }
  }
}
mutation {
  discountAutomaticAppCreate(
    automaticAppDiscount: {
      title: "Volume Discount (5+ collection items)"
      functionHandle: "volume-discount-fn"
      discountClasses: [ORDER]
      startsAt: "2026-04-16T00:00:00Z"
    }
  ) {
    automaticAppDiscount { discountId }
    userErrors { field message }
  }
}

C'est tout. La Function est active, versionnée et remplace définitivement l'ancien Script.

Tutoriel 2 : Remplacer un Shipping Script (Masquer un mode de livraison selon le montant du panier)

Un Script classique : « Masquer la livraison Express lorsque le sous-total du panier dépasse 500 $ pour éviter des frais d'envoi de nuit exorbitants sur de grosses commandes. » Voici la version Delivery Customization avec une Function.

Étape 2.1 : Générer l'extension


shopify app generate extension --template delivery_customization --name hide-express-fn
shopify app generate extension --template delivery_customization --name hide-express-fn

Étape 2.2 : Requête d'entrée (src/run.graphql)


query Input {
  cart {
    cost {
      subtotalAmount {
        amount
      }
    }
    deliveryGroups {
      deliveryOptions {
        handle
        title
      }
    }
  }
}
query Input {
  cart {
    cost {
      subtotalAmount {
        amount
      }
    }
    deliveryGroups {
      deliveryOptions {
        handle
        title
      }
    }
  }
}

Étape 2.3 : Logique (src/run.js — variante JavaScript)


// @ts-check
/**
 * @typedef {import("../generated/api").RunInput} RunInput
 * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult
 */

const NO_CHANGES = { operations: [] };
const THRESHOLD = 500.0;
const HIDE_TITLES = ["Express", "Overnight"];

/**
 * @param {RunInput} input
 * @returns {FunctionRunResult}
 */
export function run(input) {
  const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount);
  if (subtotal < THRESHOLD) return NO_CHANGES;

  const operations = input.cart.deliveryGroups.flatMap((group) =>
    group.deliveryOptions
      .filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t)))
      .map((opt) => ({
        hide: { deliveryOptionHandle: opt.handle },
      }))
  );

  return { operations };
}
// @ts-check
/**
 * @typedef {import("../generated/api").RunInput} RunInput
 * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult
 */

const NO_CHANGES = { operations: [] };
const THRESHOLD = 500.0;
const HIDE_TITLES = ["Express", "Overnight"];

/**
 * @param {RunInput} input
 * @returns {FunctionRunResult}
 */
export function run(input) {
  const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount);
  if (subtotal < THRESHOLD) return NO_CHANGES;

  const operations = input.cart.deliveryGroups.flatMap((group) =>
    group.deliveryOptions
      .filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t)))
      .map((opt) => ({
        hide: { deliveryOptionHandle: opt.handle },
      }))
  );

  return { operations };
}

Étape 2.4 : Activer via l'Admin (sans GraphQL)

Les Delivery Customizations disposent d'une interface d'administration intégrée. Après l'exécution de shopify app deploy :

  1. Allez dans Settings → Shipping and delivery

  2. Faites défiler jusqu'à la section Customizations tout en bas

  3. Cliquez sur Add customization → sélectionnez votre Function

  4. Enregistrez

La règle de masquage est active en production. Aucune mutation requise.



Shopify delivery customization Function hiding shipping option at checkout

Tutoriel 3 : Remplacer un Payment Script (Masquer le paiement à la livraison pour le B2B)

Ancien Script : « Masquer le paiement à la livraison (COD) pour tout client doté du tag 'B2B'. » Voici la version Payment Customization.

Étape 3.1 : Générer l'extension


shopify app generate extension --template payment_customization --name hide-cod-b2b-fn
shopify app generate extension --template payment_customization --name hide-cod-b2b-fn

Étape 3.2 : Requête d'entrée


query Input {
  cart {
    buyerIdentity {
      customer {
        hasTags(tags: [{ tag: "B2B" }]) {
          tag
          hasTag
        }
      }
    }
  }
  paymentMethods {
    id
    name
  }
}
query Input {
  cart {
    buyerIdentity {
      customer {
        hasTags(tags: [{ tag: "B2B" }]) {
          tag
          hasTag
        }
      }
    }
  }
  paymentMethods {
    id
    name
  }
}

Étape 3.3 : Logique (src/run.js)


const NO_CHANGES = { operations: [] };

export function run(input) {
  const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0];
  const isB2B = tagCheck?.hasTag === true;
  if (!isB2B) return NO_CHANGES;

  const codMethod = input.paymentMethods.find((pm) =>
    pm.name.toLowerCase().includes("cash on delivery")
  );
  if (!codMethod) return NO_CHANGES;

  return {
    operations: [{ hide: { paymentMethodId: codMethod.id } }],
  };
}
const NO_CHANGES = { operations: [] };

export function run(input) {
  const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0];
  const isB2B = tagCheck?.hasTag === true;
  if (!isB2B) return NO_CHANGES;

  const codMethod = input.paymentMethods.find((pm) =>
    pm.name.toLowerCase().includes("cash on delivery")
  );
  if (!codMethod) return NO_CHANGES;

  return {
    operations: [{ hide: { paymentMethodId: codMethod.id } }],
  };
}

Étape 3.4 : Activer

Les Payment Customizations ont également une interface d'administration dans Settings → Payments → Customizations. Même processus que pour la livraison — sélectionnez votre Function, enregistrez, terminé.

Puisque vous lisez ceci — Un mot sur le post-achat

Une mise au point rapide puisque vous êtes sur le blog de Revize. Revize gère ce que les Functions ne peuvent pas toucher — une fois la commande passée, les clients veulent ajouter un article, modifier une taille, corriger l'adresse de livraison ou appliquer un code promo oublié. Les Functions interviennent lors du paiement. Revize intervient après. Les Functions déterminent ce qui est autorisé dans le panier ; Revize offre à vos clients et à votre équipe de support la possibilité de modifier la commande a posteriori sans passer par un cycle d'annulation et de recréation. C'est capital pour deux types de boutiques : celles qui ont un volume de commandes tel que l'édition manuelle devient impossible (les opérateurs Plus, par définition, mais aussi les boutiques Advanced à fort trafic), et celles dont l'image de marque repose sur l'expérience client — où un e-mail indiquant « désolé, nous ne pouvons pas modifier cela » détruit la fidélisation.

Si votre plan de migration couvre Scripts → Functions mais que vous n'avez pas encore résolu la gestion des modifications post-achat, vous vous heurterez au prochain obstacle technique d'ici trois semaines. Le guide de gestion des commandes que nous venons de publier détaille l'ensemble de la stratégie post-paiement.

Retour à la migration.

Stratégie de test : La méthode du tag client

Les Functions ne possèdent pas de « mode brouillon » activable dans l'admin. La bonne pratique professionnelle consiste à conditionner la nouvelle Function à la présence d'un tag client, à exécuter l'ancien Script et la nouvelle Function en parallèle, à vérifier qu'ils produisent des résultats identiques pour les utilisateurs taggués, puis à effectuer la bascule complète.

Étape 1 : Tagger vos utilisateurs de test

Dans la section Customers, ajoutez le tag FN-TESTER à deux ou trois comptes internes.

Étape 2 : Conditionner la Function à la présence du tag


// Au début de votre fonction run
let is_tester = input
    .cart()
    .buyer_identity()
    .and_then(|bi| bi.customer())
    .map(|c| c.has_any_tag())
    .unwrap_or(&false);

if !*is_tester {
    return Ok(default_result);  // Laisser l'exécution à l'ancien Script
}

// La logique de la nouvelle Function s'exécute uniquement pour les testeurs
// Au début de votre fonction run
let is_tester = input
    .cart()
    .buyer_identity()
    .and_then(|bi| bi.customer())
    .map(|c| c.has_any_tag())
    .unwrap_or(&false);

if !*is_tester {
    return Ok(default_result);  // Laisser l'exécution à l'ancien Script
}

// La logique de la nouvelle Function s'exécute uniquement pour les testeurs

Étape 3 : Ajouter hasAnyTag à votre requête d'entrée


cart {
  buyerIdentity {
    customer {
      hasAnyTag(tags: ["FN-TESTER"])
    }
  }
}
cart {
  buyerIdentity {
    customer {
      hasAnyTag(tags: ["FN-TESTER"])
    }
  }
}

Étape 4 : Vérifier dans le checkout

Connectez-vous avec un compte taggué, passez une commande de test, validez que la Function se déclenche. Connectez-vous avec un compte non taggué, validez que l'ancien Script s'exécute toujours. Après quelques jours sans anomalie, retirez la vérification du tag pour appliquer la Function à tous.

Étape 5 : Retirer l'ancien Script

Allez dans Apps → Script Editor → [Votre Script] → Unpublish. Une fois dépublié, la Function devient l'unique source de vérité.

Un flux de déploiement véritablement structuré

Ne déployez pas indéfiniment depuis la machine d'un développeur. Dès que vous avez migré un ou deux Scripts, configurez un véritable pipeline CI.

Le workflow minimal viable


# .github/workflows/deploy-functions.yml
name: Deploy Shopify Functions
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - uses: dtolnay/rust-toolchain@stable
        with: { targets: wasm32-wasip1 }
      - run: npm install -g @shopify/cli@latest
      - run: shopify app deploy --force
        env:
          SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}
# .github/workflows/deploy-functions.yml
name: Deploy Shopify Functions
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - uses: dtolnay/rust-toolchain@stable
        with: { targets: wasm32-wasip1 }
      - run: npm install -g @shopify/cli@latest
      - run: shopify app deploy --force
        env:
          SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}

Générez le token partenaire depuis votre tableau de bord Partner dans Settings → Tokens. Désormais, chaque fusion vers main déploie vos Functions. Fini les discussions Slack pour savoir qui a déployé la dernière version.

Gestion des versions et retour arrière

La commande shopify app deploy crée un instantané versionné. Pour revenir en arrière :


shopify app versions list
shopify app release --version <previous-version-id

shopify app versions list
shopify app release --version <previous-version-id

Comparé aux Scripts — où le retour arrière consistait à retrouver l'ancien code manuellement pour le recoller — c'est le jour et la nuit.



Shopify Functions deployment pipeline across local staging and production environments

Les erreurs les plus fréquentes commises par les équipes

Après avoir accompagné de nombreux marchands Plus dans cette migration l'an dernier, les cinq mêmes erreurs reviennent systématiquement.

1. Traiter les Functions comme un simple portage de Script individuel. Ce n'est pas le cas. Une seule Function peut remplacer trois Scripts grâce à une logique de branchement plus saine. Analysez vos Scripts de manière globale avant de réécrire le code.

2. Oublier les habilitations d'API (scopes d'accès). Beaucoup de Functions nécessitent read_customers, read_orders ou write_discounts. Ajoutez-les dans shopify.app.toml sous la clé scopes et autorisez à nouveau l'application, sans quoi votre requête d'entrée renverra des données nulles.

3. Lancer les Functions pour tous les clients sans test de parité préalable. Même si votre code vous semble correct, des cas particuliers (paniers vides, cartes-cadeaux, avoirs, brouillons de commandes B2B) feront émerger des anomalies. Un déploiement progressif par tag vous évite des pannes bloquantes en production.

4. Faire l'impasse sur le Customizations Report. C'est la cartographie la plus précise de vos personnalisations actives. Ne vous fiez pas à votre mémoire, fiez-vous au rapport.

5. Hardcoder les identifiants de collections et les tags clients. Utilisez la configuration de Function via les metafields si vous avez besoin de valeurs ajustables par les marchands. La CLI permet de générer des configurations basées sur les metafields — consultez la documentation de Shopify à ce sujet.

Feuille de route de migration pour les 75 prochains jours

Un calendrier réaliste semaine par semaine pour aborder le 30 juin sereinement.


Semaines

Action

Semaine 1 (cette semaine)

Générez le Customizations Report. Listez chaque Script. Choisissez : Function, application publique ou suppression.

Semaines 2 et 3

Configurez l'environnement de dev local. Créez la première Function. Migrez le Script le plus simple (généralement une règle de masquage de paiement).

Semaines 4 à 6

Migrez les Scripts liés aux remises. Ce sont les plus longs à traiter en raison de la richesse de l'API Discounts. Testez minutieusement par tag.

Semaines 7 et 8

Migrez les Scripts liés à la livraison. Activez les Delivery Customizations dans l'admin.

Semaines 9 et 10

Configurez le pipeline CI. Automatisez les déploiements hors des machines locales des développeurs.

Semaine 11 (mi-juin)

Validation finale de la parité. Désactivez tous les Scripts. Faites tourner la boutique uniquement avec les Functions pendant deux semaines.

30 juin

Date de fin d'exécution. Aucune interruption de service car vous avez terminé en avance.

En commençant cette semaine, vous conservez une marge de sécurité. En commençant en juin, vous n'en aurez pas.



Week-by-week migration roadmap from Shopify Scripts to Functions

Foire Aux Questions

Dois-je posséder un forfait Shopify Plus pour utiliser les Functions ?

Les Functions personnalisées nécessitent Shopify Plus, mais les Functions issues d'applications publiques fonctionnent sur tous les forfaits. Si vous n'êtes pas sur Plus, deux solutions s'offrent à vous : installer une application publique depuis le Shopify App Store qui intègre la Function requise, ou passer à Plus pour concevoir vos propres Functions personnalisées. La plupart des marchands d'envergure utilisant des Scripts disposent déjà de Plus.

Puis-je écrire des Functions en TypeScript ?

Oui — TypeScript est pleinement pris en charge et la CLI configure le projet pour vous. Lorsque vous lancez shopify app generate extension et optez pour « JavaScript », le projet généré inclut les déclarations de types de import("../generated/api"). Vous pouvez renommer vos fichiers en .ts et ajouter un fichier tsconfig.json. Le build final (WASM) sera identique.

Quelle est la rapidité des Functions par rapport aux Scripts ?

Les Functions s'exécutent généralement en moins de 5 ms — soit beaucoup plus rapidement que les Scripts Ruby. Étant compilées en WebAssembly et exécutées dans un environnement optimisé, un budget d'exécution de 5 ms est imposé par Shopify. Si votre Function le dépasse, l'opération est abandonnée. En pratique, une Function bien conçue requiert 1 à 2 ms.

Une Function peut-elle interroger une API externe ?

Non — les Functions ne peuvent effectuer aucun appel réseau. Ce sont des briques de calcul pur : elles reçoivent des données de panier en entrée et renvoient des opérations en sortie. Si vous devez exploiter des données externes (CRM, stock en temps réel), stockez-les préalablement dans des metafields, ou utilisez un autre mécanisme (App Proxy, webhooks, Cart Transform avec appel back-end).

Quelle est la différence entre Cart Transform et les Discounts ?

Les Discounts appliquent des réductions tarifaires ; Cart Transform modifie le contenu même du panier. Utilisez l'API Discounts pour appliquer un code, une remise de 10 %, la livraison gratuite ou du type X achetés Y offerts. Utilisez Cart Transform pour regrouper deux produits sous une ligne unique, ou décomposer une variante en plusieurs éléments. Séparez bien ces deux fonctions lors de votre migration.

Comment tester une Function en local sans boutique de développement ?

Vous pouvez exécuter des tests unitaires avec cargo test (Rust) ou npm test (JS), mais le test d'intégration complet exige une boutique de dev. La CLI propose la commande shopify app function run pour exécuter votre Function face à un fichier d'entrée simulé. Pour valider l'expérience dans le checkout réel, une boutique est incontournable.

Puis-je avoir plusieurs Functions du même type actives simultanément ?

Oui — Shopify autorise plusieurs Functions par cible, exécutées selon un ordre déterminé. Pour les remises, la priorité dépend des règles de cumul de Shopify. Pour les personnalisations de livraison et de paiement, les outputs s'enchaînent. Utiliser une seule Function par cible simplifie grandement la maintenance.

Qu'advient-il de mon Script une fois la Function déployée ?

Les deux s'exécutent en parallèle jusqu'à ce que vous archiviez le Script dans Apps → Script Editor. Ce fonctionnement est voulu pour vous permettre de réaliser des phases de tests parallèles en production. Une fois les tests concluants, désactivez le Script. Au-delà du 30 juin 2026, de toute façon, aucun Script ne fonctionnera plus.

Cette migration aura-t-elle un impact sur mon SEO ou mon thème ?

Non — les Functions s'exécutent côté serveur lors du passage en caisse et n'interfèrent jamais avec votre thème ou vos pages produits. Elles ciblent uniquement les réductions, les choix de livraison et les paiements à l'étape finale. Votre site d'e-commerce et votre référencement ne subissent aucun changement.

Comment migrer un Script qui exploite Input.line_items avec des propriétés personnalisées ?

Ces propriétés personnalisées sont accessibles via le champ attribute des lignes de panier de la requête GraphQL. Ajoutez attribute(key: "votre-clef") { value } au sein de la sélection de lignes. La Function lira cette valeur de la même manière que vos Scripts Ruby lisaient les attributs d'articles.

Qu'en est-il des données analytiques et des tags de commande ? Les Functions peuvent-elles en écrire ?

Les Functions ne peuvent pas appliquer de tags aux commandes ni déclencher de webhooks — elles gèrent exclusivement le panier actif. Pour du taggage ou d'autres flux en aval, utilisez Shopify Flow déclenché par l'événement de création de commande. Associez par exemple une Function pour appliquer la remise et un workflow Flow pour tagguer la commande finale.

Existe-t-il une application publique prête à l'emploi si je ne souhaite pas développer de Function personnalisée ?

Oui — le Shopify App Store propose des dizaines d'applications qui encapsulent les Functions pour les cas d'usage récurrents. Cherchez des termes comme "discount function" ou "payment customization". Pour des stratégies classiques (remise sur quantité, masquer des paiements par tag, livraison gratuite dès X $), cela peut vous éviter plusieurs jours de développement. Réservez le sur-mesure aux règles métiers uniques.

Que se passe-t-il si je dépasse la date limite du 30 juin ?

Le Script s'arrête net — aucun délai de grâce, aucune prolongation ne sera accordée. Tout mécanisme géré par le Script (réduction, frais de port modifiés, mode de paiement masqué) reprendra son comportement par défaut le 1er juillet à minuit UTC. Prévoyez une mise en ligne finale bien avant cette date.

Puis-je supprimer définitivement l'application Script Editor ?

Vous pourrez la désinstaller après le 30 juin 2026, sachant que Shopify devrait la retirer automatiquement. Une fois l'échéance passée, cet éditeur n'aura plus d'utilité. Si votre migration est validée en amont, vous pouvez la supprimer dès maintenant ; vos Functions s'exécutent de manière autonome.

Actions prioritaires pour cette semaine

Ne remettez pas à plus tard. Initiez la transition en accomplissant ces quatre tâches d'ici sept jours.

1. Exportez le Customizations Report. Rendez-vous sur Settings → Checkout → Customizations Report et téléchargez-le. Ce document constitue votre cahier des charges de migration.

2. Installez votre environnement de développement. Mettez en place Node 18+, la CLI Shopify et Rust (si requis). Vérifiez le bon fonctionnement de shopify version. Durée estimée : 30 minutes.

3. Déployez une micro-Function sur une boutique de développement. Sélectionnez le Script le moins complexe (par exemple, le masquage d'une option de paiement). Réalisez sa migration de bout en bout pour éprouver votre pipeline d'outils, même si elle n'est pas déployée immédiatement.

4. Planifiez des plages de travail dans les huit prochaines semaines. Une migration réussie demande du temps dédié. Réservez des créneaux de travail récurrents (par exemple deux après-midis par semaine) et traitez ces phases comme des jalons de livraison majeurs.

Les retours d'expérience montrent souvent le même schéma : deux semaines de latence, trois semaines de développement et une semaine d'ajustements. Cela représente un total de six semaines. Il vous en reste dix. Profitez de cette avance pour soigner vos revues de code et vos étapes de recette.

Une fois votre logique de paiement convertie, l'étape suivante pour la majorité des équipes consiste à optimiser les processus post-achat (corrections d'adresses, ajouts de remises après commande). Si vous intégrez cela à votre feuille de route, sachez que l'application Revize est disponible sur le Shopify App Store et opère aux côtés des nouvelles Functions que vous concevez.

Ressources


Articles connexes


Nous sommes le 16 avril 2026. Hier — le 15 avril — Shopify a définitivement verrouillé le Script Editor. Vous ne pouvez plus créer ni publier de nouveau Script. L'arrêt de l'exécution intervient dans 75 jours, le 30 juin 2026.

Si vous êtes un développeur Shopify Plus — ou l'agence qui gère une boutique Plus — et que vous avez repoussé cette migration au « prochain sprint » ces douze derniers mois, vous avez un problème. Pas un problème cosmétique. Un problème du type « votre tunnel de paiement plante à minuit le 1er juillet ». La plupart des boutiques Plus ont accumulé entre 5 et 20 Scripts au fil des ans, chacun gérant silencieusement une règle de réduction, un masquage de livraison ou une passerelle de paiement que personne ne se souvient avoir codée.

Ce guide est le manuel technique de migration que nous aurions aimé avoir en janvier. Il traite du code réel, pas seulement de la stratégie. À la fin de votre lecture, vous saurez comment échafauder une Function avec la Shopify CLI, écrire la logique en Rust ou JavaScript pour les réductions, les personnalisations de livraison et de paiement, la tester en toute sécurité sur un sous-ensemble de clients ciblé, et la déployer en production sans perturber votre checkout actuel.

Débarrassons votre boutique des Scripts et installons-y les Functions.



Developer migrating Shopify Scripts to Shopify Functions modules

Réponse rapide : Scripts → Functions en 60 secondes

La migration en un paragraphe : Les Shopify Scripts (code Ruby dans le Script Editor, réservés à Plus) sont remplacés par les Shopify Functions (modules WebAssembly écrits en Rust ou JavaScript, disponibles pour tous les forfaits). Vous générez une Function avec shopify app generate extension, écrivez une requête run.graphql qui récupère les données de panier nécessaires, écrivez un fichier run.rs ou run.js qui renvoie les opérations (réductions, modes de livraison masqués, etc.), puis déployez avec shopify app deploy et l'activez via l'Admin ou une mutation GraphQL. Les Functions s'exécutent sous forme de WASM compilé avec une latence inférieure à 5 ms, fonctionnent sur tous les forfaits et constituent l'unique voie de personnalisation prise en charge par Shopify à l'avenir.

Ce qui change réellement le 30 juin

Avant de toucher au code, actons les dates. Il y en a deux, et toutes deux sont cruciales.


Date

Événement

Action requise

15 avril 2026 (passé)

Script Editor en lecture seule. Aucun nouveau Script. Aucune modification des Scripts existants.

Les Scripts existants s'exécutent encore. Migrez maintenant ou figez votre logique.

30 juin 2026

Tous les Shopify Scripts cessent de s'exécuter. Définitivement.

Votre Function de remplacement doit être active avant cette date.

La migration est binaire. Soit votre Function est déployée d'ici le 30 juin et votre checkout continue de fonctionner, soit elle ne l'est pas — et chaque panier concerné appliquera par défaut les tarifs standards, les frais de livraison de base et l'ensemble des modes de paiement activés. Pas de demi-mesure. Le Script s'exécute ou ne s'exécute pas, et après le 30 juin, il ne s'exécutera plus.

Astuce : Allez dans Settings → Checkout → Customizations Report dans votre admin Shopify. Vous y trouverez la liste de chaque Script actif sur votre boutique, son rôle et le type de Function de remplacement recommandé. Commencez par là.

Functions vs Scripts : Ce qui a réellement changé


Critère

Shopify Scripts (obsolète)

Shopify Functions (remplacement)

Langage

Ruby DSL (propre à Shopify)

Rust, JavaScript, TypeScript

Environnement d'exécution

Ruby sandboxé sur l'infrastructure Shopify

WebAssembly (WASM) — exécution < 5ms

Forfaits compatibles

Plus uniquement

Tous les forfaits (les apps personnalisées nécessitent Plus ; les apps publiques sont ouvertes)

Éditeur

Script Editor intégré à l'admin

IDE local + Shopify CLI

Gestion des versions

Aucune — modifications en direct

Compatible Git — contrôle de version complet

Tests

Manuels dans le checkout

Développement local avec shopify app dev, liens d'aperçu

Déploiement

Clic sur "Enregistrer" dans l'admin

shopify app deploy depuis le terminal

Cibles

Articles du panier, expédition, paiements

Discounts, Cart Transform, Validation, Delivery Customization, Payment Customization, Order Routing, Fulfillment Constraints, et plus

Le changement d'architecture est fondamental. Les Scripts consistaient à « bricoler du Ruby dans une zone de texte ». Les Functions consistent à « écrire une véritable application, la versionner, la tester localement, la déployer via un pipeline CI digne de ce nom ». La courbe d'apprentissage est plus raide. C'est aussi la dernière migration que vous aurez à faire pour la logique de checkout dans un avenir prévisible — les Functions représentent l'engagement à long terme de Shopify, contrairement aux Scripts qui se sont avérés être une solution temporaire.

Associer vos Scripts au bon type de Function

Chaque Script actuel correspond à exactement une API de Function. Voici la table de correspondance à garder sous les yeux.


Ancien type de Script

Rôle

Nouvelle API de Function

Cible (Target)

Line Item Script

Appliquer des remises à des produits / clients / conditions de panier spécifiques

Cart & Checkout Discounts API

cart.lines.discounts.generate.run

Shipping Script (remise)

Livraison gratuite ou réduite selon des règles de panier

Cart & Checkout Discounts API

cart.delivery-options.discounts.generate.run

Shipping Script (masquer / renommer / réordonner)

Masquer un tarif au-dessus de X $, renommer "Standard" en "Gratuit dès 50 $"

Delivery Customization API

cart.delivery-options.transform.run

Payment Script

Masquer PayPal pour le B2B, masquer le paiement à la livraison au-dessus de 500 $, réordonner les modes de paiement

Payment Customization API

cart.payment-methods.transform.run

Script de modification de panier (rare)

Créer des lots de produits, remplacer des articles

Cart Transform API

cart.transform.run

Script de blocage du checkout

Refuser le panier si la combinaison de SKU est non valide

Cart & Checkout Validation API

cart.validations.generate.run

Si vous avez dix Scripts, vous développerez probablement entre trois et cinq Functions — plusieurs Scripts se résument souvent à une seule Function dotée d'une logique de branchement plus propre.



Shopify Functions unifying discounts, delivery, and payment customizations

Prérequis : Configurer votre environnement de développement local

Avant de générer une Function, vous devez installer trois outils en local. Exécutez ces vérifications dans votre terminal.

1. Node.js 18+


node --version
# Doit être >= 18.0.0

Si la version est plus ancienne, installez-la via nvm ou téléchargez-la sur nodejs.org.

2. Shopify CLI 3+


npm install -g @shopify/cli@latest
shopify version
# Doit afficher 3.x ou plus

3. Toolchain Rust (uniquement si vous écrivez vos Functions en Rust)


curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup target add wasm32-wasip1
cargo --version

Les Functions en JavaScript n'ont pas besoin de Rust. Choisissez un langage pour votre équipe et tenez-vous-y — mélanger les deux ajoute des coûts de maintenance.

4. Une boutique de développement

Connectez-vous à votre tableau de bord Partner et créez une nouvelle boutique de développement, ou utilisez-en une existante. Vous y déploierez vos Functions avant de les passer en production.

Générer votre première Function

La CLI s'occupe de l'essentiel du code de base. Dans n'importe quel répertoire :


# Créer une nouvelle application Shopify (ignorez si vous en avez déjà une)
shopify app init my-checkout-functions
cd my-checkout-functions

# Générer une extension de type Function
shopify app generate extension

La CLI vous guide à travers différentes questions. Pour une Function de réduction, vous choisiriez :

  • Type : Function

  • Modèle : discount (ou cart_checkout_validation, delivery_customization, payment_customization, etc.)

  • Langage : Rust ou JavaScript

  • Nom : par exemple volume-discount-fn

Cela crée le répertoire extensions/volume-discount-fn/ contenant :


extensions/volume-discount-fn/
├── shopify.extension.toml      # Config de la Function cibles, build, version
├── src/
├── cart_lines_discounts_generate_run.graphql   # Requête d'entrée
└── cart_lines_discounts_generate_run.rs        # Logique de la Function
├── Cargo.toml                  # Dépendances Rust (Rust uniquement)
└── README.md

Les trois fichiers que vous modifierez en permanence sont le .toml (config), le .graphql (entrée) et le .rs / .js (logique). C'est tout.

Tutoriel 1 : Remplacer un Line Item Script (Remise sur volume)

Supposons que votre ancien Script appliquait une remise de 10 % sur le sous-total de la commande dès que le panier contenait au moins 5 articles d'une collection spécifique. Voici l'équivalent sous forme de Function.

Étape 1.1 : La configuration (shopify.extension.toml)


api_version = "2026-01"

[[extensions]]
name = "volume-discount-fn"
handle = "volume-discount-fn"
type = "function"

[[extensions.targeting]]
target = "cart.lines.discounts.generate.run"
input_query = "src/cart_lines_discounts_generate_run.graphql"
export = "cart_lines_discounts_generate_run"

[extensions.build]
command = "cargo build --target=wasm32-wasip1 --release"
path = "target/wasm32-wasip1/release/volume-discount-fn.wasm"
watch = ["src/**/*.rs"]

Étape 1.2 : La requête d'entrée (src/cart_lines_discounts_generate_run.graphql)


query Input {
  cart {
    lines {
      id
      quantity
      cost {
        subtotalAmount {
          amount
        }
      }
      merchandise {
        ... on ProductVariant {
          product {
            inAnyCollection(ids: ["gid://shopify/Collection/123456789"])
          }
        }
      }
    }
  }
  discount {
    discountClasses
  }
}

Astuce : Les Functions ne voient que les données que vous demandez. Limitez le GraphQL au strict minimum — chaque champ ignoré garantit une exécution plus rapide et moins coûteuse.

Étape 1.3 : La logique (src/cart_lines_discounts_generate_run.rs)


use super::schema;
use shopify_function::prelude::*;
use shopify_function::Result;

#[shopify_function]
fn cart_lines_discounts_generate_run(
    input: schema::cart_lines_discounts_generate_run::Input,
) -> Result<schema::CartLinesDiscountsGenerateRunResult> {
    // Arrêter si la classe de remise ne correspond pas
    let has_order_discount = input
        .discount()
        .discount_classes()
        .contains(&schema::DiscountClass::Order);

    if !has_order_discount {
        return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
    }

    // Sommer les quantités d'articles de la collection cible
    let qualifying_qty: i64 = input
        .cart()
        .lines()
        .iter()
        .filter(|line| {
            if let schema::Merchandise::ProductVariant(v) = line.merchandise() {
                *v.product().in_any_collection()
            } else {
                false
            }
        })
        .map(|line| *line.quantity())
        .sum();

    if qualifying_qty < 5 {
        return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
    }

    // Appliquer 10 % de réduction sur le sous-total de la commande
    Ok(schema::CartLinesDiscountsGenerateRunResult {
        operations: vec![schema::CartOperation::OrderDiscountsAdd(
            schema::OrderDiscountsAddOperation {
                selection_strategy: schema::OrderDiscountSelectionStrategy::First,
                candidates: vec![schema::OrderDiscountCandidate {
                    targets: vec![schema::OrderDiscountCandidateTarget::OrderSubtotal(
                        schema::OrderSubtotalTarget {
                            excluded_cart_line_ids: vec![],
                        },
                    )],
                    message: Some("Volume discount: 10% off".to_string()),
                    value: schema::OrderDiscountCandidateValue::Percentage(
                        schema::Percentage { value: Decimal(10.0) }
                    ),
                    conditions: None,
                    associated_discount_code: None,
                }],
            },
        )],
    })
}

Étape 1.4 : Tester, déployer, activer


# Développement local avec rechargement à chaud
shopify app dev

# Lorsque vous êtes prêt, déployez
shopify app deploy

# Dans le panneau GraphiQL qui s'ouvre (appuyez sur `g` dans le terminal de dev),
# créez la remise automatique qui utilise votre Function :
mutation {
  discountAutomaticAppCreate(
    automaticAppDiscount: {
      title: "Volume Discount (5+ collection items)"
      functionHandle: "volume-discount-fn"
      discountClasses: [ORDER]
      startsAt: "2026-04-16T00:00:00Z"
    }
  ) {
    automaticAppDiscount { discountId }
    userErrors { field message }
  }
}

C'est tout. La Function est active, versionnée et remplace définitivement l'ancien Script.

Tutoriel 2 : Remplacer un Shipping Script (Masquer un mode de livraison selon le montant du panier)

Un Script classique : « Masquer la livraison Express lorsque le sous-total du panier dépasse 500 $ pour éviter des frais d'envoi de nuit exorbitants sur de grosses commandes. » Voici la version Delivery Customization avec une Function.

Étape 2.1 : Générer l'extension


shopify app generate extension --template delivery_customization --name hide-express-fn

Étape 2.2 : Requête d'entrée (src/run.graphql)


query Input {
  cart {
    cost {
      subtotalAmount {
        amount
      }
    }
    deliveryGroups {
      deliveryOptions {
        handle
        title
      }
    }
  }
}

Étape 2.3 : Logique (src/run.js — variante JavaScript)


// @ts-check
/**
 * @typedef {import("../generated/api").RunInput} RunInput
 * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult
 */

const NO_CHANGES = { operations: [] };
const THRESHOLD = 500.0;
const HIDE_TITLES = ["Express", "Overnight"];

/**
 * @param {RunInput} input
 * @returns {FunctionRunResult}
 */
export function run(input) {
  const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount);
  if (subtotal < THRESHOLD) return NO_CHANGES;

  const operations = input.cart.deliveryGroups.flatMap((group) =>
    group.deliveryOptions
      .filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t)))
      .map((opt) => ({
        hide: { deliveryOptionHandle: opt.handle },
      }))
  );

  return { operations };
}

Étape 2.4 : Activer via l'Admin (sans GraphQL)

Les Delivery Customizations disposent d'une interface d'administration intégrée. Après l'exécution de shopify app deploy :

  1. Allez dans Settings → Shipping and delivery

  2. Faites défiler jusqu'à la section Customizations tout en bas

  3. Cliquez sur Add customization → sélectionnez votre Function

  4. Enregistrez

La règle de masquage est active en production. Aucune mutation requise.



Shopify delivery customization Function hiding shipping option at checkout

Tutoriel 3 : Remplacer un Payment Script (Masquer le paiement à la livraison pour le B2B)

Ancien Script : « Masquer le paiement à la livraison (COD) pour tout client doté du tag 'B2B'. » Voici la version Payment Customization.

Étape 3.1 : Générer l'extension


shopify app generate extension --template payment_customization --name hide-cod-b2b-fn

Étape 3.2 : Requête d'entrée


query Input {
  cart {
    buyerIdentity {
      customer {
        hasTags(tags: [{ tag: "B2B" }]) {
          tag
          hasTag
        }
      }
    }
  }
  paymentMethods {
    id
    name
  }
}

Étape 3.3 : Logique (src/run.js)


const NO_CHANGES = { operations: [] };

export function run(input) {
  const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0];
  const isB2B = tagCheck?.hasTag === true;
  if (!isB2B) return NO_CHANGES;

  const codMethod = input.paymentMethods.find((pm) =>
    pm.name.toLowerCase().includes("cash on delivery")
  );
  if (!codMethod) return NO_CHANGES;

  return {
    operations: [{ hide: { paymentMethodId: codMethod.id } }],
  };
}

Étape 3.4 : Activer

Les Payment Customizations ont également une interface d'administration dans Settings → Payments → Customizations. Même processus que pour la livraison — sélectionnez votre Function, enregistrez, terminé.

Puisque vous lisez ceci — Un mot sur le post-achat

Une mise au point rapide puisque vous êtes sur le blog de Revize. Revize gère ce que les Functions ne peuvent pas toucher — une fois la commande passée, les clients veulent ajouter un article, modifier une taille, corriger l'adresse de livraison ou appliquer un code promo oublié. Les Functions interviennent lors du paiement. Revize intervient après. Les Functions déterminent ce qui est autorisé dans le panier ; Revize offre à vos clients et à votre équipe de support la possibilité de modifier la commande a posteriori sans passer par un cycle d'annulation et de recréation. C'est capital pour deux types de boutiques : celles qui ont un volume de commandes tel que l'édition manuelle devient impossible (les opérateurs Plus, par définition, mais aussi les boutiques Advanced à fort trafic), et celles dont l'image de marque repose sur l'expérience client — où un e-mail indiquant « désolé, nous ne pouvons pas modifier cela » détruit la fidélisation.

Si votre plan de migration couvre Scripts → Functions mais que vous n'avez pas encore résolu la gestion des modifications post-achat, vous vous heurterez au prochain obstacle technique d'ici trois semaines. Le guide de gestion des commandes que nous venons de publier détaille l'ensemble de la stratégie post-paiement.

Retour à la migration.

Stratégie de test : La méthode du tag client

Les Functions ne possèdent pas de « mode brouillon » activable dans l'admin. La bonne pratique professionnelle consiste à conditionner la nouvelle Function à la présence d'un tag client, à exécuter l'ancien Script et la nouvelle Function en parallèle, à vérifier qu'ils produisent des résultats identiques pour les utilisateurs taggués, puis à effectuer la bascule complète.

Étape 1 : Tagger vos utilisateurs de test

Dans la section Customers, ajoutez le tag FN-TESTER à deux ou trois comptes internes.

Étape 2 : Conditionner la Function à la présence du tag


// Au début de votre fonction run
let is_tester = input
    .cart()
    .buyer_identity()
    .and_then(|bi| bi.customer())
    .map(|c| c.has_any_tag())
    .unwrap_or(&false);

if !*is_tester {
    return Ok(default_result);  // Laisser l'exécution à l'ancien Script
}

// La logique de la nouvelle Function s'exécute uniquement pour les testeurs

Étape 3 : Ajouter hasAnyTag à votre requête d'entrée


cart {
  buyerIdentity {
    customer {
      hasAnyTag(tags: ["FN-TESTER"])
    }
  }
}

Étape 4 : Vérifier dans le checkout

Connectez-vous avec un compte taggué, passez une commande de test, validez que la Function se déclenche. Connectez-vous avec un compte non taggué, validez que l'ancien Script s'exécute toujours. Après quelques jours sans anomalie, retirez la vérification du tag pour appliquer la Function à tous.

Étape 5 : Retirer l'ancien Script

Allez dans Apps → Script Editor → [Votre Script] → Unpublish. Une fois dépublié, la Function devient l'unique source de vérité.

Un flux de déploiement véritablement structuré

Ne déployez pas indéfiniment depuis la machine d'un développeur. Dès que vous avez migré un ou deux Scripts, configurez un véritable pipeline CI.

Le workflow minimal viable


# .github/workflows/deploy-functions.yml
name: Deploy Shopify Functions
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - uses: dtolnay/rust-toolchain@stable
        with: { targets: wasm32-wasip1 }
      - run: npm install -g @shopify/cli@latest
      - run: shopify app deploy --force
        env:
          SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}

Générez le token partenaire depuis votre tableau de bord Partner dans Settings → Tokens. Désormais, chaque fusion vers main déploie vos Functions. Fini les discussions Slack pour savoir qui a déployé la dernière version.

Gestion des versions et retour arrière

La commande shopify app deploy crée un instantané versionné. Pour revenir en arrière :


shopify app versions list
shopify app release --version <previous-version-id

Comparé aux Scripts — où le retour arrière consistait à retrouver l'ancien code manuellement pour le recoller — c'est le jour et la nuit.



Shopify Functions deployment pipeline across local staging and production environments

Les erreurs les plus fréquentes commises par les équipes

Après avoir accompagné de nombreux marchands Plus dans cette migration l'an dernier, les cinq mêmes erreurs reviennent systématiquement.

1. Traiter les Functions comme un simple portage de Script individuel. Ce n'est pas le cas. Une seule Function peut remplacer trois Scripts grâce à une logique de branchement plus saine. Analysez vos Scripts de manière globale avant de réécrire le code.

2. Oublier les habilitations d'API (scopes d'accès). Beaucoup de Functions nécessitent read_customers, read_orders ou write_discounts. Ajoutez-les dans shopify.app.toml sous la clé scopes et autorisez à nouveau l'application, sans quoi votre requête d'entrée renverra des données nulles.

3. Lancer les Functions pour tous les clients sans test de parité préalable. Même si votre code vous semble correct, des cas particuliers (paniers vides, cartes-cadeaux, avoirs, brouillons de commandes B2B) feront émerger des anomalies. Un déploiement progressif par tag vous évite des pannes bloquantes en production.

4. Faire l'impasse sur le Customizations Report. C'est la cartographie la plus précise de vos personnalisations actives. Ne vous fiez pas à votre mémoire, fiez-vous au rapport.

5. Hardcoder les identifiants de collections et les tags clients. Utilisez la configuration de Function via les metafields si vous avez besoin de valeurs ajustables par les marchands. La CLI permet de générer des configurations basées sur les metafields — consultez la documentation de Shopify à ce sujet.

Feuille de route de migration pour les 75 prochains jours

Un calendrier réaliste semaine par semaine pour aborder le 30 juin sereinement.


Semaines

Action

Semaine 1 (cette semaine)

Générez le Customizations Report. Listez chaque Script. Choisissez : Function, application publique ou suppression.

Semaines 2 et 3

Configurez l'environnement de dev local. Créez la première Function. Migrez le Script le plus simple (généralement une règle de masquage de paiement).

Semaines 4 à 6

Migrez les Scripts liés aux remises. Ce sont les plus longs à traiter en raison de la richesse de l'API Discounts. Testez minutieusement par tag.

Semaines 7 et 8

Migrez les Scripts liés à la livraison. Activez les Delivery Customizations dans l'admin.

Semaines 9 et 10

Configurez le pipeline CI. Automatisez les déploiements hors des machines locales des développeurs.

Semaine 11 (mi-juin)

Validation finale de la parité. Désactivez tous les Scripts. Faites tourner la boutique uniquement avec les Functions pendant deux semaines.

30 juin

Date de fin d'exécution. Aucune interruption de service car vous avez terminé en avance.

En commençant cette semaine, vous conservez une marge de sécurité. En commençant en juin, vous n'en aurez pas.



Week-by-week migration roadmap from Shopify Scripts to Functions

Foire Aux Questions

Dois-je posséder un forfait Shopify Plus pour utiliser les Functions ?

Les Functions personnalisées nécessitent Shopify Plus, mais les Functions issues d'applications publiques fonctionnent sur tous les forfaits. Si vous n'êtes pas sur Plus, deux solutions s'offrent à vous : installer une application publique depuis le Shopify App Store qui intègre la Function requise, ou passer à Plus pour concevoir vos propres Functions personnalisées. La plupart des marchands d'envergure utilisant des Scripts disposent déjà de Plus.

Puis-je écrire des Functions en TypeScript ?

Oui — TypeScript est pleinement pris en charge et la CLI configure le projet pour vous. Lorsque vous lancez shopify app generate extension et optez pour « JavaScript », le projet généré inclut les déclarations de types de import("../generated/api"). Vous pouvez renommer vos fichiers en .ts et ajouter un fichier tsconfig.json. Le build final (WASM) sera identique.

Quelle est la rapidité des Functions par rapport aux Scripts ?

Les Functions s'exécutent généralement en moins de 5 ms — soit beaucoup plus rapidement que les Scripts Ruby. Étant compilées en WebAssembly et exécutées dans un environnement optimisé, un budget d'exécution de 5 ms est imposé par Shopify. Si votre Function le dépasse, l'opération est abandonnée. En pratique, une Function bien conçue requiert 1 à 2 ms.

Une Function peut-elle interroger une API externe ?

Non — les Functions ne peuvent effectuer aucun appel réseau. Ce sont des briques de calcul pur : elles reçoivent des données de panier en entrée et renvoient des opérations en sortie. Si vous devez exploiter des données externes (CRM, stock en temps réel), stockez-les préalablement dans des metafields, ou utilisez un autre mécanisme (App Proxy, webhooks, Cart Transform avec appel back-end).

Quelle est la différence entre Cart Transform et les Discounts ?

Les Discounts appliquent des réductions tarifaires ; Cart Transform modifie le contenu même du panier. Utilisez l'API Discounts pour appliquer un code, une remise de 10 %, la livraison gratuite ou du type X achetés Y offerts. Utilisez Cart Transform pour regrouper deux produits sous une ligne unique, ou décomposer une variante en plusieurs éléments. Séparez bien ces deux fonctions lors de votre migration.

Comment tester une Function en local sans boutique de développement ?

Vous pouvez exécuter des tests unitaires avec cargo test (Rust) ou npm test (JS), mais le test d'intégration complet exige une boutique de dev. La CLI propose la commande shopify app function run pour exécuter votre Function face à un fichier d'entrée simulé. Pour valider l'expérience dans le checkout réel, une boutique est incontournable.

Puis-je avoir plusieurs Functions du même type actives simultanément ?

Oui — Shopify autorise plusieurs Functions par cible, exécutées selon un ordre déterminé. Pour les remises, la priorité dépend des règles de cumul de Shopify. Pour les personnalisations de livraison et de paiement, les outputs s'enchaînent. Utiliser une seule Function par cible simplifie grandement la maintenance.

Qu'advient-il de mon Script une fois la Function déployée ?

Les deux s'exécutent en parallèle jusqu'à ce que vous archiviez le Script dans Apps → Script Editor. Ce fonctionnement est voulu pour vous permettre de réaliser des phases de tests parallèles en production. Une fois les tests concluants, désactivez le Script. Au-delà du 30 juin 2026, de toute façon, aucun Script ne fonctionnera plus.

Cette migration aura-t-elle un impact sur mon SEO ou mon thème ?

Non — les Functions s'exécutent côté serveur lors du passage en caisse et n'interfèrent jamais avec votre thème ou vos pages produits. Elles ciblent uniquement les réductions, les choix de livraison et les paiements à l'étape finale. Votre site d'e-commerce et votre référencement ne subissent aucun changement.

Comment migrer un Script qui exploite Input.line_items avec des propriétés personnalisées ?

Ces propriétés personnalisées sont accessibles via le champ attribute des lignes de panier de la requête GraphQL. Ajoutez attribute(key: "votre-clef") { value } au sein de la sélection de lignes. La Function lira cette valeur de la même manière que vos Scripts Ruby lisaient les attributs d'articles.

Qu'en est-il des données analytiques et des tags de commande ? Les Functions peuvent-elles en écrire ?

Les Functions ne peuvent pas appliquer de tags aux commandes ni déclencher de webhooks — elles gèrent exclusivement le panier actif. Pour du taggage ou d'autres flux en aval, utilisez Shopify Flow déclenché par l'événement de création de commande. Associez par exemple une Function pour appliquer la remise et un workflow Flow pour tagguer la commande finale.

Existe-t-il une application publique prête à l'emploi si je ne souhaite pas développer de Function personnalisée ?

Oui — le Shopify App Store propose des dizaines d'applications qui encapsulent les Functions pour les cas d'usage récurrents. Cherchez des termes comme "discount function" ou "payment customization". Pour des stratégies classiques (remise sur quantité, masquer des paiements par tag, livraison gratuite dès X $), cela peut vous éviter plusieurs jours de développement. Réservez le sur-mesure aux règles métiers uniques.

Que se passe-t-il si je dépasse la date limite du 30 juin ?

Le Script s'arrête net — aucun délai de grâce, aucune prolongation ne sera accordée. Tout mécanisme géré par le Script (réduction, frais de port modifiés, mode de paiement masqué) reprendra son comportement par défaut le 1er juillet à minuit UTC. Prévoyez une mise en ligne finale bien avant cette date.

Puis-je supprimer définitivement l'application Script Editor ?

Vous pourrez la désinstaller après le 30 juin 2026, sachant que Shopify devrait la retirer automatiquement. Une fois l'échéance passée, cet éditeur n'aura plus d'utilité. Si votre migration est validée en amont, vous pouvez la supprimer dès maintenant ; vos Functions s'exécutent de manière autonome.

Actions prioritaires pour cette semaine

Ne remettez pas à plus tard. Initiez la transition en accomplissant ces quatre tâches d'ici sept jours.

1. Exportez le Customizations Report. Rendez-vous sur Settings → Checkout → Customizations Report et téléchargez-le. Ce document constitue votre cahier des charges de migration.

2. Installez votre environnement de développement. Mettez en place Node 18+, la CLI Shopify et Rust (si requis). Vérifiez le bon fonctionnement de shopify version. Durée estimée : 30 minutes.

3. Déployez une micro-Function sur une boutique de développement. Sélectionnez le Script le moins complexe (par exemple, le masquage d'une option de paiement). Réalisez sa migration de bout en bout pour éprouver votre pipeline d'outils, même si elle n'est pas déployée immédiatement.

4. Planifiez des plages de travail dans les huit prochaines semaines. Une migration réussie demande du temps dédié. Réservez des créneaux de travail récurrents (par exemple deux après-midis par semaine) et traitez ces phases comme des jalons de livraison majeurs.

Les retours d'expérience montrent souvent le même schéma : deux semaines de latence, trois semaines de développement et une semaine d'ajustements. Cela représente un total de six semaines. Il vous en reste dix. Profitez de cette avance pour soigner vos revues de code et vos étapes de recette.

Une fois votre logique de paiement convertie, l'étape suivante pour la majorité des équipes consiste à optimiser les processus post-achat (corrections d'adresses, ajouts de remises après commande). Si vous intégrez cela à votre feuille de route, sachez que l'application Revize est disponible sur le Shopify App Store et opère aux côtés des nouvelles Functions que vous concevez.

Ressources


Articles connexes


Nous sommes le 16 avril 2026. Hier — le 15 avril — Shopify a définitivement verrouillé le Script Editor. Vous ne pouvez plus créer ni publier de nouveau Script. L'arrêt de l'exécution intervient dans 75 jours, le 30 juin 2026.

Si vous êtes un développeur Shopify Plus — ou l'agence qui gère une boutique Plus — et que vous avez repoussé cette migration au « prochain sprint » ces douze derniers mois, vous avez un problème. Pas un problème cosmétique. Un problème du type « votre tunnel de paiement plante à minuit le 1er juillet ». La plupart des boutiques Plus ont accumulé entre 5 et 20 Scripts au fil des ans, chacun gérant silencieusement une règle de réduction, un masquage de livraison ou une passerelle de paiement que personne ne se souvient avoir codée.

Ce guide est le manuel technique de migration que nous aurions aimé avoir en janvier. Il traite du code réel, pas seulement de la stratégie. À la fin de votre lecture, vous saurez comment échafauder une Function avec la Shopify CLI, écrire la logique en Rust ou JavaScript pour les réductions, les personnalisations de livraison et de paiement, la tester en toute sécurité sur un sous-ensemble de clients ciblé, et la déployer en production sans perturber votre checkout actuel.

Débarrassons votre boutique des Scripts et installons-y les Functions.



Developer migrating Shopify Scripts to Shopify Functions modules

Réponse rapide : Scripts → Functions en 60 secondes

La migration en un paragraphe : Les Shopify Scripts (code Ruby dans le Script Editor, réservés à Plus) sont remplacés par les Shopify Functions (modules WebAssembly écrits en Rust ou JavaScript, disponibles pour tous les forfaits). Vous générez une Function avec shopify app generate extension, écrivez une requête run.graphql qui récupère les données de panier nécessaires, écrivez un fichier run.rs ou run.js qui renvoie les opérations (réductions, modes de livraison masqués, etc.), puis déployez avec shopify app deploy et l'activez via l'Admin ou une mutation GraphQL. Les Functions s'exécutent sous forme de WASM compilé avec une latence inférieure à 5 ms, fonctionnent sur tous les forfaits et constituent l'unique voie de personnalisation prise en charge par Shopify à l'avenir.

Ce qui change réellement le 30 juin

Avant de toucher au code, actons les dates. Il y en a deux, et toutes deux sont cruciales.


Date

Événement

Action requise

15 avril 2026 (passé)

Script Editor en lecture seule. Aucun nouveau Script. Aucune modification des Scripts existants.

Les Scripts existants s'exécutent encore. Migrez maintenant ou figez votre logique.

30 juin 2026

Tous les Shopify Scripts cessent de s'exécuter. Définitivement.

Votre Function de remplacement doit être active avant cette date.

La migration est binaire. Soit votre Function est déployée d'ici le 30 juin et votre checkout continue de fonctionner, soit elle ne l'est pas — et chaque panier concerné appliquera par défaut les tarifs standards, les frais de livraison de base et l'ensemble des modes de paiement activés. Pas de demi-mesure. Le Script s'exécute ou ne s'exécute pas, et après le 30 juin, il ne s'exécutera plus.

Astuce : Allez dans Settings → Checkout → Customizations Report dans votre admin Shopify. Vous y trouverez la liste de chaque Script actif sur votre boutique, son rôle et le type de Function de remplacement recommandé. Commencez par là.

Functions vs Scripts : Ce qui a réellement changé


Critère

Shopify Scripts (obsolète)

Shopify Functions (remplacement)

Langage

Ruby DSL (propre à Shopify)

Rust, JavaScript, TypeScript

Environnement d'exécution

Ruby sandboxé sur l'infrastructure Shopify

WebAssembly (WASM) — exécution < 5ms

Forfaits compatibles

Plus uniquement

Tous les forfaits (les apps personnalisées nécessitent Plus ; les apps publiques sont ouvertes)

Éditeur

Script Editor intégré à l'admin

IDE local + Shopify CLI

Gestion des versions

Aucune — modifications en direct

Compatible Git — contrôle de version complet

Tests

Manuels dans le checkout

Développement local avec shopify app dev, liens d'aperçu

Déploiement

Clic sur "Enregistrer" dans l'admin

shopify app deploy depuis le terminal

Cibles

Articles du panier, expédition, paiements

Discounts, Cart Transform, Validation, Delivery Customization, Payment Customization, Order Routing, Fulfillment Constraints, et plus

Le changement d'architecture est fondamental. Les Scripts consistaient à « bricoler du Ruby dans une zone de texte ». Les Functions consistent à « écrire une véritable application, la versionner, la tester localement, la déployer via un pipeline CI digne de ce nom ». La courbe d'apprentissage est plus raide. C'est aussi la dernière migration que vous aurez à faire pour la logique de checkout dans un avenir prévisible — les Functions représentent l'engagement à long terme de Shopify, contrairement aux Scripts qui se sont avérés être une solution temporaire.

Associer vos Scripts au bon type de Function

Chaque Script actuel correspond à exactement une API de Function. Voici la table de correspondance à garder sous les yeux.


Ancien type de Script

Rôle

Nouvelle API de Function

Cible (Target)

Line Item Script

Appliquer des remises à des produits / clients / conditions de panier spécifiques

Cart & Checkout Discounts API

cart.lines.discounts.generate.run

Shipping Script (remise)

Livraison gratuite ou réduite selon des règles de panier

Cart & Checkout Discounts API

cart.delivery-options.discounts.generate.run

Shipping Script (masquer / renommer / réordonner)

Masquer un tarif au-dessus de X $, renommer "Standard" en "Gratuit dès 50 $"

Delivery Customization API

cart.delivery-options.transform.run

Payment Script

Masquer PayPal pour le B2B, masquer le paiement à la livraison au-dessus de 500 $, réordonner les modes de paiement

Payment Customization API

cart.payment-methods.transform.run

Script de modification de panier (rare)

Créer des lots de produits, remplacer des articles

Cart Transform API

cart.transform.run

Script de blocage du checkout

Refuser le panier si la combinaison de SKU est non valide

Cart & Checkout Validation API

cart.validations.generate.run

Si vous avez dix Scripts, vous développerez probablement entre trois et cinq Functions — plusieurs Scripts se résument souvent à une seule Function dotée d'une logique de branchement plus propre.



Shopify Functions unifying discounts, delivery, and payment customizations

Prérequis : Configurer votre environnement de développement local

Avant de générer une Function, vous devez installer trois outils en local. Exécutez ces vérifications dans votre terminal.

1. Node.js 18+


node --version
# Doit être >= 18.0.0

Si la version est plus ancienne, installez-la via nvm ou téléchargez-la sur nodejs.org.

2. Shopify CLI 3+


npm install -g @shopify/cli@latest
shopify version
# Doit afficher 3.x ou plus

3. Toolchain Rust (uniquement si vous écrivez vos Functions en Rust)


curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup target add wasm32-wasip1
cargo --version

Les Functions en JavaScript n'ont pas besoin de Rust. Choisissez un langage pour votre équipe et tenez-vous-y — mélanger les deux ajoute des coûts de maintenance.

4. Une boutique de développement

Connectez-vous à votre tableau de bord Partner et créez une nouvelle boutique de développement, ou utilisez-en une existante. Vous y déploierez vos Functions avant de les passer en production.

Générer votre première Function

La CLI s'occupe de l'essentiel du code de base. Dans n'importe quel répertoire :


# Créer une nouvelle application Shopify (ignorez si vous en avez déjà une)
shopify app init my-checkout-functions
cd my-checkout-functions

# Générer une extension de type Function
shopify app generate extension

La CLI vous guide à travers différentes questions. Pour une Function de réduction, vous choisiriez :

  • Type : Function

  • Modèle : discount (ou cart_checkout_validation, delivery_customization, payment_customization, etc.)

  • Langage : Rust ou JavaScript

  • Nom : par exemple volume-discount-fn

Cela crée le répertoire extensions/volume-discount-fn/ contenant :


extensions/volume-discount-fn/
├── shopify.extension.toml      # Config de la Function cibles, build, version
├── src/
├── cart_lines_discounts_generate_run.graphql   # Requête d'entrée
└── cart_lines_discounts_generate_run.rs        # Logique de la Function
├── Cargo.toml                  # Dépendances Rust (Rust uniquement)
└── README.md

Les trois fichiers que vous modifierez en permanence sont le .toml (config), le .graphql (entrée) et le .rs / .js (logique). C'est tout.

Tutoriel 1 : Remplacer un Line Item Script (Remise sur volume)

Supposons que votre ancien Script appliquait une remise de 10 % sur le sous-total de la commande dès que le panier contenait au moins 5 articles d'une collection spécifique. Voici l'équivalent sous forme de Function.

Étape 1.1 : La configuration (shopify.extension.toml)


api_version = "2026-01"

[[extensions]]
name = "volume-discount-fn"
handle = "volume-discount-fn"
type = "function"

[[extensions.targeting]]
target = "cart.lines.discounts.generate.run"
input_query = "src/cart_lines_discounts_generate_run.graphql"
export = "cart_lines_discounts_generate_run"

[extensions.build]
command = "cargo build --target=wasm32-wasip1 --release"
path = "target/wasm32-wasip1/release/volume-discount-fn.wasm"
watch = ["src/**/*.rs"]

Étape 1.2 : La requête d'entrée (src/cart_lines_discounts_generate_run.graphql)


query Input {
  cart {
    lines {
      id
      quantity
      cost {
        subtotalAmount {
          amount
        }
      }
      merchandise {
        ... on ProductVariant {
          product {
            inAnyCollection(ids: ["gid://shopify/Collection/123456789"])
          }
        }
      }
    }
  }
  discount {
    discountClasses
  }
}

Astuce : Les Functions ne voient que les données que vous demandez. Limitez le GraphQL au strict minimum — chaque champ ignoré garantit une exécution plus rapide et moins coûteuse.

Étape 1.3 : La logique (src/cart_lines_discounts_generate_run.rs)


use super::schema;
use shopify_function::prelude::*;
use shopify_function::Result;

#[shopify_function]
fn cart_lines_discounts_generate_run(
    input: schema::cart_lines_discounts_generate_run::Input,
) -> Result<schema::CartLinesDiscountsGenerateRunResult> {
    // Arrêter si la classe de remise ne correspond pas
    let has_order_discount = input
        .discount()
        .discount_classes()
        .contains(&schema::DiscountClass::Order);

    if !has_order_discount {
        return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
    }

    // Sommer les quantités d'articles de la collection cible
    let qualifying_qty: i64 = input
        .cart()
        .lines()
        .iter()
        .filter(|line| {
            if let schema::Merchandise::ProductVariant(v) = line.merchandise() {
                *v.product().in_any_collection()
            } else {
                false
            }
        })
        .map(|line| *line.quantity())
        .sum();

    if qualifying_qty < 5 {
        return Ok(schema::CartLinesDiscountsGenerateRunResult { operations: vec![] });
    }

    // Appliquer 10 % de réduction sur le sous-total de la commande
    Ok(schema::CartLinesDiscountsGenerateRunResult {
        operations: vec![schema::CartOperation::OrderDiscountsAdd(
            schema::OrderDiscountsAddOperation {
                selection_strategy: schema::OrderDiscountSelectionStrategy::First,
                candidates: vec![schema::OrderDiscountCandidate {
                    targets: vec![schema::OrderDiscountCandidateTarget::OrderSubtotal(
                        schema::OrderSubtotalTarget {
                            excluded_cart_line_ids: vec![],
                        },
                    )],
                    message: Some("Volume discount: 10% off".to_string()),
                    value: schema::OrderDiscountCandidateValue::Percentage(
                        schema::Percentage { value: Decimal(10.0) }
                    ),
                    conditions: None,
                    associated_discount_code: None,
                }],
            },
        )],
    })
}

Étape 1.4 : Tester, déployer, activer


# Développement local avec rechargement à chaud
shopify app dev

# Lorsque vous êtes prêt, déployez
shopify app deploy

# Dans le panneau GraphiQL qui s'ouvre (appuyez sur `g` dans le terminal de dev),
# créez la remise automatique qui utilise votre Function :
mutation {
  discountAutomaticAppCreate(
    automaticAppDiscount: {
      title: "Volume Discount (5+ collection items)"
      functionHandle: "volume-discount-fn"
      discountClasses: [ORDER]
      startsAt: "2026-04-16T00:00:00Z"
    }
  ) {
    automaticAppDiscount { discountId }
    userErrors { field message }
  }
}

C'est tout. La Function est active, versionnée et remplace définitivement l'ancien Script.

Tutoriel 2 : Remplacer un Shipping Script (Masquer un mode de livraison selon le montant du panier)

Un Script classique : « Masquer la livraison Express lorsque le sous-total du panier dépasse 500 $ pour éviter des frais d'envoi de nuit exorbitants sur de grosses commandes. » Voici la version Delivery Customization avec une Function.

Étape 2.1 : Générer l'extension


shopify app generate extension --template delivery_customization --name hide-express-fn

Étape 2.2 : Requête d'entrée (src/run.graphql)


query Input {
  cart {
    cost {
      subtotalAmount {
        amount
      }
    }
    deliveryGroups {
      deliveryOptions {
        handle
        title
      }
    }
  }
}

Étape 2.3 : Logique (src/run.js — variante JavaScript)


// @ts-check
/**
 * @typedef {import("../generated/api").RunInput} RunInput
 * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult
 */

const NO_CHANGES = { operations: [] };
const THRESHOLD = 500.0;
const HIDE_TITLES = ["Express", "Overnight"];

/**
 * @param {RunInput} input
 * @returns {FunctionRunResult}
 */
export function run(input) {
  const subtotal = parseFloat(input.cart.cost.subtotalAmount.amount);
  if (subtotal < THRESHOLD) return NO_CHANGES;

  const operations = input.cart.deliveryGroups.flatMap((group) =>
    group.deliveryOptions
      .filter((opt) => HIDE_TITLES.some((t) => opt.title.includes(t)))
      .map((opt) => ({
        hide: { deliveryOptionHandle: opt.handle },
      }))
  );

  return { operations };
}

Étape 2.4 : Activer via l'Admin (sans GraphQL)

Les Delivery Customizations disposent d'une interface d'administration intégrée. Après l'exécution de shopify app deploy :

  1. Allez dans Settings → Shipping and delivery

  2. Faites défiler jusqu'à la section Customizations tout en bas

  3. Cliquez sur Add customization → sélectionnez votre Function

  4. Enregistrez

La règle de masquage est active en production. Aucune mutation requise.



Shopify delivery customization Function hiding shipping option at checkout

Tutoriel 3 : Remplacer un Payment Script (Masquer le paiement à la livraison pour le B2B)

Ancien Script : « Masquer le paiement à la livraison (COD) pour tout client doté du tag 'B2B'. » Voici la version Payment Customization.

Étape 3.1 : Générer l'extension


shopify app generate extension --template payment_customization --name hide-cod-b2b-fn

Étape 3.2 : Requête d'entrée


query Input {
  cart {
    buyerIdentity {
      customer {
        hasTags(tags: [{ tag: "B2B" }]) {
          tag
          hasTag
        }
      }
    }
  }
  paymentMethods {
    id
    name
  }
}

Étape 3.3 : Logique (src/run.js)


const NO_CHANGES = { operations: [] };

export function run(input) {
  const tagCheck = input.cart?.buyerIdentity?.customer?.hasTags?.[0];
  const isB2B = tagCheck?.hasTag === true;
  if (!isB2B) return NO_CHANGES;

  const codMethod = input.paymentMethods.find((pm) =>
    pm.name.toLowerCase().includes("cash on delivery")
  );
  if (!codMethod) return NO_CHANGES;

  return {
    operations: [{ hide: { paymentMethodId: codMethod.id } }],
  };
}

Étape 3.4 : Activer

Les Payment Customizations ont également une interface d'administration dans Settings → Payments → Customizations. Même processus que pour la livraison — sélectionnez votre Function, enregistrez, terminé.

Puisque vous lisez ceci — Un mot sur le post-achat

Une mise au point rapide puisque vous êtes sur le blog de Revize. Revize gère ce que les Functions ne peuvent pas toucher — une fois la commande passée, les clients veulent ajouter un article, modifier une taille, corriger l'adresse de livraison ou appliquer un code promo oublié. Les Functions interviennent lors du paiement. Revize intervient après. Les Functions déterminent ce qui est autorisé dans le panier ; Revize offre à vos clients et à votre équipe de support la possibilité de modifier la commande a posteriori sans passer par un cycle d'annulation et de recréation. C'est capital pour deux types de boutiques : celles qui ont un volume de commandes tel que l'édition manuelle devient impossible (les opérateurs Plus, par définition, mais aussi les boutiques Advanced à fort trafic), et celles dont l'image de marque repose sur l'expérience client — où un e-mail indiquant « désolé, nous ne pouvons pas modifier cela » détruit la fidélisation.

Si votre plan de migration couvre Scripts → Functions mais que vous n'avez pas encore résolu la gestion des modifications post-achat, vous vous heurterez au prochain obstacle technique d'ici trois semaines. Le guide de gestion des commandes que nous venons de publier détaille l'ensemble de la stratégie post-paiement.

Retour à la migration.

Stratégie de test : La méthode du tag client

Les Functions ne possèdent pas de « mode brouillon » activable dans l'admin. La bonne pratique professionnelle consiste à conditionner la nouvelle Function à la présence d'un tag client, à exécuter l'ancien Script et la nouvelle Function en parallèle, à vérifier qu'ils produisent des résultats identiques pour les utilisateurs taggués, puis à effectuer la bascule complète.

Étape 1 : Tagger vos utilisateurs de test

Dans la section Customers, ajoutez le tag FN-TESTER à deux ou trois comptes internes.

Étape 2 : Conditionner la Function à la présence du tag


// Au début de votre fonction run
let is_tester = input
    .cart()
    .buyer_identity()
    .and_then(|bi| bi.customer())
    .map(|c| c.has_any_tag())
    .unwrap_or(&false);

if !*is_tester {
    return Ok(default_result);  // Laisser l'exécution à l'ancien Script
}

// La logique de la nouvelle Function s'exécute uniquement pour les testeurs

Étape 3 : Ajouter hasAnyTag à votre requête d'entrée


cart {
  buyerIdentity {
    customer {
      hasAnyTag(tags: ["FN-TESTER"])
    }
  }
}

Étape 4 : Vérifier dans le checkout

Connectez-vous avec un compte taggué, passez une commande de test, validez que la Function se déclenche. Connectez-vous avec un compte non taggué, validez que l'ancien Script s'exécute toujours. Après quelques jours sans anomalie, retirez la vérification du tag pour appliquer la Function à tous.

Étape 5 : Retirer l'ancien Script

Allez dans Apps → Script Editor → [Votre Script] → Unpublish. Une fois dépublié, la Function devient l'unique source de vérité.

Un flux de déploiement véritablement structuré

Ne déployez pas indéfiniment depuis la machine d'un développeur. Dès que vous avez migré un ou deux Scripts, configurez un véritable pipeline CI.

Le workflow minimal viable


# .github/workflows/deploy-functions.yml
name: Deploy Shopify Functions
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - uses: dtolnay/rust-toolchain@stable
        with: { targets: wasm32-wasip1 }
      - run: npm install -g @shopify/cli@latest
      - run: shopify app deploy --force
        env:
          SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}

Générez le token partenaire depuis votre tableau de bord Partner dans Settings → Tokens. Désormais, chaque fusion vers main déploie vos Functions. Fini les discussions Slack pour savoir qui a déployé la dernière version.

Gestion des versions et retour arrière

La commande shopify app deploy crée un instantané versionné. Pour revenir en arrière :


shopify app versions list
shopify app release --version <previous-version-id

Comparé aux Scripts — où le retour arrière consistait à retrouver l'ancien code manuellement pour le recoller — c'est le jour et la nuit.



Shopify Functions deployment pipeline across local staging and production environments

Les erreurs les plus fréquentes commises par les équipes

Après avoir accompagné de nombreux marchands Plus dans cette migration l'an dernier, les cinq mêmes erreurs reviennent systématiquement.

1. Traiter les Functions comme un simple portage de Script individuel. Ce n'est pas le cas. Une seule Function peut remplacer trois Scripts grâce à une logique de branchement plus saine. Analysez vos Scripts de manière globale avant de réécrire le code.

2. Oublier les habilitations d'API (scopes d'accès). Beaucoup de Functions nécessitent read_customers, read_orders ou write_discounts. Ajoutez-les dans shopify.app.toml sous la clé scopes et autorisez à nouveau l'application, sans quoi votre requête d'entrée renverra des données nulles.

3. Lancer les Functions pour tous les clients sans test de parité préalable. Même si votre code vous semble correct, des cas particuliers (paniers vides, cartes-cadeaux, avoirs, brouillons de commandes B2B) feront émerger des anomalies. Un déploiement progressif par tag vous évite des pannes bloquantes en production.

4. Faire l'impasse sur le Customizations Report. C'est la cartographie la plus précise de vos personnalisations actives. Ne vous fiez pas à votre mémoire, fiez-vous au rapport.

5. Hardcoder les identifiants de collections et les tags clients. Utilisez la configuration de Function via les metafields si vous avez besoin de valeurs ajustables par les marchands. La CLI permet de générer des configurations basées sur les metafields — consultez la documentation de Shopify à ce sujet.

Feuille de route de migration pour les 75 prochains jours

Un calendrier réaliste semaine par semaine pour aborder le 30 juin sereinement.


Semaines

Action

Semaine 1 (cette semaine)

Générez le Customizations Report. Listez chaque Script. Choisissez : Function, application publique ou suppression.

Semaines 2 et 3

Configurez l'environnement de dev local. Créez la première Function. Migrez le Script le plus simple (généralement une règle de masquage de paiement).

Semaines 4 à 6

Migrez les Scripts liés aux remises. Ce sont les plus longs à traiter en raison de la richesse de l'API Discounts. Testez minutieusement par tag.

Semaines 7 et 8

Migrez les Scripts liés à la livraison. Activez les Delivery Customizations dans l'admin.

Semaines 9 et 10

Configurez le pipeline CI. Automatisez les déploiements hors des machines locales des développeurs.

Semaine 11 (mi-juin)

Validation finale de la parité. Désactivez tous les Scripts. Faites tourner la boutique uniquement avec les Functions pendant deux semaines.

30 juin

Date de fin d'exécution. Aucune interruption de service car vous avez terminé en avance.

En commençant cette semaine, vous conservez une marge de sécurité. En commençant en juin, vous n'en aurez pas.



Week-by-week migration roadmap from Shopify Scripts to Functions

Foire Aux Questions

Dois-je posséder un forfait Shopify Plus pour utiliser les Functions ?

Les Functions personnalisées nécessitent Shopify Plus, mais les Functions issues d'applications publiques fonctionnent sur tous les forfaits. Si vous n'êtes pas sur Plus, deux solutions s'offrent à vous : installer une application publique depuis le Shopify App Store qui intègre la Function requise, ou passer à Plus pour concevoir vos propres Functions personnalisées. La plupart des marchands d'envergure utilisant des Scripts disposent déjà de Plus.

Puis-je écrire des Functions en TypeScript ?

Oui — TypeScript est pleinement pris en charge et la CLI configure le projet pour vous. Lorsque vous lancez shopify app generate extension et optez pour « JavaScript », le projet généré inclut les déclarations de types de import("../generated/api"). Vous pouvez renommer vos fichiers en .ts et ajouter un fichier tsconfig.json. Le build final (WASM) sera identique.

Quelle est la rapidité des Functions par rapport aux Scripts ?

Les Functions s'exécutent généralement en moins de 5 ms — soit beaucoup plus rapidement que les Scripts Ruby. Étant compilées en WebAssembly et exécutées dans un environnement optimisé, un budget d'exécution de 5 ms est imposé par Shopify. Si votre Function le dépasse, l'opération est abandonnée. En pratique, une Function bien conçue requiert 1 à 2 ms.

Une Function peut-elle interroger une API externe ?

Non — les Functions ne peuvent effectuer aucun appel réseau. Ce sont des briques de calcul pur : elles reçoivent des données de panier en entrée et renvoient des opérations en sortie. Si vous devez exploiter des données externes (CRM, stock en temps réel), stockez-les préalablement dans des metafields, ou utilisez un autre mécanisme (App Proxy, webhooks, Cart Transform avec appel back-end).

Quelle est la différence entre Cart Transform et les Discounts ?

Les Discounts appliquent des réductions tarifaires ; Cart Transform modifie le contenu même du panier. Utilisez l'API Discounts pour appliquer un code, une remise de 10 %, la livraison gratuite ou du type X achetés Y offerts. Utilisez Cart Transform pour regrouper deux produits sous une ligne unique, ou décomposer une variante en plusieurs éléments. Séparez bien ces deux fonctions lors de votre migration.

Comment tester une Function en local sans boutique de développement ?

Vous pouvez exécuter des tests unitaires avec cargo test (Rust) ou npm test (JS), mais le test d'intégration complet exige une boutique de dev. La CLI propose la commande shopify app function run pour exécuter votre Function face à un fichier d'entrée simulé. Pour valider l'expérience dans le checkout réel, une boutique est incontournable.

Puis-je avoir plusieurs Functions du même type actives simultanément ?

Oui — Shopify autorise plusieurs Functions par cible, exécutées selon un ordre déterminé. Pour les remises, la priorité dépend des règles de cumul de Shopify. Pour les personnalisations de livraison et de paiement, les outputs s'enchaînent. Utiliser une seule Function par cible simplifie grandement la maintenance.

Qu'advient-il de mon Script une fois la Function déployée ?

Les deux s'exécutent en parallèle jusqu'à ce que vous archiviez le Script dans Apps → Script Editor. Ce fonctionnement est voulu pour vous permettre de réaliser des phases de tests parallèles en production. Une fois les tests concluants, désactivez le Script. Au-delà du 30 juin 2026, de toute façon, aucun Script ne fonctionnera plus.

Cette migration aura-t-elle un impact sur mon SEO ou mon thème ?

Non — les Functions s'exécutent côté serveur lors du passage en caisse et n'interfèrent jamais avec votre thème ou vos pages produits. Elles ciblent uniquement les réductions, les choix de livraison et les paiements à l'étape finale. Votre site d'e-commerce et votre référencement ne subissent aucun changement.

Comment migrer un Script qui exploite Input.line_items avec des propriétés personnalisées ?

Ces propriétés personnalisées sont accessibles via le champ attribute des lignes de panier de la requête GraphQL. Ajoutez attribute(key: "votre-clef") { value } au sein de la sélection de lignes. La Function lira cette valeur de la même manière que vos Scripts Ruby lisaient les attributs d'articles.

Qu'en est-il des données analytiques et des tags de commande ? Les Functions peuvent-elles en écrire ?

Les Functions ne peuvent pas appliquer de tags aux commandes ni déclencher de webhooks — elles gèrent exclusivement le panier actif. Pour du taggage ou d'autres flux en aval, utilisez Shopify Flow déclenché par l'événement de création de commande. Associez par exemple une Function pour appliquer la remise et un workflow Flow pour tagguer la commande finale.

Existe-t-il une application publique prête à l'emploi si je ne souhaite pas développer de Function personnalisée ?

Oui — le Shopify App Store propose des dizaines d'applications qui encapsulent les Functions pour les cas d'usage récurrents. Cherchez des termes comme "discount function" ou "payment customization". Pour des stratégies classiques (remise sur quantité, masquer des paiements par tag, livraison gratuite dès X $), cela peut vous éviter plusieurs jours de développement. Réservez le sur-mesure aux règles métiers uniques.

Que se passe-t-il si je dépasse la date limite du 30 juin ?

Le Script s'arrête net — aucun délai de grâce, aucune prolongation ne sera accordée. Tout mécanisme géré par le Script (réduction, frais de port modifiés, mode de paiement masqué) reprendra son comportement par défaut le 1er juillet à minuit UTC. Prévoyez une mise en ligne finale bien avant cette date.

Puis-je supprimer définitivement l'application Script Editor ?

Vous pourrez la désinstaller après le 30 juin 2026, sachant que Shopify devrait la retirer automatiquement. Une fois l'échéance passée, cet éditeur n'aura plus d'utilité. Si votre migration est validée en amont, vous pouvez la supprimer dès maintenant ; vos Functions s'exécutent de manière autonome.

Actions prioritaires pour cette semaine

Ne remettez pas à plus tard. Initiez la transition en accomplissant ces quatre tâches d'ici sept jours.

1. Exportez le Customizations Report. Rendez-vous sur Settings → Checkout → Customizations Report et téléchargez-le. Ce document constitue votre cahier des charges de migration.

2. Installez votre environnement de développement. Mettez en place Node 18+, la CLI Shopify et Rust (si requis). Vérifiez le bon fonctionnement de shopify version. Durée estimée : 30 minutes.

3. Déployez une micro-Function sur une boutique de développement. Sélectionnez le Script le moins complexe (par exemple, le masquage d'une option de paiement). Réalisez sa migration de bout en bout pour éprouver votre pipeline d'outils, même si elle n'est pas déployée immédiatement.

4. Planifiez des plages de travail dans les huit prochaines semaines. Une migration réussie demande du temps dédié. Réservez des créneaux de travail récurrents (par exemple deux après-midis par semaine) et traitez ces phases comme des jalons de livraison majeurs.

Les retours d'expérience montrent souvent le même schéma : deux semaines de latence, trois semaines de développement et une semaine d'ajustements. Cela représente un total de six semaines. Il vous en reste dix. Profitez de cette avance pour soigner vos revues de code et vos étapes de recette.

Une fois votre logique de paiement convertie, l'étape suivante pour la majorité des équipes consiste à optimiser les processus post-achat (corrections d'adresses, ajouts de remises après commande). Si vous intégrez cela à votre feuille de route, sachez que l'application Revize est disponible sur le Shopify App Store et opère aux côtés des nouvelles Functions que vous concevez.

Ressources


Articles connexes


Repensez votre boutique Shopify. Misez sur l’expérience client.

© Copyright 2024, Tous droits réservés

Repensez votre boutique Shopify. Misez sur l’expérience client.

© Copyright 2024, Tous droits réservés

Repensez votre boutique Shopify. Misez sur l’expérience client.

© Copyright 2024, Tous droits réservés

Repensez votre boutique Shopify. Misez sur l’expérience client.

© Copyright 2024, Tous droits réservés

The Universal Commerce Protocol UCP Guide How to Start a Shopify Store in 2026 The True Cost of Returns Guide How to Change Shipping Address on Shopify Best Shopify Customer Service Apps 10 Advanced Shopify Flow Workflows How to Add Discount on Shopify After Checkout How to Edit an Order on Shopify Shopify Draft Orders Complete Guide How to Do a Partial Refund on Shopify Shopify Social Login Complete Guide Post Purchase Email Marketing Automating E-commerce with Shopify Flow Customize Shopify Login Redirect Shopify New Customer Accounts Migration Guide How Poor Customer Support Can Sabotage Your Business How Refunds Work on Shopify In-House Warranty Management vs Shopify Apps Shopify Checkout Extensibility 2026: Deadline, Migration, and What's Broken How to Let Customers Cancel Orders on Shopify Shopify Legacy Customer Accounts Are Deprecated How to Edit Your Shopify Order Confirmation Email How to Do an Exchange on Shopify How to Sell on ChatGPT with Shopify Agentic Storefronts Shopify Functions Migration Tutorial Shopify AI Toolkit Guide 2026: Agents, MCP, and UCP Explained Shopify Sidekick vs Your Agency: The 2026 Scorecard for Plus Stores Shopify B2B 2026 Complete Guide Shopify Order Management Guide 2026 Shopify Advanced to Plus 2026 Migration Playbook 20 Shopify Flow AI Prompts Plus Operators Copy Shopify MCP Developer Guide 2026 EU Withdrawal Button for Shopify 2026 Best Shopify Order Editing Apps 2026