isEmpty()) { return null; } $file = $field->toFile(); if ($file) { return $file->url(); } return null; } /** * Résout les images dans le contenu HTML */ function resolveImagesInHtml($html, $page) { if (!$html) return $html; // Remplacer les références file:// par les URLs réelles return preg_replace_callback( '/file:\/\/([a-z0-9]+)/i', function($matches) use ($page) { $uuid = $matches[1]; $file = $page->file("file://{$uuid}"); if (!$file) { // Chercher dans les fichiers du site $file = site()->file("file://{$uuid}"); } return $file ? $file->url() : $matches[0]; }, $html ); } /** * Parse les blocks Kirby en structure JSON */ function parseBlocks($blocksField, $page) { if (!$blocksField || $blocksField->isEmpty()) { return []; } $blocks = []; foreach ($blocksField->toBlocks() as $block) { $blockData = [ 'id' => $block->id(), 'type' => $block->type(), 'isHidden' => $block->isHidden(), ]; switch ($block->type()) { case 'text': $blockData['content'] = [ 'text' => resolveImagesInHtml($block->text()->value(), $page) ]; break; case 'heading': $blockData['content'] = [ 'level' => $block->level()->value() ?? 'h2', 'text' => $block->text()->value() ]; break; case 'image': $image = $block->image()->toFile(); $blockData['content'] = [ 'url' => $image ? $image->url() : null, 'alt' => $block->alt()->value() ?? '', 'caption' => $block->caption()->value() ?? '', 'width' => $block->width()->value() ?? '100%', 'position' => $block->position()->value() ?? 'auto' ]; break; case 'list': $blockData['content'] = [ 'text' => $block->text()->value() ]; break; case 'quote': $blockData['content'] = [ 'text' => $block->text()->value(), 'citation' => $block->citation()->value() ?? '' ]; break; case 'video': $blockData['content'] = [ 'url' => $block->url()->value(), 'caption' => $block->caption()->value() ?? '' ]; break; case 'map': $mapPage = $block->map()->toPages()->first(); if ($mapPage) { $blockData['content'] = parseMap($mapPage); } else { $blockData['content'] = [ 'map' => $block->map()->value() ]; } break; default: $blockData['content'] = $block->content()->toArray(); } $blocks[] = $blockData; } return $blocks; } /** * Parse a chapter */ function parseChapter($chapter) { return [ 'id' => $chapter->id(), 'uuid' => $chapter->uuid()->toString(), 'template' => 'chapter', 'title' => $chapter->title()->value(), 'slug' => $chapter->slug(), 'blocks' => parseBlocks($chapter->text(), $chapter) ]; } /** * Parse a marker */ function parseMarker($marker) { return [ 'title' => $marker->title()->value(), 'cover' => resolveFileUrl($marker->cover(), $marker), 'icon' => $marker->markerIcon()->toFile() ? $marker->markerIcon()->toFile()->url() : null, 'iconSize' => $marker->markerIconSize()->value() ?? 40, 'blocks' => parseBlocks($marker->text(), $marker) ]; } /** * Parse a map */ function parseMap($map) { $markers = []; foreach ($map->children()->listed() as $child) { if ($child->intendedTemplate()->name() === 'marker') { $markers[] = parseMarker($child); } } $staticImage = $map->file('map-static.png'); return [ 'id' => $map->id(), 'uuid' => $map->uuid()->toString(), 'template' => 'carte', 'title' => $map->title()->value(), 'slug' => $map->slug(), 'tags' => $map->tags()->isNotEmpty() ? $map->tags()->split() : [], 'image' => $staticImage ? $staticImage->url() : null, 'intro' => resolveImagesInHtml($map->text()->value(), $map), 'markers' => $markers ]; } /** * Parse un geoformat */ function parseGeoformat($geoformat) { $children = []; foreach ($geoformat->children()->listed() as $child) { $template = $child->intendedTemplate()->name(); if ($template === 'chapter') { $children[] = parseChapter($child); } elseif ($template === 'map') { $children[] = parseMap($child); } } return [ 'id' => $geoformat->id(), 'uuid' => $geoformat->uuid()->toString(), 'template' => 'geoformat', 'title' => $geoformat->title()->value(), 'slug' => $geoformat->slug(), 'subtitle' => $geoformat->subtitle()->value() ?? '', 'tags' => $geoformat->tags()->isNotEmpty() ? $geoformat->tags()->split() : [], 'cover' => resolveFileUrl($geoformat->cover(), $geoformat), 'text' => resolveImagesInHtml($geoformat->text()->value(), $geoformat), 'children' => $children ]; } // Build JSON response $data = [ 'id' => $page->id(), 'uuid' => $page->uuid()->toString(), 'template' => 'narrative', 'title' => $page->title()->value(), 'slug' => $page->slug(), 'author' => $page->author()->value() ?? '', 'cover' => resolveFileUrl($page->cover(), $page), 'introduction' => resolveImagesInHtml($page->introduction()->value(), $page), 'customCss' => $page->customCss()->value() ?? '', 'modified' => $page->modified(), 'modifiedFormatted' => $page->modified('d/m/Y H:i'), 'children' => [] ]; // Parse children (geoformats and maps) foreach ($page->children()->listed() as $child) { $template = $child->intendedTemplate()->name(); if ($template === 'geoformat') { $data['children'][] = parseGeoformat($child); } elseif ($template === 'map') { $data['children'][] = parseMap($child); } } echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);