Files
novaconium/novaconium/bin/create-static-page.php
T
code fbd4e92e9f Replace v1 with v2 codebase
Full rewrite: swap out the v1 framework (src/, controllers/, views/,
twig/, sass/, skeleton/) for the working v2 codebase from phpproject
(App/, novaconium/, public/).
2026-07-14 01:58:25 +00:00

99 lines
3.4 KiB
PHP

<?php
/**
* Scaffolds a new static page from the same copy-paste starter template
* documented at /admin/docs/seo, so adding a page doesn't require manually
* copying it by hand.
*
* Usage:
* php novaconium/bin/create-static-page.php <path>
*
* <path> is relative to App/pages/ and becomes the route — with or
* without a trailing index.twig/.twig, so any of these are equivalent:
* php novaconium/bin/create-static-page.php pricing
* php novaconium/bin/create-static-page.php blog/my-new-post
* php novaconium/bin/create-static-page.php blog/my-new-post.twig
* php novaconium/bin/create-static-page.php blog/my-new-post/index.twig
*
* Creates App/pages/<path>/index.twig and nothing else — no sidecar, since
* the point of this template is a sidecar-less, statically-cacheable page
* (see /admin/docs/caching). Add an index.php next to it yourself if the
* page ends up needing one (see /admin/docs/sidecars).
*/
$path = $argv[1] ?? null;
if ($path === null || trim($path) === '') {
fwrite(STDERR, "Usage: php novaconium/bin/create-static-page.php <path>\n");
fwrite(STDERR, "Example: php novaconium/bin/create-static-page.php blog/my-new-post\n");
exit(1);
}
// Normalize away a trailing /index.twig or .twig, so the path can be
// passed either as a bare route or as a file-shaped argument.
$path = trim($path, '/');
$path = preg_replace('#/index\.twig$#', '', $path);
$path = preg_replace('#\.twig$#', '', $path);
if ($path === '') {
fwrite(STDERR, "Error: path cannot be empty.\n");
exit(1);
}
// Reserved segments (see Router::resolve()) can never be routed to
// directly — refuse to scaffold a page nothing could ever visit.
foreach (explode('/', $path) as $segment) {
if ($segment === '' || str_starts_with($segment, '_') || $segment === '404') {
fwrite(STDERR, "Error: \"$segment\" is a reserved path segment (starts with _, or is literally \"404\") and can never be routed to directly.\n");
exit(1);
}
}
$pageDir = __DIR__ . '/../../App/pages/' . $path;
$templateFile = $pageDir . '/index.twig';
if (is_file($templateFile)) {
fwrite(STDERR, "Error: $templateFile already exists — not overwriting.\n");
exit(1);
}
if (!is_dir($pageDir) && !mkdir($pageDir, 0775, true) && !is_dir($pageDir)) {
fwrite(STDERR, "Error: could not create directory $pageDir\n");
exit(1);
}
// "my-new-post" -> "My New Post", used to pre-fill the title/heading.
$title = ucwords(str_replace(['-', '_'], ' ', basename($path)));
$template = <<<TWIG
{% extends layout %}
{% block title %}$title{% endblock %}
{% block description %}One or two sentences describing this page.{% endblock %}
{% block robots %}index, follow{% endblock %}
{% block canonical %}{{ request_path|default('/') }}{% endblock %}
{% block og_type %}website{% endblock %}
{% block og_title %}{{ block('title') }}{% endblock %}
{% block og_description %}{{ block('description') }}{% endblock %}
{% block og_url %}{{ block('canonical') }}{% endblock %}
{% block twitter_card %}summary{% endblock %}
{% block twitter_title %}{{ block('title') }}{% endblock %}
{% block twitter_description %}{{ block('description') }}{% endblock %}
{% block content %}
<article>
<h1>$title</h1>
<p>...</p>
</article>
{% endblock %}
TWIG;
file_put_contents($templateFile, $template);
echo "Created $templateFile\n";
echo "Visit it at /$path once you fill in the content.\n";