ilmiont / ardea
Ardea is a minimal static site generator using PHP.
Requires
- php: ^8.1
- erusev/parsedown: ^1.7
Requires (Dev)
- phpstan/phpstan: ^2.1
README
Ardea is a minimal static site generator using PHP. It focuses on the essentials of loading and rendering your site's pages and content. An extendable foundation lets you add custom content discovery mechanisms and template renderers.
Usage
Install Ardea in your project using Composer:
$ composer require ilmiont/ardea
(PHP versions ^8.1 are supported.)
Create an ardea.json
file in your working directory:
{
"content": {
"pages": {
"template": "tpl/page.php",
"items": [
{
"uri": "/index.html",
"title": "Home",
"body": "Welcome to my website."
},
{
"uri": "/about.html",
"title": "About Me",
"body": "I'm a developer."
},
{
"uri": "/contact.html",
"title": "Contact Me",
"body": "You can contact me by email."
}
]
}
}
}
Next create a tpl/page.php
file, again inside your working directory:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><?= $i -> prop("title"); ?></title>
</head>
<body>
<h1><?= $i -> prop("title"); ?></h1>
<p><?= $i -> prop("body"); ?></p>
</body>
</html>
Now you can run Ardea to render your site:
$ vendor/bin/ardea
Your pages will be rendered into build
within your working directory:
$ ls build
about.html contact.html index.html
That's it! This example demonstrates the basics of using Ardea.
Getting Started
Ardea is configured using an ardea.json
file in your working directory. Within this file, the content
property is the most important, as it defines the content items that Ardea will render to create your site.
Each property nested inside content
defines a "content type." Content items within a content type are logically grouped together and rendered with the same template.
The template to use for a content type is defined by the template
property within its definition object. The property's value should be the relative path to a PHP file within your working directory.
When a content type omits the template
property, the default template set in your configuration file will be used instead. See the Configuration section below for more information.
Content items can be added to a content type in several ways. In the example above, content items are defined as static objects within the content type's items
array. Each object is rendered individually and saved to the path given by its uri
property, which is resolved relative to the active output directory.
Static Content Items
Content items can be added to a content type as static objects by defining an items
property on the content type as an array of content objects. Each content object needs a uri
property that defines the path to save that content item's rendered output to, relative to the active output directory.
All other properties of each content item object become item props which are accessible in your template.
An example of static content items is included in the Usage section above.
Markdown Content Items
Ardea has built-in support for rendering on-disk Markdown files. Each Markdown file's name must end with .md
and the file must exhibit a valid Markdown MIME type.
To add Markdown-sourced items to a content type, provide a markdown
property in its configuration object. Supply the path to load the Markdown content items from as the property's value. The path is resolved relative to your working directory.
{
"content": {
"posts": {
"template": "tpl/post.php",
"markdown": "content/blog"
}
}
}
The directory will be recursively searched for valid Markdown files. Each found file will be rendered using the specified template and output to the path it was discovered at, relative to the output directory. For example, using the example configuration above, the Markdown file content/blog/demo-post.md
will be output to content/blog/demo-post.html
within the output directory. You can change the output path URI for a specific Markdown file by supplying a uri
property in its front matter.
The Markdown content loader provides the following template props for each rendered file:
Property | Type | Description |
---|---|---|
file | String | The relative path to the file, within the searched directory root (e.g. 2022/05/01/demo-post.md ). |
filename | String | The name of the file (e.g. demo-post.md ). |
html | String | The Markdown file's content, rendered to HTML. |
markdown | String | The Markdown file's content. |
src | String | The complete relative path to the file, relative to the working directory (e.g. content/blog/2022/05/01/demo-post.md ). |
title | String | The assumed title of the content; this is the first line of the Markdown content, stripped of any tags. |
The Markdown content loader is front matter-aware. Any front matter will be stripped from the markdown
and html
props. Front matter is extracted and made available as key/value props in your template; where a front matter key is the same as one of the properties listed above, the value from the front matter will overwrite that supplied by Ardea.
Ardea uses Parsedown to render Markdown files. You can provide a custom Parsedown instance by manually constructing the MarkdownContentLoader
instance:
use Ardea\MarkdownContentLoader;
use Parsedown;
$markdownLoader = new MarkdownContentLoader(new Parsedown());
Refer to the Writing Extensions section of this guide below for details of how to supply Ardea with your customised content loader instance.
Templates
Ardea defaults to using plain PHP templates which are rendered by the included PhpRenderer
. You can implement your own renderers using the guidance in the Writing Extensions section of this guide below.
When using the default PhpRenderer
, you can access the following variables in your templates:
Variable | Type | Description |
---|---|---|
$i | Ardea\ContentItem | The content item that's being rendered. |
$item | Ardea\Content | Aggregate of the content item that's being rendered and its content type. |
$content | Ardea\ContentCollection | All of the content items that are being rendered. |
$ardea / $config / $props | Ardea\PropStore | The content of your ardea.json file. |
$tpl | String | The path to the template that the content item's being rendered with. |
$dst | String | The path that the content item's rendered output will be saved to. |
$this | Ardea\PhpRenderer | The active renderer instance. |
Refer to the API Reference below for details of the methods available on the content, content collection, and config prop store objects. You'll use these ubiquitously to access your active configuration values and content item properties.
Example: Rendering a list of Markdown-sourced blog posts, ordered by their date
front matter property
ardea.json
{
"content": {
"posts": {
"template": "tpl/post.php",
"markdown": "content/blog"
}
}
}
tpl/post.php
// ...
<?php foreach ($content -> getByContentType("posts") -> sortByContentProp("date") as $post): ?>
<li><a href="<?= $post -> ContentItem -> uri(); ?>"><?= $post -> ContentItem -> prop("title"); ></a></li>
<?php endforeach; ?>
// ...
Example: Accessing a custom configuration property
ardea.json
{
"site": {
"theme": {
"palette": {
"accent": "##bbddff"
}
}
},
"content": {
"pages": {
"template": "tpl/page.php",
"items": [
{
"uri": "/index.html"
}
]
}
}
}
tpl/page.php
// ...
<head>
<meta name="theme-color" content="<?= $props -> prop("site.theme.palette.accent"); ?>">
</head>
// ...
Configuration
All configuration properties are set in your ardea.json
file within the ardea
property:
{
"ardea": {
"template": "tpl/page.php",
"outputDir": "build",
"workDir": "/tmp/my-site"
}
}
Property | Type | Description | Default Value |
---|---|---|---|
ardea.template | String | The path to the template file to render content items with, when their content type doesn't define one (relative to the working directory). | - |
ardea.outputDir | String | The path to output rendered content to, relative to the working directory. | build |
ardea.workDir | String | Path to interpret the working directory as. Only reliable within the Ardea core - content loaders and renderers, including built-in ones, may not currently support it and may use your real working directory instead. | A call to PHP's getcwd() function. |
API Reference
It's recommended you currently refer to the source code to obtain a complete API reference. Inspecting the Content
, ContentCollection
, ContentItem
, ContentItemCollection
, ContentType
, ContentTypeCollection
, ContentTypeDefinition
, HasProps
, and PropStore
objects will inform you how to access content and configuration values within your templates.
When writing extensions, refer primarily to the application entrypoint (ardea
at the root of the repository), and the PropStore
, ContentLoader
, and Renderer
interfaces.
Writing Extensions
Ardea can be extended with new content loaders and renderers.
To write and use your own extensions, create your own entrypoint that constructs an instance of Ardea\Ardea
. The signature is as follows:
namespace Ardea;
final class Ardea {
public function __construct(
protected readonly PropStore $Config,
protected readonly ContentLoaderCollection $ContentLoaders,
protected readonly Renderer $Renderer) {}
}
$Config
- ThisPropStore
instance provides Ardea with its configuration values (i.e.ardea.json
content by default).$ContentLoaders
- TheContentLoader
instances provided here will be used to discover the content to render within each of your content types.Renderer
- ThisRenderer
instance is used by Ardea to render all your content items.
Refer to the standard application entrypoint, ardea
at the root of the repository, for an example of how Ardea's default content loaders and renderer are configured.
Writing a Content Loader
Content loaders add content items to your content types. Ardea ships with support for inline statically defined content items and content items sourced from on-disk Markdown files.
To create a new content loader, implement the ContentLoader
interface and provide an instance as a member in the $ContentLoaders
collection when you construct Ardea.
Renderers
Renderers convert a content item to rendered output. Ardea ships with a default renderer that supports PHP template syntax.
To create a new renderer, implement the Renderer
interface and provide an instance as the $Renderer
parameter when you construct Ardea.
Customising the default renderer
The default PHP template renderer has two constructor parameters:
namespace Ardea;
final class PhpRenderer {
public function __construct(
/**
* Props to make available to templates
*/
protected readonly PropStore $Props,
/**
* Writer instance that saves rendered output
*/
protected readonly Writer $Writer) {}
}
$Props
is made available to your templates as the $ardea
, $config
, and $props
variables.
The Writer
instance supplied as $Writer
is responsible for writing rendered templates to the intended output path. The default writer saves to the local filesystem. You can create your own writers by implementing the Writer
interface.
©James Walker. Licensed under the MIT License.