{
  "version": "https://jsonfeed.org/version/1.1",
  "title": "Cecil - Développeurs",
  "home_page_url": "https://cecil.app/fr/documentation/developpeurs/",
  "feed_url": "https://cecil.app/fr/documentation/developpeurs/feed.json",
  "description": "Étendez Cecil avec PHP, utilisez-le comme bibliothèque et comprenez son architecture.",
  "icon": "https://cecil.app/favicon.7ff4b89eec6dad139a7d2d6561543285.png",
  "favicon": "https://cecil.app/thumbnails/64x/favicon.7ff4b89eec6dad139a7d2d6561543285.png",
  "language": "fr",
  "items": [
    {
      "id": "https://cecil.app/fr/documentation/developpeurs/architecture/",
      "url": "https://cecil.app/fr/documentation/developpeurs/architecture/",
      "title": "Architecture",
      "summary": "Diagramme du processus de génération et composants clés.",
      "date_published": "2026-05-27T00:00:00+00:00",
      "date_modified": "2026-10-02T00:00:00+00:00","content_text": "Architecture\nDiagramme\ngraph TD\n    %% Entrée\n    CLI[\"bin\/cecil\\n(Point d'entrée CLI)\"]\n    APP[\"Application\\n(Symfony Console)\"]\n    CMD[\"Commandes\\nbuild \/ serve \/ new:site\\nnew:page \/ clear \/ show:content\"]\n\n    CLI --&gt; APP --&gt; CMD\n\n    %% Orchestrateur\n    BUILDER[\"Builder\\n(Orchestrateur)\"]\n    CONFIG[\"Configuration\\n(config.yml + default.php\\n+ thèmes)\"]\n    CMD --&gt; BUILDER\n    CONFIG --&gt; BUILDER\n\n    %% Pipeline\n    subgraph PIPELINE[\"Pipeline de génération (étapes)\"]\n        S1[\"1. Pages\/Load\\n(Finder → fichiers Markdown)\"]\n        S2[\"2. Data\/Load\\n(fichiers YAML)\"]\n        S3[\"3. StaticFiles\/Load\\n(chargement des fichiers statiques)\"]\n        S4[\"4. Pages\/Create\\n(création des objets Page)\"]\n        S5[\"5. Pages\/Convert\\n(Markdown → HTML\\nfront matter)\"]\n        S6[\"6. Taxonomies\/Create\\n(création des taxonomies)\"]\n        S7[\"7. Pages\/Generate\\n(générateurs)\"]\n        S8[\"8. Menus\/Create\\n(création des menus)\"]\n        S9[\"9. StaticFiles\/Copy\\n(copie des fichiers statiques)\"]\n        S10[\"10. Pages\/Render\\n(rendu Twig)\"]\n        S11[\"11. Pages\/Save\\n(sauvegarde des pages)\"]\n        S12[\"12. Assets\/Save\\n(sauvegarde des assets)\"]\n        S13[\"13. Optimize\/*\\n(optimisation HTML\/CSS\/JS\/Images)\"]\n\n        S1 --&gt; S2 --&gt; S3 --&gt; S4 --&gt; S5 --&gt; S6 --&gt; S7 --&gt; S8 --&gt; S9 --&gt; S10 --&gt; S11 --&gt; S12 --&gt; S13\n    end\n\n    BUILDER --&gt; PIPELINE\n\n    %% Sous-systèmes\n    subgraph COLLECTIONS[\"Collections\"]\n        PC[\"PagesCollection\\n(objets Page)\"]\n        TC[\"TaxonomiesCollection\\n(vocabulaires\/termes)\"]\n        MC[\"MenusCollection\"]\n    end\n\n    subgraph GENERATORS[\"Générateurs (virtuels)\"]\n        GP[\"Pagination\"]\n        GT[\"Taxonomie\"]\n        GS[\"Section\"]\n        GR[\"Redirection\"]\n        GD[\"DefaultPages (accueil, 404)\"]\n    end\n\n    subgraph RENDERER[\"Rendu Twig\"]\n        TW[\"Moteur Twig\"]\n        EXT[\"Extensions\\n(Core, Content, Collection)\"]\n        PP[\"PostProcessors\\n(métadonnées, extraits, liens)\"]\n        TH[\"Thèmes \/ Layouts\"]\n        TW --&gt; EXT\n        TW --&gt; PP\n        TH --&gt; TW\n    end\n\n    subgraph ASSETS[\"Assets\"]\n        AL[\"Localisateur d'assets\"]\n        AC[\"Compilateur\\n(SCSS → CSS)\"]\n        AI[\"Processeur d'images\\n(responsive, WebP, AVIF)\"]\n        AO[\"Optimiseur\\n(minification CSS\/JS)\"]\n    end\n\n    subgraph OUTPUT[\"Sortie (_site\/)\"]\n        HTML[\"pages .html\"]\n        CSS2[\"assets CSS\/JS\"]\n        IMG[\"images\"]\n        SF[\"fichiers statiques\"]\n    end\n\n    S4 --&gt; PC\n    S6 --&gt; TC\n    S8 --&gt; MC\n    S7 --&gt; GENERATORS\n    GENERATORS --&gt; PC\n    S10 --&gt; RENDERER\n    S12 --&gt; ASSETS\n\n    PC --&gt; RENDERER\n    TC --&gt; RENDERER\n    MC --&gt; RENDERER\n\n    RENDERER --&gt; S11\n    S11 --&gt; HTML\n    S12 --&gt; CSS2\n    S12 --&gt; IMG\n    S9 --&gt; SF\n\n    %% Entrées\n    subgraph INPUT[\"Sources\"]\n        MD[\"content\/\\n(Markdown + front matter)\"]\n        DATA[\"data\/\\n(YAML)\"]\n        STATIC[\"static\/\"]\n        LAYOUTS[\"layouts\/\\n(modèles Twig)\"]\n    end\n\n    MD --&gt; S1\n    DATA --&gt; S2\n    STATIC --&gt; S3\n    LAYOUTS --&gt; TH\nLégende des composants clés\n\n\n\nComposant\nRôle\n\n\n\n\nBuilder\nOrchestrateur central, exécute les étapes en séquence\n\n\nConfig\nFusion de la configuration par défaut + thème + projet + CLI\n\n\nSteps\nPipeline modulaire (13 étapes), chacune avec init() \/ canProcess() \/ process()\n\n\nCollections\nPages, Taxonomies, Menus — structures de données centrales\n\n\nGenerators\nCréent des pages virtuelles (pagination, tags, redirections…)\n\n\nRenderer (Twig)\nApplique les modèles + extensions + post-traitements\n\n\nAssets\nCompile SCSS, optimise images, fingerprinte les fichiers\n\n\n",
      "content_html": "<h1>Architecture</h1>\n<h2 id=\"diagramme\">Diagramme</h2>\n<pre><code class=\"language-mermaid\" translate=\"no\">graph TD\n    %% Entrée\n    CLI[\"bin/cecil\\n(Point d'entrée CLI)\"]\n    APP[\"Application\\n(Symfony Console)\"]\n    CMD[\"Commandes\\nbuild / serve / new:site\\nnew:page / clear / show:content\"]\n\n    CLI --&gt; APP --&gt; CMD\n\n    %% Orchestrateur\n    BUILDER[\"Builder\\n(Orchestrateur)\"]\n    CONFIG[\"Configuration\\n(config.yml + default.php\\n+ thèmes)\"]\n    CMD --&gt; BUILDER\n    CONFIG --&gt; BUILDER\n\n    %% Pipeline\n    subgraph PIPELINE[\"Pipeline de génération (étapes)\"]\n        S1[\"1. Pages/Load\\n(Finder → fichiers Markdown)\"]\n        S2[\"2. Data/Load\\n(fichiers YAML)\"]\n        S3[\"3. StaticFiles/Load\\n(chargement des fichiers statiques)\"]\n        S4[\"4. Pages/Create\\n(création des objets Page)\"]\n        S5[\"5. Pages/Convert\\n(Markdown → HTML\\nfront matter)\"]\n        S6[\"6. Taxonomies/Create\\n(création des taxonomies)\"]\n        S7[\"7. Pages/Generate\\n(générateurs)\"]\n        S8[\"8. Menus/Create\\n(création des menus)\"]\n        S9[\"9. StaticFiles/Copy\\n(copie des fichiers statiques)\"]\n        S10[\"10. Pages/Render\\n(rendu Twig)\"]\n        S11[\"11. Pages/Save\\n(sauvegarde des pages)\"]\n        S12[\"12. Assets/Save\\n(sauvegarde des assets)\"]\n        S13[\"13. Optimize/*\\n(optimisation HTML/CSS/JS/Images)\"]\n\n        S1 --&gt; S2 --&gt; S3 --&gt; S4 --&gt; S5 --&gt; S6 --&gt; S7 --&gt; S8 --&gt; S9 --&gt; S10 --&gt; S11 --&gt; S12 --&gt; S13\n    end\n\n    BUILDER --&gt; PIPELINE\n\n    %% Sous-systèmes\n    subgraph COLLECTIONS[\"Collections\"]\n        PC[\"PagesCollection\\n(objets Page)\"]\n        TC[\"TaxonomiesCollection\\n(vocabulaires/termes)\"]\n        MC[\"MenusCollection\"]\n    end\n\n    subgraph GENERATORS[\"Générateurs (virtuels)\"]\n        GP[\"Pagination\"]\n        GT[\"Taxonomie\"]\n        GS[\"Section\"]\n        GR[\"Redirection\"]\n        GD[\"DefaultPages (accueil, 404)\"]\n    end\n\n    subgraph RENDERER[\"Rendu Twig\"]\n        TW[\"Moteur Twig\"]\n        EXT[\"Extensions\\n(Core, Content, Collection)\"]\n        PP[\"PostProcessors\\n(métadonnées, extraits, liens)\"]\n        TH[\"Thèmes / Layouts\"]\n        TW --&gt; EXT\n        TW --&gt; PP\n        TH --&gt; TW\n    end\n\n    subgraph ASSETS[\"Assets\"]\n        AL[\"Localisateur d'assets\"]\n        AC[\"Compilateur\\n(SCSS → CSS)\"]\n        AI[\"Processeur d'images\\n(responsive, WebP, AVIF)\"]\n        AO[\"Optimiseur\\n(minification CSS/JS)\"]\n    end\n\n    subgraph OUTPUT[\"Sortie (_site/)\"]\n        HTML[\"pages .html\"]\n        CSS2[\"assets CSS/JS\"]\n        IMG[\"images\"]\n        SF[\"fichiers statiques\"]\n    end\n\n    S4 --&gt; PC\n    S6 --&gt; TC\n    S8 --&gt; MC\n    S7 --&gt; GENERATORS\n    GENERATORS --&gt; PC\n    S10 --&gt; RENDERER\n    S12 --&gt; ASSETS\n\n    PC --&gt; RENDERER\n    TC --&gt; RENDERER\n    MC --&gt; RENDERER\n\n    RENDERER --&gt; S11\n    S11 --&gt; HTML\n    S12 --&gt; CSS2\n    S12 --&gt; IMG\n    S9 --&gt; SF\n\n    %% Entrées\n    subgraph INPUT[\"Sources\"]\n        MD[\"content/\\n(Markdown + front matter)\"]\n        DATA[\"data/\\n(YAML)\"]\n        STATIC[\"static/\"]\n        LAYOUTS[\"layouts/\\n(modèles Twig)\"]\n    end\n\n    MD --&gt; S1\n    DATA --&gt; S2\n    STATIC --&gt; S3\n    LAYOUTS --&gt; TH</code></pre>\n<h2 id=\"legende-des-composants-cles\">Légende des composants clés</h2>\n<table>\n<thead>\n<tr>\n<th>Composant</th>\n<th>Rôle</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>Builder</strong></td>\n<td>Orchestrateur central, exécute les étapes en séquence</td>\n</tr>\n<tr>\n<td><strong>Config</strong></td>\n<td>Fusion de la configuration par défaut + thème + projet + CLI</td>\n</tr>\n<tr>\n<td><strong>Steps</strong></td>\n<td>Pipeline modulaire (13 étapes), chacune avec <code translate=\"no\">init()</code> / <code translate=\"no\">canProcess()</code> / <code translate=\"no\">process()</code></td>\n</tr>\n<tr>\n<td><strong>Collections</strong></td>\n<td>Pages, Taxonomies, Menus — structures de données centrales</td>\n</tr>\n<tr>\n<td><strong>Generators</strong></td>\n<td>Créent des pages virtuelles (pagination, tags, redirections…)</td>\n</tr>\n<tr>\n<td><strong>Renderer (Twig)</strong></td>\n<td>Applique les modèles + extensions + post-traitements</td>\n</tr>\n<tr>\n<td><strong>Assets</strong></td>\n<td>Compile SCSS, optimise images, fingerprinte les fichiers</td>\n</tr>\n</tbody>\n</table>",
      "language": "fr"
    },
    {
      "id": "https://cecil.app/fr/documentation/developpeurs/etendre/",
      "url": "https://cecil.app/fr/documentation/developpeurs/etendre/",
      "title": "Étendre",
      "summary": "Créez des générateurs de pages, ajoutez des extensions Twig et post-traitez les fichiers de sortie.",
      "date_published": "2026-03-27T00:00:00+00:00",
      "date_modified": "2026-10-02T00:00:00+00:00","content_text": "Étendre\nComme Cecil repose sur PHP, il est facile d'en étendre les capacités.\nGénérateur de pages\nUn générateur permet de créer des pages sans fichiers Markdown (avec des données provenant d'une API ou d'une base de données, par exemple), ou de modifier des pages existantes.\nCréez simplement une nouvelle classe PHP dans l'espace de noms Cecil\\Generator, puis ajoutez le nom de la classe à la liste pages.generators.\nExemple:\n\/extensions\/Cecil\/Generator\/DummyPage.php\n&lt;?php\nnamespace Cecil\\Generator;\n\nuse Cecil\\Collection\\Page\\Page;\nuse Cecil\\Collection\\Page\\Type;\n\nclass DummyPage extends AbstractGenerator implements GeneratorInterface\n{\n    public function generate(): void\n    {\n        \/\/ create a new page $page, then add it to the site collection\n        $page = (new Page('my-page'))\n            -&gt;setType(Type::PAGE-&gt;value)\n            -&gt;setPath('mypage')\n            -&gt;setBodyHtml('&lt;p&gt;My page body&lt;\/p&gt;')\n            -&gt;setVariable('language', 'en')\n            -&gt;setVariable('title', 'My page')\n            -&gt;setVariable('date', now())\n            -&gt;setVariable('menu', ['main' =&gt; ['weight' =&gt; 99]]);\n        $this-&gt;generatedPages-&gt;add($page);\n    }\n}\n\/extensions\/Cecil\/Generator\/Database.php\n&lt;?php\nnamespace Cecil\\Generator;\n\nuse Cecil\\Collection\\Page\\Page;\nuse Cecil\\Collection\\Page\\Type;\n\nclass Database extends AbstractGenerator implements GeneratorInterface\n{\n    public function generate(): void\n    {\n        \/\/ create pages from a SQLite database\n        $db = new SQLite3('database.sqlite');\n        $statement = $db-&gt;prepare('SELECT * FROM blog');\n        $result = $statement-&gt;execute();\n        while ($row = $result-&gt;fetchArray(SQLITE3_ASSOC)) {\n            $page = (new Page($row['page-id']))\n                -&gt;setType(Type::PAGE-&gt;value)\n                -&gt;setPath($row['path'])\n                -&gt;setBodyHtml($row['html'])\n                -&gt;setVariable('title', $row['title'])\n                -&gt;setVariable('date', $row['date']);\n            $this-&gt;generatedPages-&gt;add($page);\n        }\n        $result-&gt;finalize();\n        $db-&gt;close();\n    }\n}\nconfiguration\npages:\n  generators:\n    # priority: class name\n    99: Cecil\\Generator\\DummyPage\n    35: Cecil\\Generator\\Database\nExtension Twig\nVous pouvez ajouter des fonctions et des filtres personnalisés :\n\ncréez une extension Twig dans l'espace de noms Cecil\\Renderer\\Extension\najoutez le fichier PHP dans le répertoire extensions\najoutez le nom de la classe à la configuration\n\nExemple:\n\/extensions\/Cecil\/Renderer\/Extension\/MyTwigExtension.php\n&lt;?php\nnamespace Cecil\\Renderer\\Extension;\n\nclass MyTwigExtension extends \\Twig\\Extension\\AbstractExtension\n{\n    public function getFilters()\n    {\n        \/\/ add a new filter named 'md5'\n        return [\n            new \\Twig\\TwigFilter('md5', 'md5'),\n        ];\n    }\n}\nconfiguration\nlayouts:\n  extensions:\n    MyExtension: Cecil\\Renderer\\Extension\\MyTwigExtension\nPost-processeur de rendu\nVous pouvez post-traiter le rendu des pages.\nCréez simplement une nouvelle classe PHP dans l'espace de noms Cecil\\Renderer\\PostProcessor et ajoutez le nom de la classe à la liste output.postprocessors.\nExemple:\n\/extensions\/Cecil\/Renderer\/PostProcessor\/MyProcessor.php\n&lt;?php\nnamespace Cecil\\Renderer\\PostProcessor;\n\nuse Cecil\\Collection\\Page\\Page;\n\nclass MyProcessor extends AbstractPostProcessor\n{\n    public function process(Page $page, string $output, string $format): string\n    {\n        \/\/ add a meta tag to the head of the HTML output\n        if ($format == 'html') {\n            if (!preg_match('\/&lt;meta name=\"test\".*\/i', $output)) {\n                $meta = \\sprintf('&lt;meta name=\"test\" content=\"Test\"&gt;');\n                $output = preg_replace_callback('\/([[:blank:]]*)(&lt;\\\/head&gt;)\/i', function ($matches) use ($meta) {\n                    return str_repeat($matches[1] ?: ' ', 2) . $meta . \"\\n\" . $matches[1] . $matches[2];\n                }, $output);\n            }\n        }\n\n        return $output;\n    }\n}\nconfiguration\noutput:\n  postprocessors:\n    MyProcessor: Cecil\\Renderer\\PostProcessor\\MyProcessor",
      "content_html": "<h1>Étendre</h1>\n<p>Comme Cecil repose sur PHP, il est facile d'en étendre les capacités.</p>\n<h2 id=\"generateur-de-pages\">Générateur de pages</h2>\n<p>Un générateur permet de créer des pages sans fichiers Markdown (avec des données provenant d'une API ou d'une base de données, par exemple), ou de modifier des pages existantes.</p>\n<p>Créez simplement une nouvelle classe PHP dans l'espace de noms <code translate=\"no\">Cecil\\Generator</code>, puis ajoutez le nom de la classe à la liste <a href=\"../configuration/25-pages.fr.md#pages-generators\"><code translate=\"no\">pages.generators</code></a>.</p>\n<p><strong>Exemple:</strong></p>\n<p><em>/extensions/Cecil/Generator/DummyPage.php</em></p>\n<pre><code class=\"language-php hljs php\" translate=\"no\"><span class=\"hljs-meta\">&lt;?php</span>\n<span class=\"hljs-keyword\">namespace</span> <span class=\"hljs-title\">Cecil</span>\\<span class=\"hljs-title\">Generator</span>;\n\n<span class=\"hljs-keyword\">use</span> <span class=\"hljs-title\">Cecil</span>\\<span class=\"hljs-title\">Collection</span>\\<span class=\"hljs-title\">Page</span>\\<span class=\"hljs-title\">Page</span>;\n<span class=\"hljs-keyword\">use</span> <span class=\"hljs-title\">Cecil</span>\\<span class=\"hljs-title\">Collection</span>\\<span class=\"hljs-title\">Page</span>\\<span class=\"hljs-title\">Type</span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class</span> <span class=\"hljs-title\">DummyPage</span> <span class=\"hljs-keyword\">extends</span> <span class=\"hljs-title\">AbstractGenerator</span> <span class=\"hljs-keyword\">implements</span> <span class=\"hljs-title\">GeneratorInterface</span>\n</span>{\n    <span class=\"hljs-keyword\">public</span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span> <span class=\"hljs-title\">generate</span><span class=\"hljs-params\">()</span>: <span class=\"hljs-title\">void</span>\n    </span>{\n        <span class=\"hljs-comment\">// create a new page $page, then add it to the site collection</span>\n        $page = (<span class=\"hljs-keyword\">new</span> Page(<span class=\"hljs-string\">'my-page'</span>))\n            -&gt;setType(Type::PAGE-&gt;value)\n            -&gt;setPath(<span class=\"hljs-string\">'mypage'</span>)\n            -&gt;setBodyHtml(<span class=\"hljs-string\">'&lt;p&gt;My page body&lt;/p&gt;'</span>)\n            -&gt;setVariable(<span class=\"hljs-string\">'language'</span>, <span class=\"hljs-string\">'en'</span>)\n            -&gt;setVariable(<span class=\"hljs-string\">'title'</span>, <span class=\"hljs-string\">'My page'</span>)\n            -&gt;setVariable(<span class=\"hljs-string\">'date'</span>, now())\n            -&gt;setVariable(<span class=\"hljs-string\">'menu'</span>, [<span class=\"hljs-string\">'main'</span> =&gt; [<span class=\"hljs-string\">'weight'</span> =&gt; <span class=\"hljs-number\">99</span>]]);\n        <span class=\"hljs-keyword\">$this</span>-&gt;generatedPages-&gt;add($page);\n    }\n}</code></pre>\n<p><em>/extensions/Cecil/Generator/Database.php</em></p>\n<pre><code class=\"language-php hljs php\" translate=\"no\"><span class=\"hljs-meta\">&lt;?php</span>\n<span class=\"hljs-keyword\">namespace</span> <span class=\"hljs-title\">Cecil</span>\\<span class=\"hljs-title\">Generator</span>;\n\n<span class=\"hljs-keyword\">use</span> <span class=\"hljs-title\">Cecil</span>\\<span class=\"hljs-title\">Collection</span>\\<span class=\"hljs-title\">Page</span>\\<span class=\"hljs-title\">Page</span>;\n<span class=\"hljs-keyword\">use</span> <span class=\"hljs-title\">Cecil</span>\\<span class=\"hljs-title\">Collection</span>\\<span class=\"hljs-title\">Page</span>\\<span class=\"hljs-title\">Type</span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class</span> <span class=\"hljs-title\">Database</span> <span class=\"hljs-keyword\">extends</span> <span class=\"hljs-title\">AbstractGenerator</span> <span class=\"hljs-keyword\">implements</span> <span class=\"hljs-title\">GeneratorInterface</span>\n</span>{\n    <span class=\"hljs-keyword\">public</span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span> <span class=\"hljs-title\">generate</span><span class=\"hljs-params\">()</span>: <span class=\"hljs-title\">void</span>\n    </span>{\n        <span class=\"hljs-comment\">// create pages from a SQLite database</span>\n        $db = <span class=\"hljs-keyword\">new</span> SQLite3(<span class=\"hljs-string\">'database.sqlite'</span>);\n        $statement = $db-&gt;prepare(<span class=\"hljs-string\">'SELECT * FROM blog'</span>);\n        $result = $statement-&gt;execute();\n        <span class=\"hljs-keyword\">while</span> ($row = $result-&gt;fetchArray(SQLITE3_ASSOC)) {\n            $page = (<span class=\"hljs-keyword\">new</span> Page($row[<span class=\"hljs-string\">'page-id'</span>]))\n                -&gt;setType(Type::PAGE-&gt;value)\n                -&gt;setPath($row[<span class=\"hljs-string\">'path'</span>])\n                -&gt;setBodyHtml($row[<span class=\"hljs-string\">'html'</span>])\n                -&gt;setVariable(<span class=\"hljs-string\">'title'</span>, $row[<span class=\"hljs-string\">'title'</span>])\n                -&gt;setVariable(<span class=\"hljs-string\">'date'</span>, $row[<span class=\"hljs-string\">'date'</span>]);\n            <span class=\"hljs-keyword\">$this</span>-&gt;generatedPages-&gt;add($page);\n        }\n        $result-&gt;finalize();\n        $db-&gt;close();\n    }\n}</code></pre>\n<p><em>configuration</em></p>\n<pre><code class=\"language-yaml hljs yaml\" translate=\"no\"><span class=\"hljs-attr\">pages:</span>\n  <span class=\"hljs-attr\">generators:</span>\n    <span class=\"hljs-comment\"># priority: class name</span>\n    <span class=\"hljs-attr\">99:</span> <span class=\"hljs-string\">Cecil\\Generator\\DummyPage</span>\n    <span class=\"hljs-attr\">35:</span> <span class=\"hljs-string\">Cecil\\Generator\\Database</span></code></pre>\n<h2 id=\"extension-twig\">Extension Twig</h2>\n<p>Vous pouvez ajouter des <a href=\"../templates/reference/12-functions.fr.md\">fonctions</a> et des <a href=\"../templates/reference/14-filters.fr.md\">filtres</a> personnalisés :</p>\n<ol>\n<li><a href=\"https://twig.symfony.com/doc/advanced.html#creating-an-extension\" target=\"_blank\" rel=\"noopener noreferrer\">créez une extension Twig</a> dans l'espace de noms <code translate=\"no\">Cecil\\Renderer\\Extension</code></li>\n<li>ajoutez le fichier PHP dans le répertoire <code translate=\"no\">extensions</code></li>\n<li>ajoutez le nom de la classe à la configuration</li>\n</ol>\n<p><strong>Exemple:</strong></p>\n<p><em>/extensions/Cecil/Renderer/Extension/MyTwigExtension.php</em></p>\n<pre><code class=\"language-php hljs php\" translate=\"no\"><span class=\"hljs-meta\">&lt;?php</span>\n<span class=\"hljs-keyword\">namespace</span> <span class=\"hljs-title\">Cecil</span>\\<span class=\"hljs-title\">Renderer</span>\\<span class=\"hljs-title\">Extension</span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class</span> <span class=\"hljs-title\">MyTwigExtension</span> <span class=\"hljs-keyword\">extends</span> \\<span class=\"hljs-title\">Twig</span>\\<span class=\"hljs-title\">Extension</span>\\<span class=\"hljs-title\">AbstractExtension</span>\n</span>{\n    <span class=\"hljs-keyword\">public</span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span> <span class=\"hljs-title\">getFilters</span><span class=\"hljs-params\">()</span>\n    </span>{\n        <span class=\"hljs-comment\">// add a new filter named 'md5'</span>\n        <span class=\"hljs-keyword\">return</span> [\n            <span class=\"hljs-keyword\">new</span> \\Twig\\TwigFilter(<span class=\"hljs-string\">'md5'</span>, <span class=\"hljs-string\">'md5'</span>),\n        ];\n    }\n}</code></pre>\n<p><em>configuration</em></p>\n<pre><code class=\"language-yaml hljs yaml\" translate=\"no\"><span class=\"hljs-attr\">layouts:</span>\n  <span class=\"hljs-attr\">extensions:</span>\n    <span class=\"hljs-attr\">MyExtension:</span> <span class=\"hljs-string\">Cecil\\Renderer\\Extension\\MyTwigExtension</span></code></pre>\n<h2 id=\"post-processeur-de-rendu\">Post-processeur de rendu</h2>\n<p>Vous pouvez post-traiter le rendu des pages.</p>\n<p>Créez simplement une nouvelle classe PHP dans l'espace de noms <code translate=\"no\">Cecil\\Renderer\\PostProcessor</code> et ajoutez le nom de la classe à la liste <code translate=\"no\">output.postprocessors</code>.</p>\n<p><strong>Exemple:</strong></p>\n<p><em>/extensions/Cecil/Renderer/PostProcessor/MyProcessor.php</em></p>\n<pre><code class=\"language-php hljs php\" translate=\"no\"><span class=\"hljs-meta\">&lt;?php</span>\n<span class=\"hljs-keyword\">namespace</span> <span class=\"hljs-title\">Cecil</span>\\<span class=\"hljs-title\">Renderer</span>\\<span class=\"hljs-title\">PostProcessor</span>;\n\n<span class=\"hljs-keyword\">use</span> <span class=\"hljs-title\">Cecil</span>\\<span class=\"hljs-title\">Collection</span>\\<span class=\"hljs-title\">Page</span>\\<span class=\"hljs-title\">Page</span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class</span> <span class=\"hljs-title\">MyProcessor</span> <span class=\"hljs-keyword\">extends</span> <span class=\"hljs-title\">AbstractPostProcessor</span>\n</span>{\n    <span class=\"hljs-keyword\">public</span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span> <span class=\"hljs-title\">process</span><span class=\"hljs-params\">(Page $page, string $output, string $format)</span>: <span class=\"hljs-title\">string</span>\n    </span>{\n        <span class=\"hljs-comment\">// add a meta tag to the head of the HTML output</span>\n        <span class=\"hljs-keyword\">if</span> ($format == <span class=\"hljs-string\">'html'</span>) {\n            <span class=\"hljs-keyword\">if</span> (!preg_match(<span class=\"hljs-string\">'/&lt;meta name=\"test\".*/i'</span>, $output)) {\n                $meta = \\sprintf(<span class=\"hljs-string\">'&lt;meta name=\"test\" content=\"Test\"&gt;'</span>);\n                $output = preg_replace_callback(<span class=\"hljs-string\">'/([[:blank:]]*)(&lt;\\/head&gt;)/i'</span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function</span> <span class=\"hljs-params\">($matches)</span> <span class=\"hljs-title\">use</span> <span class=\"hljs-params\">($meta)</span> </span>{\n                    <span class=\"hljs-keyword\">return</span> str_repeat($matches[<span class=\"hljs-number\">1</span>] ?: <span class=\"hljs-string\">' '</span>, <span class=\"hljs-number\">2</span>) . $meta . <span class=\"hljs-string\">\"\\n\"</span> . $matches[<span class=\"hljs-number\">1</span>] . $matches[<span class=\"hljs-number\">2</span>];\n                }, $output);\n            }\n        }\n\n        <span class=\"hljs-keyword\">return</span> $output;\n    }\n}</code></pre>\n<p><em>configuration</em></p>\n<pre><code class=\"language-yaml hljs yaml\" translate=\"no\"><span class=\"hljs-attr\">output:</span>\n  <span class=\"hljs-attr\">postprocessors:</span>\n    <span class=\"hljs-attr\">MyProcessor:</span> <span class=\"hljs-string\">Cecil\\Renderer\\PostProcessor\\MyProcessor</span></code></pre>",
      "language": "fr"
    },
    {
      "id": "https://cecil.app/fr/documentation/developpeurs/bibliotheque/",
      "url": "https://cecil.app/fr/documentation/developpeurs/bibliotheque/",
      "title": "Bibliothèque",
      "summary": "Utilisez Cecil comme bibliothèque PHP : installez-le avec Composer, puis générez et diagnostiquez par programmation.",
      "date_published": "2026-03-27T00:00:00+00:00",
      "date_modified": "2026-10-03T00:00:00+00:00","content_text": "Bibliothèque\nCecil propose une API PHP simple pour générer votre site web.\nVous pouvez consulter la documentation de l'API pour plus de détails.\nInstallation\ncomposer require cecil\/cecil\nSupport de libvips\nPour traiter les images avec libvips (optionnel), installez le driver libvips dans votre projet :\ncomposer require intervention\/image-driver-vips\nCe driver nécessite libvips installé sur le système et l’extension PHP FFI activée.\nSans lui, Cecil utilise Imagick ou GD à la place.\nUtilisation\nConstruction\nConstruisez un nouveau site web avec une configuration personnalisée :\nrequire_once 'vendor\/autoload.php';\n\nuse Cecil\\Builder;\n\n$config = [\n    'title'   =&gt; \"My website\",\n    'baseurl' =&gt; 'https:\/\/domain.tld\/',\n];\n\nBuilder::create($config)-&gt;build();\n\nexec('php -S localhost:8000 -t _site'); \/\/ prévisualisation locale\nLe paramètre principal de la méthode create doit être un array PHP ou une instance de Cecil\\Config.\nDiagnostic\nVous pouvez aussi exécuter les vérifications doctor via des services de domaine dédiés, sans utiliser les commandes CLI.\n&lt;?php\n\nrequire_once 'vendor\/autoload.php';\n\nuse Cecil\\Builder;\nuse Cecil\\Doctor\\SeoDoctor;\nuse Cecil\\Doctor\\SiteDoctor;\n\n$builder = Builder::create(require 'config.php')\n    -&gt;setSourceDir(__DIR__)\n    -&gt;setDestinationDir(__DIR__);\n\n$siteDoctor = new SiteDoctor();\n$diagnosis = $siteDoctor-&gt;diagnose($builder, __DIR__, ['cecil.yml']);\n\n$seoDoctor = new SeoDoctor();\n$seoAudit = $seoDoctor-&gt;audit($builder, [\n    'page' =&gt; '',\n    'include_virtual' =&gt; false,\n]);\n\nvar_dump($diagnosis['errors'], $seoAudit['summary']);",
      "content_html": "<h1>Bibliothèque</h1>\n<p>Cecil propose une API PHP simple pour générer votre site web.</p>\n<p>Vous pouvez consulter la <a href=\"https://cecil.app/documentation/library/api/namespaces/cecil.html\">documentation de l'API</a> pour plus de détails.</p>\n<h2 id=\"installation\">Installation</h2>\n<pre><code class=\"language-bash hljs bash\" translate=\"no\">composer require cecil/cecil</code></pre>\n<h3 id=\"support-de-libvips\">Support de libvips</h3>\n<p>Pour traiter les images avec <a href=\"https://www.libvips.org/\" target=\"_blank\" rel=\"noopener noreferrer\">libvips</a> (optionnel), installez le driver libvips dans votre projet :</p>\n<pre><code class=\"language-bash hljs bash\" translate=\"no\">composer require intervention/image-driver-vips</code></pre>\n<aside class=\"note note-important\"><p>Ce driver nécessite <a href=\"https://www.libvips.org/install.html\" target=\"_blank\" rel=\"noopener noreferrer\">libvips</a> installé sur le système et l’extension PHP <a href=\"https://www.php.net/manual/book.ffi.php\" target=\"_blank\" rel=\"noopener noreferrer\">FFI</a> activée.<br>\nSans lui, Cecil utilise <a href=\"https://www.php.net/manual/book.imagick.php\" target=\"_blank\" rel=\"noopener noreferrer\">Imagick</a> ou <a href=\"https://www.php.net/manual/book.image.php\" target=\"_blank\" rel=\"noopener noreferrer\">GD</a> à la place.</p></aside>\n<h2 id=\"utilisation\">Utilisation</h2>\n<h3 id=\"construction\">Construction</h3>\n<p>Construisez un nouveau site web avec une configuration personnalisée :</p>\n<pre><code class=\"language-php hljs php\" translate=\"no\"><span class=\"hljs-keyword\">require_once</span> <span class=\"hljs-string\">'vendor/autoload.php'</span>;\n\n<span class=\"hljs-keyword\">use</span> <span class=\"hljs-title\">Cecil</span>\\<span class=\"hljs-title\">Builder</span>;\n\n$config = [\n    <span class=\"hljs-string\">'title'</span>   =&gt; <span class=\"hljs-string\">\"My website\"</span>,\n    <span class=\"hljs-string\">'baseurl'</span> =&gt; <span class=\"hljs-string\">'https://domain.tld/'</span>,\n];\n\nBuilder::create($config)-&gt;build();\n\nexec(<span class=\"hljs-string\">'php -S localhost:8000 -t _site'</span>); <span class=\"hljs-comment\">// prévisualisation locale</span></code></pre>\n<aside class=\"note note-info\"><p>Le paramètre principal de la méthode <code translate=\"no\">create</code> doit être un <code translate=\"no\">array</code> PHP ou une instance de <a href=\"https://github.com/Cecilapp/Cecil/blob/main/src/Config.php\" target=\"_blank\" rel=\"noopener noreferrer\"><code translate=\"no\">Cecil\\Config</code></a>.</p></aside>\n<h3 id=\"diagnostic\">Diagnostic</h3>\n<p>Vous pouvez aussi exécuter les vérifications doctor via des services de domaine dédiés, sans utiliser les commandes CLI.</p>\n<pre><code class=\"language-php hljs php\" translate=\"no\"><span class=\"hljs-meta\">&lt;?php</span>\n\n<span class=\"hljs-keyword\">require_once</span> <span class=\"hljs-string\">'vendor/autoload.php'</span>;\n\n<span class=\"hljs-keyword\">use</span> <span class=\"hljs-title\">Cecil</span>\\<span class=\"hljs-title\">Builder</span>;\n<span class=\"hljs-keyword\">use</span> <span class=\"hljs-title\">Cecil</span>\\<span class=\"hljs-title\">Doctor</span>\\<span class=\"hljs-title\">SeoDoctor</span>;\n<span class=\"hljs-keyword\">use</span> <span class=\"hljs-title\">Cecil</span>\\<span class=\"hljs-title\">Doctor</span>\\<span class=\"hljs-title\">SiteDoctor</span>;\n\n$builder = Builder::create(<span class=\"hljs-keyword\">require</span> <span class=\"hljs-string\">'config.php'</span>)\n    -&gt;setSourceDir(<span class=\"hljs-keyword\">__DIR__</span>)\n    -&gt;setDestinationDir(<span class=\"hljs-keyword\">__DIR__</span>);\n\n$siteDoctor = <span class=\"hljs-keyword\">new</span> SiteDoctor();\n$diagnosis = $siteDoctor-&gt;diagnose($builder, <span class=\"hljs-keyword\">__DIR__</span>, [<span class=\"hljs-string\">'cecil.yml'</span>]);\n\n$seoDoctor = <span class=\"hljs-keyword\">new</span> SeoDoctor();\n$seoAudit = $seoDoctor-&gt;audit($builder, [\n    <span class=\"hljs-string\">'page'</span> =&gt; <span class=\"hljs-string\">''</span>,\n    <span class=\"hljs-string\">'include_virtual'</span> =&gt; <span class=\"hljs-keyword\">false</span>,\n]);\n\nvar_dump($diagnosis[<span class=\"hljs-string\">'errors'</span>], $seoAudit[<span class=\"hljs-string\">'summary'</span>]);</code></pre>",
      "language": "fr"
    }
  ]
}
