A small PHP CMS
Declare the content.
The CMS builds the rest.
One file describes a kind of content. From it you get the database table, the admin list, the editor, publishing, revision history and the public routes — with no migration to write and no screens to build.
Read the guides What it is not
Plain PHP 8.1+ and SQLite. No framework, no Composer, no npm, no build step.
The whole idea
One file per kind of content
Save this as app/types/recipe.php and reload any page.
You now have a recipes table, Recipes in the admin menu, a list screen, an editor with a markdown toolbar and live preview, draft and scheduled publishing, per-item SEO, revision history with restore, and the routes /recipes and /recipes/{slug}.
Add a field tomorrow and the column appears by itself.
<?php
return [
'label' => 'Recipe',
'features' => ['slug', 'status', 'schedule', 'seo', 'revisions'],
'title' => 'name',
'public' => [
'index' => '/recipes',
'single' => '/recipes/{slug}',
'template' => 'recipe',
],
'fields' => [
['name' => 'name', 'type' => 'text', 'panel' => 'title'],
['name' => 'method', 'type' => 'markdown', 'panel' => 'main', 'editor' => true],
['name' => 'serves', 'type' => 'number', 'panel' => 'sidebar'],
['name' => 'photo', 'type' => 'media', 'panel' => 'sidebar'],
],
];
What comes with it
The parts you would have written anyway
None of this is a plugin. It is in the box, and it is the same for every type you declare.
-
A real editor
Markdown with a toolbar, live preview and word count. Media picker. Repeaters. Drag to reorder. Ctrl+S to save, and a warning if you leave with unsaved changes.
-
Publishing
Draft and published, future-dated scheduling, featured items, per-item SEO and social image, and an automatic redirect when an address changes.
-
History
Every save keeps the previous version. Restore any of them, including items someone deleted last week.
-
Media
Drag-and-drop uploads, automatic 480–2400px WebP versions, and a warning before deleting a file that is still used somewhere.
-
Security
bcrypt passwords, optional two-factor sign-in, login rate limiting, CSRF on every form, idle timeout, admin and editor roles.
-
Page sections
Give a type a blocks field and editors assemble pages from the sections you allow — like this page, which is eight blocks in the panel.
Getting started
Four steps from download to live
-
Upload the folder
Point the domain at public/. There is nothing to compile and nothing to install.
-
Create your account
Visit /admin. It asks for the app key from config.php, then your name and a password.
-
Declare your types
Copy one of the two examples in app/types/ and change the fields to suit the site.
-
Write the templates
Plain PHP in app/views/site/. The CMS decides what data a template receives, and nothing else.
Everything on this page — the headline, these words, the order of the sections — was typed into the admin panel.Open /admin and edit the page you are reading
Questions
The ones people actually ask
Do I need to know a framework?
No. It is plain PHP: templates, a router and about fifteen small classes. If you can read a PHP file you can change anything here.
What happens when I add a field to a type?
The column is added on the next page load and the input appears in the editor. Removing a field hides it again and leaves the data alone, so a typo never costs you content.
Why SQLite rather than MySQL?
A content site is read-heavy and small. One file is the easiest thing in the world to back up, copy and move, and it needs no database server. The data layer is one small class if you ever want to change it.
Can clients break the design?
Not easily. They fill in the fields you declared and reorder the sections you allowed. They cannot invent new kinds of section or touch the templates.
Is there a build step?
None. No npm, no Composer, no compiled assets. Upload the folder and it runs.
Have a look inside
The guides walk through declaring a type, the field types, and how the editing screen is put together.