Archive and disable Snipcart integration for Shopify migration

Disable Snipcart e-commerce integration to prepare for Shopify Buy Button. All Snipcart code is preserved in assets/snipcart-archive/ with complete restoration instructions.

Changes:
- Comment out Snipcart SCSS import
- Disable Snipcart routes (validate.json, webhook)
- Comment Snipcart attributes in product template
- Remove Snipcart scripts from footer
- Create archive with snipcart.js, product-size.js, _snipcart.scss
- Add comprehensive README.md with restoration guide

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
isUnknown 2026-01-13 17:17:40 +01:00
parent 84aa4cac17
commit c08662caf8
7 changed files with 348 additions and 3 deletions

View file

@ -22,6 +22,6 @@
@import "template/shop/layout";
@import "template/shop/section--product";
@import "template/shop/thanks";
@import "template/shop/snipcart";
// @import "template/shop/snipcart"; // Snipcart désactivé - voir assets/snipcart-archive/README.md
@import "template/subscription-newsletter/layout";

View file

@ -0,0 +1,164 @@
# Archive Snipcart
Cette archive contient tous les fichiers et le code nécessaires pour réactiver l'intégration Snipcart si besoin.
## Date d'archivage
13 janvier 2026
## Raison de l'archivage
Remplacement par l'intégration Shopify Buy Button
---
## Fichiers archivés
### Fichiers JavaScript
- `snipcart.js` - Loader Snipcart avec configuration de la clé API
- `product-size.js` - Gestion des options produit (tailles, etc.) pour Snipcart
### Fichiers SCSS
- `_snipcart.scss` - Styles pour le modal Snipcart
---
## Comment restaurer l'intégration Snipcart
### 1. Restaurer les fichiers JavaScript
#### Fichier: `assets/js/snipcart.js`
Copier le fichier depuis l'archive:
```bash
cp assets/snipcart-archive/snipcart.js assets/js/
```
#### Fichier: `assets/js/product-size.js`
Copier le fichier depuis l'archive:
```bash
cp assets/snipcart-archive/product-size.js assets/js/
```
### 2. Restaurer les styles SCSS
#### Fichier: `assets/css/template/shop/_snipcart.scss`
Copier le fichier depuis l'archive:
```bash
cp assets/snipcart-archive/_snipcart.scss assets/css/template/shop/
```
Puis décommenter l'import dans `assets/css/style.scss`:
```scss
// Décommenter cette ligne:
@import 'template/shop/snipcart';
```
### 3. Restaurer le template produit
#### Fichier: `site/templates/product.php`
1. **Restaurer le bouton "Ajouter au panier" avec les attributs Snipcart** (ligne ~40-78):
- Décommenter tous les attributs `data-item-*` du bouton
- Ajouter la classe `snipcart-add-item` au bouton
2. **Restaurer les scripts dans le footer** (ligne 114):
```php
<?php snippet('footer', ['scripts' => ['assets/js/product-size.js', 'assets/js/snipcart.js', 'assets/js/product-gallery.js']]) ?>
```
### 4. Restaurer les routes et webhooks
#### Fichier: `site/config/config.php`
Décommenter les routes Snipcart (lignes 39-147):
1. **Route de validation produit** (`validate.json`):
- Permet à Snipcart de valider les prix et stock
- Route: `(:any)/validate.json`
2. **Webhook Snipcart**:
- Gère les événements de commande (décrémente le stock)
- Route: `snipcart-webhook`
### 5. Configuration Snipcart
#### Clé API publique
La clé API publique Snipcart est dans `snipcart.js`:
```javascript
publicApiKey: 'NGU4ODQ3MjAtY2MzMC00MWEyLWI2YTMtNjBmNGYzMTBlOTZkNjM4OTY1NDY4OTE5MTQyMTI3'
```
#### Configuration du webhook
Pour que le webhook fonctionne, il faut:
1. Configurer l'URL du webhook dans le dashboard Snipcart
2. URL: `https://votre-domaine.com/snipcart-webhook`
3. Événements à écouter: `order.completed`
### 6. Vérifications après restauration
- [ ] Les fichiers JS sont présents dans `assets/js/`
- [ ] Le fichier SCSS est présent et importé
- [ ] Les boutons "Ajouter au panier" ont la classe `snipcart-add-item`
- [ ] Les attributs `data-item-*` sont présents sur les boutons
- [ ] Les routes sont décommentées dans `config.php`
- [ ] Le CSS de Snipcart est compilé
- [ ] Le webhook est configuré dans le dashboard Snipcart
- [ ] Les traductions sont restaurées dans `site/languages/en.php` et `fr.php`
---
## Fonctionnalités Snipcart implémentées
### Gestion des produits
- Affichage du prix
- Options de produit (tailles, couleurs, etc.)
- Validation des options obligatoires
- Images produit
### Gestion du panier
- Ajout au panier
- Gestion du stock
- Calcul des frais de port (basé sur poids/dimensions)
- Validation des prix côté serveur
### Gestion des commandes
- Webhook pour décrémenter le stock automatiquement
- Redirection vers page de remerciement après paiement
- Token de commande dans l'URL
### Multi-langue
- Support FR/EN
- Redirection post-paiement avec détection de la langue
---
## Dépendances externes
### CDN Snipcart
Snipcart est chargé depuis le CDN officiel:
- Version: 3.0
- JS: `https://cdn.snipcart.com/themes/v3.0/default/snipcart.js`
- CSS: `https://cdn.snipcart.com/themes/v3.0/default/snipcart.css`
### Stratégie de chargement
- `loadStrategy: 'on-user-interaction'`
- Chargement différé pour optimiser les performances
- Timeout: 2750ms
---
## Notes importantes
1. **Sécurité**: Le webhook devrait valider la signature Snipcart en production (voir commentaire dans `config.php`)
2. **Stock**: Le système décrémente automatiquement le stock via le webhook `order.completed`
3. **Validation**: Chaque produit expose une route `validate.json` pour que Snipcart puisse vérifier les prix
4. **Multi-langue**: La redirection post-paiement détecte automatiquement la langue depuis l'URL
---
## Support
Pour toute question sur Snipcart:
- Documentation: https://docs.snipcart.com/
- Support: https://snipcart.com/support

