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:
parent
84aa4cac17
commit
c08662caf8
7 changed files with 348 additions and 3 deletions
|
|
@ -22,6 +22,6 @@
|
||||||
@import "template/shop/layout";
|
@import "template/shop/layout";
|
||||||
@import "template/shop/section--product";
|
@import "template/shop/section--product";
|
||||||
@import "template/shop/thanks";
|
@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";
|
@import "template/subscription-newsletter/layout";
|
||||||
|
|
|
||||||
164
assets/snipcart-archive/README.md
Normal file
164
assets/snipcart-archive/README.md
Normal 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
|
||||||
3
assets/snipcart-archive/_snipcart.scss
Normal file
3
assets/snipcart-archive/_snipcart.scss
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
.snipcart-modal__container {
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
66
assets/snipcart-archive/product-size.js
Normal file
66
assets/snipcart-archive/product-size.js
Normal 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);
|
||||||
|
|
||||||
|
})();
|
||||||
94
assets/snipcart-archive/snipcart.js
Normal file
94
assets/snipcart-archive/snipcart.js
Normal 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));
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
@ -37,6 +37,8 @@ return [
|
||||||
],
|
],
|
||||||
|
|
||||||
'routes' => [
|
'routes' => [
|
||||||
|
// SNIPCART ROUTES - Désactivées, voir assets/snipcart-archive/README.md pour restauration
|
||||||
|
/*
|
||||||
[
|
[
|
||||||
'pattern' => '(:any)/validate.json',
|
'pattern' => '(:any)/validate.json',
|
||||||
'method' => 'GET',
|
'method' => 'GET',
|
||||||
|
|
@ -144,5 +146,6 @@ return [
|
||||||
return Response::json(['status' => 'success'], 200);
|
return Response::json(['status' => 'success'], 200);
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
*/
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,13 @@
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
<div class="add-to-cart">
|
<div class="add-to-cart">
|
||||||
|
<!-- Snipcart désactivé - voir assets/snipcart-archive/README.md pour restauration -->
|
||||||
<button
|
<button
|
||||||
|
class="btn__default"
|
||||||
|
disabled
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
// SNIPCART - Décommenter pour réactiver
|
||||||
class="btn__default snipcart-add-item"
|
class="btn__default snipcart-add-item"
|
||||||
data-item-id="<?= $page->slug() ?>"
|
data-item-id="<?= $page->slug() ?>"
|
||||||
data-item-price="<?= $page->price() ?>"
|
data-item-price="<?= $page->price() ?>"
|
||||||
|
|
@ -50,7 +56,11 @@
|
||||||
data-item-length="<?= $page->length()->or(0) ?>"
|
data-item-length="<?= $page->length()->or(0) ?>"
|
||||||
data-item-width="<?= $page->width()->or(0) ?>"
|
data-item-width="<?= $page->width()->or(0) ?>"
|
||||||
data-item-height="<?= $page->height()->or(0) ?>"
|
data-item-height="<?= $page->height()->or(0) ?>"
|
||||||
|
*/
|
||||||
|
?>
|
||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
// SNIPCART OPTIONS - Décommenter pour réactiver
|
||||||
if($page->hasOptions()->toBool() && $page->optionValues()->isNotEmpty()):
|
if($page->hasOptions()->toBool() && $page->optionValues()->isNotEmpty()):
|
||||||
$values = $page->optionValues()->split(',');
|
$values = $page->optionValues()->split(',');
|
||||||
$trimmedValues = array_map('trim', $values);
|
$trimmedValues = array_map('trim', $values);
|
||||||
|
|
@ -60,7 +70,8 @@
|
||||||
data-item-custom1-options="<?= $snipcartOptions ?>"
|
data-item-custom1-options="<?= $snipcartOptions ?>"
|
||||||
data-item-custom1-required="true"
|
data-item-custom1-required="true"
|
||||||
disabled
|
disabled
|
||||||
<?php endif; ?>
|
<?php endif; */
|
||||||
|
?>
|
||||||
>
|
>
|
||||||
<span class="icon">
|
<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">
|
<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>
|
</section>
|
||||||
</main>
|
</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']])
|
||||||
|
?>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue