CMS — pages and posts
On Zkrinet: add the block under Building blocks in the panel — one click, your own code is untouched and a snapshot is taken first. The installation steps below apply if you run PocketBase yourself, for example after an export.
Pages and blog posts that you write in the PocketBase admin panel (with a text editor) and display in your app. Publishing with dates, automatic URLs, version history, RSS feed and sitemap.
Tested against PocketBase 0.40.4.
#Installation
Copy pb_hooks/ and pb_migrations/ to your PocketBase and restart. The collections zk_cms_sidor and zk_cms_inlagg appear in the admin panel.
#Writing
| Field | |
|---|---|
titel, innehall (editor), utdrag | The text |
slug | The URL. Leave it empty and it is created from the title: "Våra tjänster & priser!" → vara-tjanster-priser (if it already exists it becomes -2). |
bild | Cover image (jpg/png/webp/gif/avif, max 10 MB) |
sok_titel, sok_beskrivning | Optional texts for Google (otherwise title/excerpt) |
publicerad, publiceras | Visible only when publicerad is on and the date has passed. A date in the future = scheduled. Checked without a date = published now. |
lastid_min | Calculated automatically (200 words/minute) |
Pages: ordning · Posts: taggar (list), forfattare |
Only superusers can write. Visitors read published content without logging in.
#Display in your app
// A page by its address
const sida = await pb.collection("zk_cms_sidor").getFirstListItem(`slug = "${slug}"`)
// Latest posts
const inlagg = await pb.collection("zk_cms_inlagg").getList(1, 10, { sort: "-publiceras" })
// Posts with a tag
await pb.collection("zk_cms_inlagg").getList(1, 10, { filter: 'taggar ~ "nyhet"' })
Render the content sanitized. innehall is HTML. The plugin removes scripts, event attributes, javascript: links, embeds and the like when it is saved (tested against around thirty known tricks) — but that is an extra layer of protection. Always render with a real sanitizer in the app, e.g. DOMPurify.sanitize(sida.innehall).
#RSS and sitemap
GET /api/zk/cms/rss.xml— the 20 latest published postsGET /api/zk/cms/sitemap.xml— all published pages and posts
If your site is on a different address than PocketBase, create one row in zk_cms_installningar:
| Field | Example | Default |
|---|---|---|
webbadress | https://min-sajt.se | the app's address |
sida_mall | /{slug} | /{slug} |
inlagg_mall | /nyheter/{slug} | /blogg/{slug} |
rss_titel, rss_beskrivning | the app's name |
Tip: point /rss.xml and /sitemap.xml on your site here (proxy/rewrite), and add the sitemap in Google Search Console.
#Versions
Every time the title, content or excerpt changes, the previous version is saved in zk_cms_versioner (the 20 latest per page). Restore with:
POST /api/zk/cms/aterstall/{versionens id} (superuser)
The current version is saved first, so a restore can also be undone.
#Limitations
- One language per record — if you want several languages, make one record per language (e.g.
om-ossandabout-us). - No "editor" role: the person who writes needs to be a superuser.
- Images in the text itself are uploaded via the editor's image button or as files; the plugin does no image optimization.
#Test
./bank.py cms
11 tests: slug (Swedish characters, duplicates), publishing and scheduling, permissions, sanitizing of dangerous HTML (including encoded and combined tricks) without touching ordinary HTML, reading time, versions and restore, the version cap, RSS and sitemap (valid XML, correct addresses, no drafts). The sanitizer is mutant-verified: every protection has been broken on purpose and caught.