View file

@ -0,0 +1,3 @@
.snipcart-modal__container {
z-index: 1000;
}

View file

@ -0,0 +1,66 @@
/**
* Gestion de la sélection des options produit
* Met à jour les attributs Snipcart et gère les classes CSS
*/
(function() {
'use strict';
/**
* Initialise la gestion des options
*/
function initOptionSelector() {
const optionsContainer = document.querySelector('.product-options');
const addToCartButton = document.querySelector('.snipcart-add-item');
if (!addToCartButton) {
return;
}
// Si pas d'options, le bouton est déjà actif
if (!optionsContainer) {
return;
}
const radios = optionsContainer.querySelectorAll('input[type="radio"]');
// Réinitialiser toutes les options (important pour le cache navigateur)
radios.forEach(radio => {
radio.checked = false;
});
// Retirer la classe is-selected de tous les li
const allLi = optionsContainer.querySelectorAll('li');
allLi.forEach(li => li.classList.remove('is-selected'));
// S'assurer que le bouton est désactivé au départ
addToCartButton.setAttribute('disabled', 'disabled');
// Écouter les changements de sélection
radios.forEach(radio => {
radio.addEventListener('change', function() {
// Mettre à jour l'attribut Snipcart
addToCartButton.setAttribute('data-item-custom1-value', this.value);
// Activer le bouton
addToCartButton.removeAttribute('disabled');
// Changer le texte du bouton
const buttonText = addToCartButton.querySelector('.txt');
if (buttonText) {
buttonText.textContent = buttonText.getAttribute('data-default-text') || 'Ajouter au panier';
}
// Gérer la classe is-selected sur les li parents
allLi.forEach(li => li.classList.remove('is-selected'));
this.closest('li').classList.add('is-selected');
});
});
}
/**
* Initialisation au chargement de la page
*/
document.addEventListener('DOMContentLoaded', initOptionSelector);
})();

View file

