This commit is contained in:
commit
a3620a1f5f
1042 changed files with 226722 additions and 0 deletions
0
site/accounts/index.html
Normal file
0
site/accounts/index.html
Normal file
21
site/blueprints/pages/default.yml
Normal file
21
site/blueprints/pages/default.yml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
title: Default Page
|
||||
|
||||
columns:
|
||||
main:
|
||||
width: 2/3
|
||||
sections:
|
||||
fields:
|
||||
type: fields
|
||||
fields:
|
||||
text:
|
||||
type: textarea
|
||||
size: huge
|
||||
sidebar:
|
||||
width: 1/3
|
||||
sections:
|
||||
pages:
|
||||
type: pages
|
||||
template: default
|
||||
files:
|
||||
type: files
|
||||
|
||||
30
site/blueprints/pages/home.yml
Normal file
30
site/blueprints/pages/home.yml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
title:
|
||||
en: Home
|
||||
fr: Accueil
|
||||
icon: shop
|
||||
|
||||
columns:
|
||||
- width: 2/3
|
||||
sections:
|
||||
products:
|
||||
type: pages
|
||||
headline:
|
||||
en: Products
|
||||
fr: Produits
|
||||
template: product
|
||||
sortBy: title asc
|
||||
info: "{{ page.stock }} en stock"
|
||||
layout: cardlets
|
||||
image:
|
||||
query: page.files.first
|
||||
cover: true
|
||||
|
||||
- width: 1/3
|
||||
sections:
|
||||
settings:
|
||||
type: fields
|
||||
fields:
|
||||
baseline:
|
||||
label: Baseline
|
||||
type: textarea
|
||||
size: small
|
||||
79
site/blueprints/pages/product.yml
Normal file
79
site/blueprints/pages/product.yml
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
title:
|
||||
en: Product
|
||||
fr: Produit
|
||||
icon: cart
|
||||
|
||||
tabs:
|
||||
content:
|
||||
label:
|
||||
en: Content
|
||||
fr: Contenu
|
||||
columns:
|
||||
- width: 2/3
|
||||
sections:
|
||||
main:
|
||||
type: fields
|
||||
fields:
|
||||
price:
|
||||
label:
|
||||
en: Price (€)
|
||||
fr: Prix (€)
|
||||
type: number
|
||||
min: 0
|
||||
step: 0.01
|
||||
required: true
|
||||
width: 1/4
|
||||
stock:
|
||||
label: Stock
|
||||
type: number
|
||||
min: 0
|
||||
default: 0
|
||||
help:
|
||||
en: Edit through french version
|
||||
fr: Partagé entre les versions FR et EN
|
||||
translate: false
|
||||
width: 1/4
|
||||
description:
|
||||
label: Description
|
||||
type: writer
|
||||
details:
|
||||
label:
|
||||
en: Details
|
||||
fr: Détails
|
||||
type: writer
|
||||
hasOptions:
|
||||
label:
|
||||
en: Options
|
||||
fr: Options
|
||||
type: toggle
|
||||
default: false
|
||||
width: 1/7
|
||||
optionLabel:
|
||||
label:
|
||||
en: Option label
|
||||
fr: Libellé de l'option
|
||||
type: text
|
||||
width: 3/7
|
||||
when:
|
||||
hasOptions: true
|
||||
optionValues:
|
||||
label:
|
||||
en: Option values
|
||||
fr: Valeurs de l'option
|
||||
type: tags
|
||||
help:
|
||||
en: "Comma-separated values (e.g.: XS, S, M, L, XL)"
|
||||
fr: "Valeurs séparées par des virgules (ex: XS, S, M, L, XL)"
|
||||
when:
|
||||
hasOptions: true
|
||||
width: 3/7
|
||||
|
||||
- width: 1/3
|
||||
sections:
|
||||
images:
|
||||
type: files
|
||||
headline:
|
||||
en: Product Images
|
||||
fr: Images du produit
|
||||
template: image
|
||||
layout: cards
|
||||
15
site/blueprints/site.yml
Normal file
15
site/blueprints/site.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
title: Site
|
||||
|
||||
sections:
|
||||
pages:
|
||||
type: pages
|
||||
headline:
|
||||
en: Products
|
||||
fr: Produits
|
||||
template: product
|
||||
sortBy: title asc
|
||||
info: "{{ page.stock }} en stock"
|
||||
layout: cardlets
|
||||
image:
|
||||
query: page.files.first
|
||||
cover: true
|
||||
0
site/cache/index.html
vendored
Normal file
0
site/cache/index.html
vendored
Normal file
63
site/config/config.php
Normal file
63
site/config/config.php
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'debug' => true,
|
||||
|
||||
'languages' => true,
|
||||
|
||||
'routes' => [
|
||||
[
|
||||
'pattern' => 'snipcart-webhook',
|
||||
'method' => 'POST',
|
||||
'action' => function () {
|
||||
// Webhook handler pour Snipcart
|
||||
// Vérifie la signature et décrémente le stock
|
||||
|
||||
$requestBody = file_get_contents('php://input');
|
||||
$event = json_decode($requestBody, true);
|
||||
|
||||
// Vérifier la signature Snipcart (à implémenter avec la clé secrète)
|
||||
// $signature = $_SERVER['HTTP_X_SNIPCART_REQUESTTOKEN'] ?? '';
|
||||
|
||||
if (!$event || !isset($event['eventName'])) {
|
||||
return Response::json(['error' => 'Invalid request'], 400);
|
||||
}
|
||||
|
||||
// Gérer l'événement order.completed
|
||||
if ($event['eventName'] === 'order.completed') {
|
||||
$order = $event['content'] ?? null;
|
||||
|
||||
if ($order && isset($order['items'])) {
|
||||
foreach ($order['items'] as $item) {
|
||||
$productId = $item['id'] ?? null;
|
||||
$quantity = $item['quantity'] ?? 0;
|
||||
|
||||
if ($productId && $quantity > 0) {
|
||||
// Trouver le produit par son snipcartId
|
||||
$products = site()->index()->filterBy('intendedTemplate', 'product');
|
||||
|
||||
foreach ($products as $product) {
|
||||
if ($product->slug() === $productId) {
|
||||
// Décrémenter le stock
|
||||
$currentStock = (int) $product->stock()->value();
|
||||
$newStock = max(0, $currentStock - $quantity);
|
||||
|
||||
// Mettre à jour le stock dans toutes les langues
|
||||
$product->update([
|
||||
'stock' => $newStock
|
||||
]);
|
||||
|
||||
kirby()->impersonate('kirby');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Response::json(['status' => 'success'], 200);
|
||||
}
|
||||
]
|
||||
]
|
||||
];
|
||||
39
site/languages/en.php
Normal file
39
site/languages/en.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'code' => 'en',
|
||||
'default' => false,
|
||||
'direction' => 'ltr',
|
||||
'locale' => 'en_US',
|
||||
'name' => 'English',
|
||||
'url' => '/en',
|
||||
'translations' => [
|
||||
// General
|
||||
'backToHome' => 'Back to home',
|
||||
'backToShop' => 'Back to shop',
|
||||
'supportText' => 'To support us, you can also',
|
||||
'makeDonation' => 'make a donation',
|
||||
'addToCart' => 'Add to cart',
|
||||
|
||||
// Blueprints - Home
|
||||
'home.title' => 'Home',
|
||||
'home.baseline.label' => 'Baseline',
|
||||
'home.products.headline' => 'Products',
|
||||
'home.settings.headline' => 'Settings',
|
||||
|
||||
// Blueprints - Product
|
||||
'product.title' => 'Product',
|
||||
'product.description.label' => 'Description',
|
||||
'product.details.label' => 'Details',
|
||||
'product.details.item.label' => 'Detail',
|
||||
'product.price.label' => 'Price (€)',
|
||||
'product.backgroundColor.label' => 'Background Color',
|
||||
'product.stock.label' => 'Stock',
|
||||
'product.stock.help' => 'Shared between FR and EN versions',
|
||||
'product.snipcartId.label' => 'Snipcart ID',
|
||||
'product.sizes.label' => 'Available Sizes',
|
||||
'product.images.headline' => 'Product Images',
|
||||
'product.meta.headline' => 'Metadata',
|
||||
'product.tab.content' => 'Content',
|
||||
]
|
||||
];
|
||||
39
site/languages/fr.php
Normal file
39
site/languages/fr.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'code' => 'fr',
|
||||
'default' => true,
|
||||
'direction' => 'ltr',
|
||||
'locale' => 'fr_FR',
|
||||
'name' => 'Français',
|
||||
'url' => '/',
|
||||
'translations' => [
|
||||
// Général
|
||||
'backToHome' => 'Retour à l\'accueil',
|
||||
'backToShop' => 'Retour à la boutique',
|
||||
'supportText' => 'Pour nous soutenir, vous pouvez aussi',
|
||||
'makeDonation' => 'faire un don',
|
||||
'addToCart' => 'Ajouter au panier',
|
||||
|
||||
// Blueprints - Home
|
||||
'home.title' => 'Accueil',
|
||||
'home.baseline.label' => 'Baseline',
|
||||
'home.products.headline' => 'Produits',
|
||||
'home.settings.headline' => 'Paramètres',
|
||||
|
||||
// Blueprints - Product
|
||||
'product.title' => 'Produit',
|
||||
'product.description.label' => 'Description',
|
||||
'product.details.label' => 'Détails',
|
||||
'product.details.item.label' => 'Détail',
|
||||
'product.price.label' => 'Prix (€)',
|
||||
'product.backgroundColor.label' => 'Couleur de fond',
|
||||
'product.stock.label' => 'Stock',
|
||||
'product.stock.help' => 'Partagé entre les versions FR et EN',
|
||||
'product.snipcartId.label' => 'Identifiant Snipcart',
|
||||
'product.sizes.label' => 'Tailles disponibles',
|
||||
'product.images.headline' => 'Images du produit',
|
||||
'product.meta.headline' => 'Métadonnées',
|
||||
'product.tab.content' => 'Contenu',
|
||||
]
|
||||
];
|
||||
0
site/sessions/index.html
Normal file
0
site/sessions/index.html
Normal file
0
site/snippets/index.html
Normal file
0
site/snippets/index.html
Normal file
1
site/templates/default.php
Normal file
1
site/templates/default.php
Normal file
|
|
@ -0,0 +1 @@
|
|||
<h1><?= $page->title() ?></h1>
|
||||
91
site/templates/home.php
Normal file
91
site/templates/home.php
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="<?= $kirby->language()->code() ?>">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<title><?= $site->title() ?> | Index.ngo</title>
|
||||
<link rel="icon" type="image/png" href="<?= url('assets/favicon.png') ?>"/>
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@12/swiper-bundle.min.css" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/swiper@12/swiper-bundle.min.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="<?= url('assets/fonts/stylesheet.css') ?>" />
|
||||
<link rel="stylesheet" type="text/css" href="<?= url('assets/css/style.css') ?>" />
|
||||
</head>
|
||||
<body data-template="store">
|
||||
<header id="site-header">
|
||||
<div class="header-left"></div>
|
||||
|
||||
<div class="header-center">
|
||||
<h1 class="site-title">
|
||||
<a href="<?= $site->url() ?>" aria-label="<?= t('backToHome', 'Retour à l\'accueil') ?>">
|
||||
<svg width="100%" height="100%" viewBox="0 0 162 29" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule: evenodd; clip-rule: evenodd; stroke-linejoin: round; stroke-miterlimit: 2;">
|
||||
<title>Index.ngo</title>
|
||||
<g transform="matrix(1.04516,0,0,0.659091,57.4839,-6.59091)">
|
||||
<rect x="-55" y="10" width="155" height="44" style="fill: none" />
|
||||
<clipPath id="_clip1">
|
||||
<rect x="-55" y="10" width="155" height="44" />
|
||||
</clipPath>
|
||||
<g clip-path="url(#_clip1)">
|
||||
<g transform="matrix(0.95679,0,0,1.51724,-55,10)">
|
||||
<path d="M162,29L148.198,29L141.174,20.767L134.15,29L91.184,29L91.184,0.004L120.653,0.004L120.653,7.351L102.637,7.351L102.637,10.867L120.137,10.867L120.137,18.13L102.637,18.13L102.637,21.606L120.926,21.606L120.926,28.951L134.273,14.414L120.807,0L134.56,0L141.388,7.767L147.76,0L161.201,0L148.236,13.79L161.996,28.997L162,29ZM68.58,29L54.224,29L54.224,0.004L68.637,0.004C74.672,0.004 78.31,0.004 82.046,2.045C86.259,4.379 88.674,8.889 88.674,14.417C88.674,19.406 86.862,23.405 83.427,25.975C79.463,29 75.345,29 68.58,29ZM49.819,29L38.775,29L31.499,19.815C29.746,17.735 28.088,15.545 27.307,14.495C27.387,15.813 27.524,17.238 27.524,20.499L27.524,29L15.965,29L15.965,0.004L27.009,0.004L33.798,8.349C36.223,11.121 37.709,12.993 38.393,13.881C38.347,12.615 38.26,9.911 38.26,6.84L38.26,0.004L49.819,0.004L49.819,29ZM11.559,29L0,29L0,0.004L11.559,0.004L11.559,29ZM65.784,21.818L67.904,21.818C70.918,21.818 73.067,21.818 74.728,20.531C76.074,19.491 76.845,17.308 76.845,14.541C76.845,11.526 76.084,9.541 74.525,8.476C72.895,7.411 71.461,7.224 67.578,7.224L65.784,7.224L65.784,21.818Z" style="fill-rule: nonzero" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="header-right">
|
||||
<ul id="toggle-lang">
|
||||
<?php foreach($kirby->languages() as $language): ?>
|
||||
<li<?= $kirby->language() == $language ? ' class="is-selected"' : '' ?>>
|
||||
<a href="<?= $page->url($language->code()) ?>"><?= $language->code() === 'fr' ? 'Fr' : 'En' ?></a>
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<p class="p__baseline-big">
|
||||
<?= $page->baseline()->or('Bienvenue sur la boutique de soutien à Index') ?>
|
||||
</p>
|
||||
|
||||
<section id="store__container">
|
||||
<?php foreach($site->children()->listed() as $product): ?>
|
||||
<article class="store__product">
|
||||
<figure>
|
||||
<?php if($image = $product->images()->first()): ?>
|
||||
<img src="<?= $image->url() ?>" alt="<?= $product->title()->html() ?>" />
|
||||
<?php endif ?>
|
||||
</figure>
|
||||
<p class="line-1"><a href="<?= $product->url() ?>"><?= $product->title()->html() ?></a></p>
|
||||
<p class="price"><?= $product->price() ?>€</p>
|
||||
<a href="<?= $product->url() ?>" class="link-block" aria-hidden="true"></a>
|
||||
</article>
|
||||
<?php endforeach ?>
|
||||
</section>
|
||||
|
||||
<p class="p__baseline-big">
|
||||
<?= t('supportText', 'Pour nous soutenir, vous pouvez aussi') ?>
|
||||
<a href="https://soutenir.index.ngo" class="link-don"><?= t('makeDonation', 'faire un don') ?></a>
|
||||
</p>
|
||||
</main>
|
||||
|
||||
<footer id="site-footer">
|
||||
<div class="site-footer__container">
|
||||
<div class="footer__mentions">
|
||||
<p class="p__small">
|
||||
© <?= date('Y') ?> Index Investigation |
|
||||
<a target="_blank" href="https://www.index.ngo/mentions-legales/">Mentions légales</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="<?= url('assets/js/onload.js') ?>"></script>
|
||||
</body>
|
||||
</html>
|
||||
143
site/templates/product.php
Normal file
143
site/templates/product.php
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="<?= $kirby->language()->code() ?>">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<title><?= $page->title() ?> | Index.ngo</title>
|
||||
<link rel="icon" type="image/png" href="<?= url('assets/favicon.png') ?>"/>
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@12/swiper-bundle.min.css" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/swiper@12/swiper-bundle.min.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="<?= url('assets/fonts/stylesheet.css') ?>" />
|
||||
<link rel="stylesheet" type="text/css" href="<?= url('assets/css/style.css') ?>" />
|
||||
</head>
|
||||
<body data-template="shop">
|
||||
<header id="site-header">
|
||||
<div class="header-left"></div>
|
||||
|
||||
<div class="header-center">
|
||||
<h1 class="site-title">
|
||||
<a href="<?= $site->url() ?>" aria-label="<?= t('backToHome', 'Retour à l\'accueil') ?>">
|
||||
<svg width="100%" height="100%" viewBox="0 0 162 29" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule: evenodd; clip-rule: evenodd; stroke-linejoin: round; stroke-miterlimit: 2;">
|
||||
<title>Index.ngo</title>
|
||||
<g transform="matrix(1.04516,0,0,0.659091,57.4839,-6.59091)">
|
||||
<rect x="-55" y="10" width="155" height="44" style="fill: none" />
|
||||
<clipPath id="_clip1">
|
||||
<rect x="-55" y="10" width="155" height="44" />
|
||||
</clipPath>
|
||||
<g clip-path="url(#_clip1)">
|
||||
<g transform="matrix(0.95679,0,0,1.51724,-55,10)">
|
||||
<path d="M162,29L148.198,29L141.174,20.767L134.15,29L91.184,29L91.184,0.004L120.653,0.004L120.653,7.351L102.637,7.351L102.637,10.867L120.137,10.867L120.137,18.13L102.637,18.13L102.637,21.606L120.926,21.606L120.926,28.951L134.273,14.414L120.807,0L134.56,0L141.388,7.767L147.76,0L161.201,0L148.236,13.79L161.996,28.997L162,29ZM68.58,29L54.224,29L54.224,0.004L68.637,0.004C74.672,0.004 78.31,0.004 82.046,2.045C86.259,4.379 88.674,8.889 88.674,14.417C88.674,19.406 86.862,23.405 83.427,25.975C79.463,29 75.345,29 68.58,29ZM49.819,29L38.775,29L31.499,19.815C29.746,17.735 28.088,15.545 27.307,14.495C27.387,15.813 27.524,17.238 27.524,20.499L27.524,29L15.965,29L15.965,0.004L27.009,0.004L33.798,8.349C36.223,11.121 37.709,12.993 38.393,13.881C38.347,12.615 38.26,9.911 38.26,6.84L38.26,0.004L49.819,0.004L49.819,29ZM11.559,29L0,29L0,0.004L11.559,0.004L11.559,29ZM65.784,21.818L67.904,21.818C70.918,21.818 73.067,21.818 74.728,20.531C76.074,19.491 76.845,17.308 76.845,14.541C76.845,11.526 76.084,9.541 74.525,8.476C72.895,7.411 71.461,7.224 67.578,7.224L65.784,7.224L65.784,21.818Z" style="fill-rule: nonzero" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="header-right">
|
||||
<ul id="toggle-lang">
|
||||
<?php foreach($kirby->languages() as $language): ?>
|
||||
<li<?= $kirby->language() == $language ? ' class="is-selected"' : '' ?>>
|
||||
<a href="<?= $page->url($language->code()) ?>"><?= $language->code() === 'fr' ? 'Fr' : 'En' ?></a>
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<nav class="store__nav">
|
||||
<a href="<?= $site->homePage()->url() ?>"><?= t('backToShop', 'Retour à la boutique') ?></a>
|
||||
</nav>
|
||||
|
||||
<section class="section__product">
|
||||
<div class="col-left">
|
||||
<div class="hero">
|
||||
<h2 class="p__baseline-big"><?= $page->title()->html() ?></h2>
|
||||
<p class="p__baseline-big"><?= $page->price() ?>€</p>
|
||||
</div>
|
||||
|
||||
<div class="details">
|
||||
<?php if($page->details()->isNotEmpty()): ?>
|
||||
<?= $page->details()->toBlocks() ?>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
<?php if($page->hasOptions()->toBool() && $page->optionValues()->isNotEmpty()): ?>
|
||||
<div class="product-options">
|
||||
<ul class="product-options__list">
|
||||
<?php
|
||||
$values = $page->optionValues()->split(',');
|
||||
$optionSlug = $page->optionLabel()->slug();
|
||||
foreach($values as $index => $value):
|
||||
$value = trim($value);
|
||||
$uniqueId = $optionSlug . '-' . Str::slug(strtolower($value));
|
||||
?>
|
||||
<li>
|
||||
<input type="radio" id="<?= $uniqueId ?>" name="<?= $optionSlug ?>" value="<?= $value ?>" />
|
||||
<label for="<?= $uniqueId ?>"><?= $value ?></label>
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<div class="add-to-cart">
|
||||
<button
|
||||
class="btn__default snipcart-add-item"
|
||||
data-item-id="<?= $page->slug() ?>"
|
||||
data-item-price="<?= $page->price() ?>"
|
||||
data-item-description="<?= $page->description()->excerpt(100) ?>"
|
||||
data-item-image="<?= $page->images()->first() ? $page->images()->first()->url() : '' ?>"
|
||||
data-item-name="<?= $page->title()->html() ?>"
|
||||
data-item-url="<?= $page->url() ?>/validate.json"
|
||||
<?php
|
||||
if($page->hasOptions()->toBool() && $page->optionValues()->isNotEmpty()):
|
||||
$values = $page->optionValues()->split(',');
|
||||
$trimmedValues = array_map('trim', $values);
|
||||
$snipcartOptions = implode('|', $trimmedValues);
|
||||
?>
|
||||
data-item-custom1-name="<?= $page->optionLabel()->html() ?>"
|
||||
data-item-custom1-options="<?= $snipcartOptions ?>"
|
||||
data-item-custom1-required="true"
|
||||
disabled
|
||||
<?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">
|
||||
<path d="m14.523 18.787s4.501-4.505 6.255-6.26c.146-.146.219-.338.219-.53s-.073-.383-.219-.53c-1.753-1.754-6.255-6.258-6.255-6.258-.144-.145-.334-.217-.524-.217-.193 0-.385.074-.532.221-.293.292-.295.766-.004 1.056l4.978 4.978h-14.692c-.414 0-.75.336-.75.75s.336.75.75.75h14.692l-4.979 4.979c-.289.289-.286.762.006 1.054.148.148.341.222.533.222.19 0 .378-.072.522-.215z" fill-rule="nonzero" />
|
||||
</svg>
|
||||
</span>
|
||||
<div class="txt"><?= t('addToCart', 'Ajouter au panier') ?></div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<figure>
|
||||
<?php if($image = $page->images()->first()): ?>
|
||||
<img src="<?= $image->url() ?>" alt="<?= $page->title()->html() ?>" />
|
||||
<?php endif ?>
|
||||
</figure>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer id="site-footer">
|
||||
<div class="site-footer__container">
|
||||
<div class="footer__mentions">
|
||||
<p class="p__small">
|
||||
© <?= date('Y') ?> Index Investigation |
|
||||
<a target="_blank" href="https://www.index.ngo/mentions-legales/">Mentions légales</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="<?= url('assets/js/onload.js') ?>"></script>
|
||||
<script src="<?= url('assets/js/product-size.js') ?>"></script>
|
||||
<script src="<?= url('assets/js/snipcart.js') ?>"></script>
|
||||
</body>
|
||||
</html>
|
||||
46
site/templates/validate.json.php
Normal file
46
site/templates/validate.json.php
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
// Template pour valider les produits avec Snipcart
|
||||
// Ce fichier sera appelé par Snipcart pour valider le stock avant l'ajout au panier
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$product = $page;
|
||||
|
||||
// Vérifier que c'est bien une page produit
|
||||
if ($product->intendedTemplate() !== 'product') {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Product not found']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Récupérer le stock actuel
|
||||
$stock = (int) $product->stock()->value();
|
||||
|
||||
// Préparer la réponse JSON pour Snipcart
|
||||
$response = [
|
||||
'id' => $product->slug(),
|
||||
'price' => (float) $product->price()->value(),
|
||||
'url' => $product->url() . '/validate.json',
|
||||
'name' => $product->title()->value(),
|
||||
'description' => $product->description()->value(),
|
||||
'image' => $product->images()->first() ? $product->images()->first()->url() : '',
|
||||
'inventory' => $stock,
|
||||
'stock' => $stock
|
||||
];
|
||||
|
||||
// Ajouter les options si disponibles
|
||||
if ($product->hasOptions()->toBool() && $product->optionValues()->isNotEmpty()) {
|
||||
$values = $product->optionValues()->split(',');
|
||||
$trimmedValues = array_map('trim', $values);
|
||||
$snipcartOptions = implode('|', $trimmedValues);
|
||||
|
||||
$response['customFields'] = [
|
||||
[
|
||||
'name' => $product->optionLabel()->value(),
|
||||
'options' => $snipcartOptions,
|
||||
'required' => true
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
Loading…
Add table
Add a link
Reference in a new issue