Content items
Overview
This is where writing happens — once — and from here the text goes to every configured publishing target: your own website, a WordPress, wherever else.
That is the whole difference from a blog that belongs to a website. An item is not part of a page but a record of its own. It can live in several places without being written several times, and when you correct it, you correct it everywhere.
Content types: the shape, not the content
A content type defines which fields an item of that kind has. "Blog" ships with the system: title, excerpt, body, featured image. You can add more — "press release", "job ad", "recipe" — each with its own fields.
That sounds like a detail and is the reason this module exists: without types, the second kind of text eventually repurposes a field of the first ("subtitle" as a salary figure), and nobody can work out later what was meant.
An item's type cannot be changed. Its values belong to that schema; whatever does not exist in the other type would silently be gone.
Languages live INSIDE the item
An item carries its languages within itself, not as a second row beside it. The language switch above the text changes which version you are writing. The other stays untouched.
Every language that actually contains text is published. An empty English version is not published — it would look like a mistake out there, and one the reader attributes to you.
The workflow
| State | What it means |
|---|---|
| Draft | Being written. Changes freely. |
| In review | Waiting for someone to read it. Still editable — review is a state, not a lock. |
| Scheduled | Has a date. The scheduler checks every five minutes and publishes it by itself. |
| Published | It is out, on every matching target. |
| Archived | Taken out of the working set, not deleted. |
The workflow is fixed and cannot be extended with your own intermediate states. That is deliberate: program logic hangs off these names — "scheduled" wakes the scheduler, "published" delivers. A self-invented state would be a waiting room with no exit.
Only "scheduled" requires a date. Without it the scheduler never picks the item up — it would lie there forever while looking as though everything was done. That is why it is required.
Core tasks
Write. Pick the type, fill the fields, save. The address is derived from the headline if you do not give one.
Let AI draft it. You describe the topic, the AI fills the fields of the type. The result lands in the form — you see it, change it and save it yourself.
Send to review. The item moves to "in review". Feedback runs as a task on the item, not as a separate comment system: "please check the figures in the third paragraph" is a task, and tasks already have a history, assignees and a due date here.
Schedule or publish now. Both require the publish permission. Now means now — not "in the next run".
Withdraw. Takes the item back from every target and returns it to draft. The publication date stays: it says when the item was first out.
Editorial calendar
The list can be a table, a board and a calendar. On the board you drag an item from column to column — that triggers the same path as the button inside the item. In the calendar items sit on their planned date.
Notes, not blocks
Below the text you find notes: a too-short title, a missing description, an h1 inside the body, an empty link, an image without alternative text.
None of them prevents publishing — and that is a deliberate decision. A check that blocks teaches people to work around it: you set the meta title to "x" so the button lights up again, and the value is then worse than the missing one it replaced.
The missing alternative text is the only note at the highest level. It is not a convention but accessibility: for a blind reader it is the entire content of the image. It belongs to the item, not to the file — the same image can mean two things in two places.
Fields in detail
The What it does column answers what changes in the system — not what the field is called. The grey name behind the label is the API field: the same thing runs under that name through automation, import and AI tools.
Creating and editing content
| Field | Required | Values / format | What it does |
|---|---|---|---|
Content type typeKey | yes | an existing content type | What kind of content is created. It determines which fields the mask shows at all — an article has different ones from a recipe. Switching later is rarely sensible because field content can be lost. |
Language locale | yes | language code, max. 5 characters | Which language this content is written in. A translation is a separate content item, not a field — tied together by the translation group. |
Address slug | no | text, max. 220 characters | The readable part of the public address. Built from the title; changed by hand, existing links and search entries break. |
Fields fields | yes | depending on the content type | The actual content — title, text, images, whatever the type provides for. |
Categories categories | no | several categories | Classification of the content. |
Author authorEmployeeId | no | an employee | Who wrote the content. It appears where the channels show an author. |
Planned publication plannedPublishAt | no | point in time | When the content should go out. Until then it appears in the calendar but nowhere public. |
Targets targets | no | list of channels | Where it is published. One item can appear on several channels; each channel gets its own rendering of the fields it needs. |
SEO seo | no | title, description, image | What search engines and shared previews show. Left empty the system takes title and excerpt — often enough, but never as good as a written sentence. |
Brand brandId | no | one of your brands | Which brand the content runs under. |
Translation group translationGroupUlid | no | identifier of a group | Ties the language versions of the same content together. Through it the reader finds the other language — and you see which translation is still missing. |
Settings & permissions
- Module
module.content. content.item.view— see items and types.content.item.manage— write, schedule, archive.content.item.publish— schedule, publish, withdraw. The permission with outward effect.content.type.manage— maintain content types and field schema. Deliberately separate: a
field change acts backwards on every existing item.
FAQ & troubleshooting
The scheduled item did not appear. Check the date and the state. If it says "publishing" and does not move, a run claimed it and crashed — after an hour it is recovered automatically and tried again.
"The field … does not exist on this content type." A field name does not match the schema — usually a typo, or a field that has since been renamed. Rejecting is deliberate: discarding it silently would mean the typo costs the whole text.
The English version has disappeared. It should not: the languages sit side by side inside the item, and saving one leaves the other untouched. Use the language switch to check which version you are in.
The address got a number appended. It was taken. Two items on the same address would not be decidable — which one wins would depend on database ordering.
I cannot see items of another brand. That is correct. What is visible is what you hold a content permission for in that brand — mere membership is not enough.