Add Snipcart product validation endpoint and improve product gallery
All checks were successful
Deploy / Deploy to Production (push) Successful in 6s

- Add route handler for /validate.json to enable Snipcart product validation
- Update product gallery to display all product images instead of just the first one
- Fix CSS styling for product gallery list items
- Update home page to use first sorted image as product cover

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
isUnknown 2025-12-19 16:39:16 +01:00
parent 44ed53aae0
commit 22afa818f1
6 changed files with 83 additions and 22 deletions

View file

@ -1106,10 +1106,13 @@ body.is-fullscreen {
content: "← "; content: "← ";
} }
.section__product figure { .section__product .product-gallery li {
list-style: none;
}
.section__product .product-gallery figure {
aspect-ratio: 1/1; aspect-ratio: 1/1;
} }
.section__product figure img { .section__product .product-gallery figure img {
width: 100%; width: 100%;
height: 100%; height: 100%;
-o-object-fit: contain; -o-object-fit: contain;

File diff suppressed because one or more lines are too long

View file

@ -22,13 +22,18 @@
} }
.section__product { .section__product {
figure { .product-gallery {
aspect-ratio: 1/1; li {
list-style: none;
}
figure {
aspect-ratio: 1/1;
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: contain; object-fit: contain;
}
} }
} }

View file

@ -37,6 +37,53 @@ return [
], ],
'routes' => [ 'routes' => [
[
'pattern' => '(:any)/validate.json',
'method' => 'GET',
'action' => function ($slug) {
$page = page($slug);
if (!$page || $page->intendedTemplate() !== 'product') {
header('Content-Type: application/json');
http_response_code(404);
echo json_encode(['error' => 'Product not found']);
return;
}
// Récupérer le stock actuel
$stock = (int) $page->stock()->value();
// Préparer la réponse JSON pour Snipcart
$response = [
'id' => $page->slug(),
'price' => (float) $page->price()->value(),
'url' => $page->url() . '/validate.json',
'name' => $page->title()->value(),
'description' => $page->description()->value(),
'image' => $page->images()->first() ? $page->images()->first()->url() : '',
'inventory' => $stock,
'stock' => $stock
];
// Ajouter les options si disponibles
if ($page->hasOptions()->toBool() && $page->optionValues()->isNotEmpty()) {
$values = $page->optionValues()->split(',');
$trimmedValues = array_map('trim', $values);
$snipcartOptions = implode('|', $trimmedValues);
$response['customFields'] = [
[
'name' => $page->optionLabel()->value(),
'options' => $snipcartOptions,
'required' => true
]
];
}
header('Content-Type: application/json');
echo json_encode($response);
}
],
[ [
'pattern' => 'snipcart-webhook', 'pattern' => 'snipcart-webhook',
'method' => 'POST', 'method' => 'POST',

View file

@ -9,9 +9,9 @@
<?php foreach($site->children()->listed() as $product): ?> <?php foreach($site->children()->listed() as $product): ?>
<article class="store__product"> <article class="store__product">
<figure> <figure>
<?php if($image = $product->images()->first()): ?> <?php if($cover = $product->files()->sort()->first()): ?>
<?php snippet('picture', [ <?php snippet('picture', [
'file' => $image, 'file' => $cover,
'alt' => $product->title()->html(), 'alt' => $product->title()->html(),
'preset' => 'product-card', 'preset' => 'product-card',
'size' => 25, 'size' => 25,

View file

@ -68,17 +68,23 @@
</div> </div>
</div> </div>
<figure> <?php if ($page->hasFiles()): ?>
<?php if($image = $page->images()->first()): ?> <ul class="product-gallery">
<?php snippet('picture', [ <?php foreach($page->files()->sort() as $image): ?>
'file' => $image, <li>
'alt' => $page->title()->html(), <figure>
'preset' => 'product-detail', <?php snippet('picture', [
'size' => 50, 'file' => $image,
'lazy' => false 'alt' => $page->title()->html(),
]) ?> 'preset' => 'product-detail',
<?php endif ?> 'size' => 50,
</figure> 'lazy' => false
]) ?>
</figure>
</li>
<?php endforeach ?>
</ul>
<?php endif ?>
</section> </section>
</main> </main>