What's on this page
Extend Cecil
Because Cecil is written in PHP, it's easy to extend its capabilities.
Custom classes are autoloaded from the extensions directory of your site (or of a theme): the class Cecil\Generator\MyGenerator is loaded from extensions/Cecil/Generator/MyGenerator.php.
Page generators
A generator helps you create pages without Markdown files (for example, with data from an API or a database) or alter existing pages.
Create a new PHP class in the Cecil\Generator namespace, extending AbstractGenerator, and add the class name to the pages.generators list.
Generators are run in ascending order of their key (priority). Built-in generators use the keys 10 to 90: use another key, otherwise the built-in generator is replaced.
Example:
/extensions/Cecil/Generator/DummyPage.php
<?php
namespace Cecil\Generator;
use Cecil\Collection\Page\Page;
use Cecil\Collection\Page\Type;
class DummyPage extends AbstractGenerator implements GeneratorInterface
{
public function generate(): void
{
// create a new page $page, then add it to the site collection
$page = (new Page('my-page'))
->setType(Type::PAGE)
->setPath('mypage')
->setBodyHtml('<p>My page body</p>')
->setVariable('language', 'en')
->setVariable('title', 'My page')
->setVariable('date', new \DateTime())
->setVariable('menu', ['main' => ['weight' => 99]]);
$this->generatedPages->add($page);
}
}
/extensions/Cecil/Generator/Database.php
<?php
namespace Cecil\Generator;
use Cecil\Collection\Page\Page;
use Cecil\Collection\Page\Type;
class Database extends AbstractGenerator implements GeneratorInterface
{
public function generate(): void
{
// create pages from a SQLite database
$db = new \SQLite3('database.sqlite');
$statement = $db->prepare('SELECT * FROM blog');
$result = $statement->execute();
while ($row = $result->fetchArray(\SQLITE3_ASSOC)) {
$page = (new Page($row['page-id']))
->setType(Type::PAGE)
->setPath($row['path'])
->setBodyHtml($row['html'])
->setVariable('title', $row['title'])
->setVariable('date', $row['date']);
$this->generatedPages->add($page);
}
$result->finalize();
$db->close();
}
}
configuration
pages:
generators:
# priority: class name
99: Cecil\Generator\DummyPage
35: Cecil\Generator\Database
Twig extension
You can add custom functions and filters:
- create a Twig extension in the
Cecil\Renderer\Extensionnamespace - add the PHP file in the
extensionsdirectory - add the class name to the
layouts.extensionsconfiguration
The extension constructor receives the Cecil\Builder instance, which gives access to the configuration and the site content.
Example:
/extensions/Cecil/Renderer/Extension/MyTwigExtension.php
<?php
namespace Cecil\Renderer\Extension;
class MyTwigExtension extends \Twig\Extension\AbstractExtension
{
public function getFilters(): array
{
// add a new filter named 'md5'
return [
new \Twig\TwigFilter('md5', 'md5'),
];
}
}
configuration
layouts:
extensions:
MyExtension: Cecil\Renderer\Extension\MyTwigExtension
Output post-processors
You can post-process the rendered output of pages.
Create a new PHP class in the Cecil\Renderer\PostProcessor namespace, extending AbstractPostProcessor, and add the class name to the output.postprocessors list.
Built-in post-processors (GeneratorMetaTag, HtmlExcerpt and MarkdownLink) are run first.
Example:
/extensions/Cecil/Renderer/PostProcessor/MyProcessor.php
<?php
namespace Cecil\Renderer\PostProcessor;
use Cecil\Collection\Page\Page;
class MyProcessor extends AbstractPostProcessor
{
public function process(Page $page, string $output, string $format): string
{
// add a meta tag to the head of the HTML output
if ($format == 'html') {
if (!preg_match('/<meta name="test".*/i', $output)) {
$meta = '<meta name="test" content="Test">';
$output = preg_replace_callback('/([[:blank:]]*)(<\/head>)/i', function ($matches) use ($meta) {
return str_repeat($matches[1] ?: ' ', 2) . $meta . "\n" . $matches[1] . $matches[2];
}, $output);
}
}
return $output;
}
}
configuration
output:
postprocessors:
MyProcessor: Cecil\Renderer\PostProcessor\MyProcessor