@ -0,0 +1,94 @@
window.SnipcartSettings = {
publicApiKey:
'NGU4ODQ3MjAtY2MzMC00MWEyLWI2YTMtNjBmNGYzMTBlOTZkNjM4OTY1NDY4OTE5MTQyMTI3',
loadStrategy: 'on-user-interaction',
};
// Redirection après paiement réussi
document.addEventListener('snipcart.ready', function() {
Snipcart.events.on('cart.confirmed', function(cartState) {
// Détecter la langue actuelle depuis l'URL
const currentPath = window.location.pathname;
const langMatch = currentPath.match(/^\/([a-z]{2})(\/|$)/);
const langPrefix = langMatch ? '/' + langMatch[1] : '';
window.location.href = langPrefix + '/thanks?order=' + cartState.token;
});
});
(() => {
var c, d;
(d = (c = window.SnipcartSettings).version) != null || (c.version = '3.0');
var s, S;
(S = (s = window.SnipcartSettings).timeoutDuration) != null ||
(s.timeoutDuration = 2750);
var l, p;
(p = (l = window.SnipcartSettings).domain) != null ||
(l.domain = 'cdn.snipcart.com');
var w, u;
(u = (w = window.SnipcartSettings).protocol) != null ||
(w.protocol = 'https');
var f =
window.SnipcartSettings.version.includes('v3.0.0-ci') ||
(window.SnipcartSettings.version != '3.0' &&
window.SnipcartSettings.version.localeCompare('3.4.0', void 0, {
numeric: !0,
sensitivity: 'base',
}) === -1),
m = ['focus', 'mouseover', 'touchmove', 'scroll', 'keydown'];
window.LoadSnipcart = o;
document.readyState === 'loading'
? document.addEventListener('DOMContentLoaded', r)
: r();
function r() {
window.SnipcartSettings.loadStrategy
? window.SnipcartSettings.loadStrategy === 'on-user-interaction' &&
(m.forEach((t) => document.addEventListener(t, o)),
setTimeout(o, window.SnipcartSettings.timeoutDuration))
: o();
}
var a = !1;
function o() {
if (a) return;
a = !0;
let t = document.getElementsByTagName('head')[0],
e = document.querySelector('#snipcart'),
i = document.querySelector(
`src[src^="${window.SnipcartSettings.protocol}://${window.SnipcartSettings.domain}"][src$="snipcart.js"]`
),
n = document.querySelector(
`link[href^="${window.SnipcartSettings.protocol}://${window.SnipcartSettings.domain}"][href$="snipcart.css"]`
);
e ||
((e = document.createElement('div')),
(e.id = 'snipcart'),
e.setAttribute('hidden', 'true'),
document.body.appendChild(e)),
v(e),
i ||
((i = document.createElement('script')),
(i.src = `${window.SnipcartSettings.protocol}://${window.SnipcartSettings.domain}/themes/v${window.SnipcartSettings.version}/default/snipcart.js`),
(i.async = !0),
t.appendChild(i)),
n ||
((n = document.createElement('link')),
(n.rel = 'stylesheet'),
(n.type = 'text/css'),
(n.href = `${window.SnipcartSettings.protocol}://${window.SnipcartSettings.domain}/themes/v${window.SnipcartSettings.version}/default/snipcart.css`),
t.prepend(n)),
m.forEach((g) => document.removeEventListener(g, o));
}
function v(t) {
!f ||
((t.dataset.apiKey = window.SnipcartSettings.publicApiKey),
window.SnipcartSettings.addProductBehavior &&
(t.dataset.configAddProductBehavior =
window.SnipcartSettings.addProductBehavior),
window.SnipcartSettings.modalStyle &&
(t.dataset.configModalStyle = window.SnipcartSettings.modalStyle),
window.SnipcartSettings.currency &&
(t.dataset.currency = window.SnipcartSettings.currency),
window.SnipcartSettings.templatesUrl &&
(t.dataset.templatesUrl = window.SnipcartSettings.templatesUrl));
}
})();

View file

@ -37,6 +37,8 @@ return [
],
'routes' => [
// SNIPCART ROUTES - Désactivées, voir assets/snipcart-archive/README.md pour restauration
/*
[
'pattern' => '(:any)/validate.json',
'method' => 'GET',
@ -144,5 +146,6 @@ return [
return Response::json(['status' => 'success'], 200);
}
]
*/
]
];

View file

@ -38,7 +38,13 @@
<?php endif ?>
<div class="add-to-cart">
<!-- Snipcart désactivé - voir assets/snipcart-archive/README.md pour restauration -->
<button
class="btn__default"
disabled
<?php
/*
// SNIPCART - Décommenter pour réactiver
class="btn__default snipcart-add-item"
data-item-id="<?= $page->slug() ?>"
data-item-price="<?= $page->price() ?>"
@ -50,7 +56,11 @@
data-item-length="<?= $page->length()->or(0) ?>"
data-item-width="<?= $page->width()->or(0) ?>"
data-item-height="<?= $page->height()->or(0) ?>"
*/
?>
<?php
/*
// SNIPCART OPTIONS - Décommenter pour réactiver
if($page->hasOptions()->toBool() && $page->optionValues()->isNotEmpty()):
$values = $page->optionValues()->split(',');
$trimmedValues = array_map('trim', $values);
@ -60,7 +70,8 @@
data-item-custom1-options="<?= $snipcartOptions ?>"
data-item-custom1-required="true"
disabled
<?php endif; ?>
<?php endif; */
?>
>
<span class="icon">
<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
@ -111,4 +122,8 @@
</section>
</main>
<?php snippet('footer', ['scripts' => ['assets/js/product-size.js', 'assets/js/snipcart.js', 'assets/js/product-gallery.js']]) ?>
<?php
// Snipcart désactivé - voir assets/snipcart-archive/README.md
// Pour réactiver: ajouter 'assets/js/product-size.js', 'assets/js/snipcart.js' dans le tableau
snippet('footer', ['scripts' => ['assets/js/product-gallery.js']])
?>