Fix virtual pages with routes using Page::factory()
All checks were successful
Deploy / Deploy to Production (push) Successful in 6s
All checks were successful
Deploy / Deploy to Production (push) Successful in 6s
Replace page.children:after hook with proper routes implementation. Product pages are now created dynamically via routes that match Shopify handles for both French and English versions. Changes: - Add routes with Page::factory() for virtual product pages - Remove hooks approach (not working) - Clean up old Snipcart webhook routes - Support FR and EN product URLs Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
ade0ed1a67
commit
4489e705b8
2 changed files with 68 additions and 140 deletions
|
|
@ -8,7 +8,9 @@
|
||||||
"Bash(curl:*)",
|
"Bash(curl:*)",
|
||||||
"WebFetch(domain:snipcart.com)",
|
"WebFetch(domain:snipcart.com)",
|
||||||
"Bash(grep:*)",
|
"Bash(grep:*)",
|
||||||
"Bash(npm run build:*)"
|
"Bash(npm run build:*)",
|
||||||
|
"Bash(php test-shopify.php:*)",
|
||||||
|
"WebFetch(domain:getkirby.com)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
require_once __DIR__ . '/shopify.php';
|
require_once __DIR__ . '/shopify.php';
|
||||||
|
|
||||||
|
use Kirby\Cms\Page;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'debug' => true,
|
'debug' => true,
|
||||||
|
|
||||||
|
|
@ -11,6 +13,69 @@ return [
|
||||||
'shopify' => true
|
'shopify' => true
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'routes' => [
|
||||||
|
// French product pages (default)
|
||||||
|
[
|
||||||
|
'pattern' => '(:any)',
|
||||||
|
'action' => function($slug) {
|
||||||
|
// Skip known pages
|
||||||
|
if (in_array($slug, ['home', 'error', 'thanks'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$products = getShopifyProducts();
|
||||||
|
|
||||||
|
foreach ($products as $product) {
|
||||||
|
if ($product['handle'] === $slug) {
|
||||||
|
return Page::factory([
|
||||||
|
'slug' => $product['handle'],
|
||||||
|
'template' => 'product',
|
||||||
|
'parent' => site()->homePage(),
|
||||||
|
'content' => [
|
||||||
|
'title' => $product['title'],
|
||||||
|
'shopifyHandle' => $product['handle'],
|
||||||
|
'uuid' => $product['id']
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not a product, let Kirby handle normally
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
],
|
||||||
|
// English product pages
|
||||||
|
[
|
||||||
|
'pattern' => 'en/(:any)',
|
||||||
|
'action' => function($slug) {
|
||||||
|
// Skip known pages
|
||||||
|
if (in_array($slug, ['home', 'error', 'thanks'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$products = getShopifyProducts();
|
||||||
|
|
||||||
|
foreach ($products as $product) {
|
||||||
|
if ($product['handle'] === $slug) {
|
||||||
|
return Page::factory([
|
||||||
|
'slug' => $product['handle'],
|
||||||
|
'template' => 'product',
|
||||||
|
'parent' => site()->homePage(),
|
||||||
|
'content' => [
|
||||||
|
'title' => $product['title'],
|
||||||
|
'shopifyHandle' => $product['handle'],
|
||||||
|
'uuid' => $product['id']
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not a product, let Kirby handle normally
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
|
||||||
'thumbs' => [
|
'thumbs' => [
|
||||||
'quality' => 85,
|
'quality' => 85,
|
||||||
'format' => 'webp',
|
'format' => 'webp',
|
||||||
|
|
@ -41,143 +106,4 @@ return [
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
'routes' => [
|
|
||||||
// SNIPCART ROUTES - Désactivées, voir assets/snipcart-archive/README.md pour restauration
|
|
||||||
/*
|
|
||||||
[
|
|
||||||
'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',
|
|
||||||
'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'])) {
|
|
||||||
// Impersonate pour avoir les permissions d'écriture
|
|
||||||
kirby()->impersonate('kirby');
|
|
||||||
|
|
||||||
foreach ($order['items'] as $item) {
|
|
||||||
$productId = $item['id'] ?? null;
|
|
||||||
$quantity = $item['quantity'] ?? 0;
|
|
||||||
|
|
||||||
if ($productId && $quantity > 0) {
|
|
||||||
// Trouver le produit par son slug
|
|
||||||
$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
|
|
||||||
try {
|
|
||||||
$product->update([
|
|
||||||
'stock' => $newStock
|
|
||||||
]);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
// Log l'erreur mais continue le traitement
|
|
||||||
error_log('Webhook stock update error: ' . $e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response::json(['status' => 'success'], 200);
|
|
||||||
}
|
|
||||||
]
|
|
||||||
*/
|
|
||||||
],
|
|
||||||
|
|
||||||
'hooks' => [
|
|
||||||
'page.children:after' => function ($children, $page) {
|
|
||||||
if ($page->isHomePage()) {
|
|
||||||
$products = getShopifyProducts();
|
|
||||||
|
|
||||||
foreach ($products as $product) {
|
|
||||||
$children = $children->add([
|
|
||||||
\Kirby\Cms\Page::factory([
|
|
||||||
'slug' => $product['handle'],
|
|
||||||
'template' => 'product',
|
|
||||||
'model' => 'product',
|
|
||||||
'num' => 0,
|
|
||||||
'parent' => $page,
|
|
||||||
'content' => [
|
|
||||||
'title' => $product['title'],
|
|
||||||
'shopifyHandle' => $product['handle']
|
|
||||||
]
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $children;
|
|
||||||
}
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue