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/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";
|
||||
|
|
|
|||
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' => [
|
||||
// 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);
|
||||
}
|
||||
]
|
||||
*/
|
||||
]
|
||||
];
|
||||
|
|
|
|||
|
|
@ -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']])
|
||||
?>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue