Organizing and presenting content
For administrators. How content is grouped, navigated, and presented on a Kartotek site — Categories, Tags, and per-Domain navigation — plus the admin mechanics for each. See Welcome to Kartotek for the overall concept this doc assumes, and Domains, UIDs and addresses for the technical address/UID model and the full per-Domain configuration field reference.
A Category is a grouping that Posts belong to — a Post belongs to at most one Category. Normally that's exactly one, but a Post can later be detached from its Category (see Posts and publishing's "Removing a Post from view") and left with none, at which point it no longer appears on any Category's page. Categories are created and edited from the admin area, and any number can exist.
A worked example
Say a personal site wants two top-level sections: Journal (day-to-day writing) and Projects (things built), with Projects further split into Software and Woodworking sub-categories. That's four Categories: journal and projects at the top level, software and woodworking nested under projects. A Post assigned to software shows up on the Software page and on the Projects page (its parent) automatically — see "Hierarchy," next — without being published twice.
Hierarchy
Categories can have a parent, set (and changed) from the admin area. A Category's page automatically includes every post published to it and to all of its descendants — so a parent Category's page shows everything published to any of its children too, without those posts needing to be published twice.
A Category can't be made its own ancestor — the admin area rejects a change that would create a loop (directly, or through a longer chain of parents).
If visit analytics is enabled (see Privacy and analytics), this same hierarchy is what a Post's page view rolls up through: viewing a Post increments its own count plus its directly-assigned Category's and every ancestor Category's contained Post page views — a distinct metric from a Category's own direct page views (someone loading the Category's page itself). The two are never added together.
Creating and editing a Category
The admin sidebar's Categories tree is also the entry point for Posts — there's no separate top-level Posts section, though the full sortable/filterable Posts list is always reachable at /_admin/posts. Clicking the Categories heading itself is a real navigation link, opening the Category matrix (see "The Category matrix," below); the small chevron beside it is a separate control that only expands or collapses the tree underneath, never navigates. Each unfolded Category row has two of its own small icon actions, distinct from clicking the Category's name (which opens it for editing) and from the expand/collapse arrow: a folder icon opens that Category's Content inventory (see below), and a + opens a new Post with that Category already selected. The + beside the Categories heading itself creates a new Category.
The Category matrix
Clicking the Categories heading opens an Excel-like matrix over every Category on the site: full-text search, per-column sort and filter, resizable columns (with a one-click reset back to their default widths), and paging, with the current search/sort/filter/page state all preserved in the page's own address so it can be bookmarked or shared. Each row shows:
- Name, Hierarchy path (root through this Category), and Parent.
- Direct children — the number of Categories nested directly under this one.
- Posts (direct) and Archive Media (direct) — counted the same direct-assignment-only way as "A Category's Content inventory," below — plus a Total content (direct) combining the two.
- Posts (incl. descendants), Archive Media (incl. descendants), and Total content (incl. descendants) — the same descendant-inclusive rule a Category's own visitor-facing page uses (see "Hierarchy," above), shown as clearly separate columns from the direct counts beside them, never combined into one ambiguous number.
- Original language, and a Translations column showing one bubble per configured language (its translated value, or Missing when none exists yet) — the same at-a-glance translation-completion view the Tag matrix (below) already uses.
- URL / slug — the Category's own public address.
- Display mode — its configured default view (see "List, Map, Gallery, and Chronology views," below).
- Actions — open its Content inventory, open it for editing, or start a new Post already assigned to it.
Selecting a Category's name (in the matrix, or anywhere else in the sidebar) opens the same Category detail page described in "Each Category has," below — the matrix is a bulk overview, not a separate editing surface.
A Category's Content inventory
The folder icon on a Category row opens that Category's own Content page — every Post and every Archive Media item assigned directly to that Category, clearly labeled by Type (Post or Archive Media), with a total and a per-Type count. Selecting a Post opens it in the usual Post editor; selecting an Archive Media item opens the same detail view as the Archive Media catalogue (see Media and the Media Archive). Each Post row also carries a Category dropdown, a Stage dropdown and a small OK button applying both together, exactly as the full Posts list does (see Posts and publishing) — so routine reclassification can be done from the folder you are already looking at. Moving a Post to a different Category legitimately removes it from this page, since the inventory lists direct assignments only; the row disappears once the change is saved, not before. Archive Media rows keep their existing detail view and have no such controls. A Type filter (All / Posts / Archive Media), free-text search, sorting, and paging are all available, and the page's own address preserves them, so it can be bookmarked or shared. Admin displays every matching Archive Media item here regardless of its Privacy or Quality — those are metadata on this page, not a filter, unlike a visitor-facing Category page (see Privacy and Quality).
This inventory is direct assignment only — unlike a Category's own visitor-facing page (see "Hierarchy," above), it does not also include content assigned to a nested Category. A Category with no directly-assigned Posts or Archive Media shows an explicit empty state; a Category with only one of the two Types shows that Type's results without claiming the whole Category is empty.
Each Category has:
- UID — its short name in the URL (
domain/<uid>). Shared with Posts in a single namespace — see Domains, UIDs and addresses. - Name — the Category's authoritative original display name, and Original language — the language that name is actually written in. See "Translated display names," below, for showing a different name per visitor language.
- Parent — the Category it's nested under, or none for a top-level Category.
- Presentation post — a Post (of Post Type "Category Presentation") used as this Category's page header. That Post is never shown in the Category's own list of posts — it exists only to hold the header content (name, avatar, bio, contact details). Only Posts already belonging to this Category are offered here.
- Default display mode — List (the default), Map, Gallery, or Chronology — see "List, Map, Gallery, and Chronology views," below. This only sets which view a visitor sees first; they can always switch on the page itself.
A Category isn't required to have a presentation post. A Category's link to its presentation post doesn't depend on that Post still belonging to the Category — if the presentation post is later detached from the Category, it keeps presenting that Category. If the presentation post is Hidden, the Category's page simply shows no header at all.
Unlike a Post, a Category can be deleted outright from its own admin page — it's a structural grouping, not content in its own right. The one exception is the root Category, which can never be deleted, since it's the top of the tree every other Category ultimately hangs off of. Deleting a non-root Category re-homes what it was holding, rather than deleting alongside it: Posts directly assigned to it move up to its parent, and its own child Categories are re-parented to its parent too (skipping a level, rather than being deleted or left orphaned). A Category's UID does not get the alias/redirect treatment a Post's does (see Domains, UIDs and addresses): deleting one frees its UID immediately, with no historical alias left behind, available for reuse right away.
Whether (and where) a Category shows up in a site's top navigation, or as its Domain's landing target or Category sidebar, is not a Category setting at all — it's configured per Domain instead, and a given Category can be placed differently (or not at all) across several Domains sharing the same content. See "Domain-specific navigation," next.
Domain-specific navigation
Each configured Domain (see Domains, UIDs and addresses for the full field reference and address rules) has its own independent navigation, rather than every Domain sharing one global top bar:
- Landing target — the Post or Category a Domain's bare hostname renders at the root address itself. Optional; a Domain can have none configured.
- Top navigation — an ordered list mixing Posts, Categories, Tags, and/or arbitrary URLs, each with an optional Domain-specific label overriding its own title/name/canonical spelling. Adding an entry is a two-step choice: pick a Type (Category, Tag, Post, or URL), then a Target of that Type — Categories and Posts list alphabetically by name/title; Tags list alphabetically by canonical spelling, with a synthetic All Tags entry (linking to the Tag cloud) always listed first. A Tag entry's label defaults to its own spelling with a leading
#(e.g.#byplanlægning) when left blank — a Reviewed translated spelling, when the visiting language resolves one, keeps the same#prefix. A URL entry links directly to any internal or external address instead of an existing Post/Category/Tag — its label defaults to the linked address's own domain name (lowercase, withoutwww.) when left blank, and it never creates or affects a Link record elsewhere in the system (no monitoring, no archival — it's navigation only). The same target can appear on none, one, or several Domains, each with its own position and label — the Domain owns the placement, not the content itself. - Category sidebar — an optional collapsible left sidebar showing one selected root Category plus all of its descendants as a tree. Off by default.
A Post, Category, or Tag's own identity is what a Domain's navigation entries point at — internally, by a stable reference that survives a later rename, not by the address text itself. A Hidden or PrePub Post placed in a Domain's top navigation is omitted from it for a public visitor, and shown there (clearly marked) only for a logged-in admin previewing their own content. A Category or Tag that's later deleted simply disappears from anywhere it was placed, without breaking the rest of that Domain's navigation.
A deployment with no Domain configured at all — or a request through a hostname that doesn't match any configured Domain, when no Domain has been marked Primary either — falls back to a site-wide default. Configuring even one Domain (or marking one Primary) is what switches a hostname over to the per-Domain navigation model described here. Managed from the admin sidebar's Domains entry — see Domains, UIDs and addresses for every configurable field, the Primary Domain fallback, and the admin-only Domain preview selector.
Translated display names
A Category's Name is authoritative in its own Original language, but a visitor viewing the site in a different configured language sees a translated display name wherever that Category's name is visitor-facing — top and side navigation, Category pages, and a Post's own Category reference — whenever a reviewed translation exists for that language. With none, the visitor sees the original name instead; nothing ever looks half-translated.
From the Category editor, an administrator can, per configured language:
- Type a translation by hand, or Generate with DeepL — either way it starts as a draft, not yet visible to visitors.
- Mark it Reviewed — the one action that makes it visible. A generated translation always needs this explicit step; a manually typed one does too.
- Remove a translation entirely, reverting that language back to showing the original name.
Editing the Category's own original Name later marks any already-Reviewed translations stale — they stop being shown until reviewed again, since they were approved against the name that's now changed. The translation itself isn't deleted, so re-reviewing (or regenerating) it is quick. See Languages and translations for the equivalent Post/Content translation workflow and the corpus-wide Tag-translation backfill.
Translating a Category's name never affects its UID, its page address, its place in the Category hierarchy, or which Posts belong to it — only the label a visitor sees.
Tags: a flat, informal alternative
A Tag is a completely different, much looser way to group content, written as #tagname while editing a Post. Where a Category is a curated structure someone deliberately builds and a Post belongs to at most one of, a Tag has no structure and no settings of any kind — it simply exists because it's been typed into a Post, and it always shows its Posts as a List by default (see "List, Map, Gallery, and Chronology views," below — an individual visit can still switch a Tag's own page to Map, Gallery, or Chronology, the same as a Category's page, just with nothing stored). A Post can carry any number of Tags, and they cut across Categories freely: a "woodworking" Tag might turn up on Posts filed under both Journal and Projects.
There's nothing to create in advance. Typing a new #tag while editing a Post brings it into existence immediately; the admin editor also suggests Tags already used elsewhere, so a slightly different spelling doesn't accidentally start a second, near-duplicate Tag. Tags are matched without regard to case, so #Woodworking and #woodworking are the same Tag for browsing purposes. Any letter is allowed, not just ASCII, so a real spelling like #byplanlægning is a valid Tag on its own terms, not just its ASCII-transliterated form. The spelling shown publicly is that Tag's own canonical spelling — whatever it was first typed as, or whatever it was last explicitly renamed to (see "Managing Tags," below) — not necessarily whatever capitalization was most recently typed into a Post.
Every Tag also has an Original language — the language its canonical spelling is actually written in, same concept as a Category's own Original language (above), set from Tag administration (see "Managing Tags," below). A Tag's own page and a Post's #tag links both resolve correctly whether reached via the Tag's original address or a Reviewed translation's own address — see "Translated display labels," in "Managing Tags," below, for the full detail.
Two public pages let a visitor browse by Tag, both at the same page width as a Post's own page:
/_tags/— a Tag cloud of every Tag in current public use, sized roughly by how many Posts use it. A logged-in admin sees Tags used by PrePub/Hidden/Private Posts too, the same visibility rule described below for an individual Tag's page./_tags/<tagname>— every Post currently carrying that Tag.
Because a Post's content only ever reflects its current published Version, removing a Tag from a Post (by publishing a new edit without it) removes that Post from the Tag's page and from the cloud's count entirely — not just from its current display, but from every count and every List/Map/Gallery/Chronology view. If an earlier published Version of a Post used a Tag that its current Version no longer does, that history is not lost — it's simply not part of the Tag's ordinary page. You can still see it by visiting that earlier Version directly (a Post's own Version history stays fully intact and inspectable), it just doesn't show up when browsing by Tag.
A Tag can never become a Category — it still can't be used as the Category sidebar's root, or set as a Domain's landing target, since neither of those has a meaningful "many Posts at once" equivalent. It can be placed in a Domain's top navigation (see "Domain-specific navigation," above): choosing Tag as the Type shows every current Tag, alphabetically, plus a synthetic All Tags entry linking to the Tag cloud; renaming or translating that Tag afterward updates the navigation label automatically, without breaking the link.
Managing Tags
The admin sidebar's Tags section uses the same compact row treatment as Categories (see "Creating and editing a Category," above): clicking the Tags heading itself opens the Tag matrix (below) — a separate control from the small chevron beside it, which only expands or collapses the searchable, paginated flat list (no nesting — Tags stay flat) underneath. Each row of that flat list offers a folder icon (opens that Tag's own Content inventory, below), a + (opens a new Post with that Tag already selected, the same as a Category row's own +), and its label itself (opens the Tag for editing). A + beside the Tags heading creates a new Tag directly, the same section-level create pattern Categories use. A Manage all Tags → link at the bottom of the section opens the same Tag matrix the heading itself does — everything below is available from either place.
The Tag matrix
The Tag matrix is an Excel-like grid over every Tag on the site, matching the Category matrix's own interaction pattern (above) — full-text search, per-column sort and filter, resizable columns with a one-click width reset, paging, and the current search/sort/filter/page state preserved in the page's own address. Each row shows the Tag's spelling (with its # prefix), its Posts and Media usage counts plus a Combined total, its Original language, one Translations bubble per configured language (its translated value, or Missing), and a row of actions: open its Content inventory, open it for editing, start a new Post with it already selected, rename it, and delete it directly from the row (see "Deleting a Tag from the matrix," next).
Deleting a Tag from the matrix
The Tag matrix's own Delete action — a separate click target from the row itself, so a stray click on the row never triggers it — opens a confirmation dialog before doing anything: it shows the Tag's own spelling, its Post usage count and its Archive Media usage count as two distinct numbers (never combined into one), and explains plainly that only the Tag record and its relationships are being removed, never any Post, Post Version, Post Media, or Archive Media item. An explicit "I understand" checkbox must be ticked before the Delete button itself becomes clickable. Confirming goes through the exact same deletion this doc's "Delete it entirely," below, already describes — detaching from every Post and Media item, removing translations, and reporting a failure without leaving anything partially removed — the matrix's own row action and a Tag's own edit page both trigger this one shared action, not two different code paths. Every matrix row's counts refresh immediately afterward, with no redeploy needed.
A Tag's own Content inventory works exactly like a Category's (see "A Category's Content inventory," above): every Post and every Archive Media item carrying that Tag, Type-discriminated with a total and a per-Type count, a Type filter, free-text search, sorting, and paging, all preserved in the page's own address. Unlike a Category, there's no "direct vs. descendant" distinction to call out — a Tag is flat, so this is simply everything that carries it.
Opening a Tag for editing shows the same detail layout as a Category's own edit page (above) — canonical spelling and Original language, its translations, its Post/Media/Combined usage counts, and a row of actions — minus the hierarchy-specific fields (parent, children, presentation) a Tag has no equivalent of, since it's flat. From here, a Full Admin can, for any existing Tag:
- Set its Original language — every Tag that existed before this setting was introduced starts flagged "needs review" (a starting guess, not a confirmed fact), and a newly-created Tag starts flagged the same way until explicitly confirmed. Setting or confirming it is a plain field edit; the one thing it refuses is a language that already has a saved translation for that same language on this Tag, since an original and a translation can't coexist for the same language.
- Give it a translated display label per configured language — the same draft/DeepL-assisted/Reviewed workflow a Category's own display name already uses. Only a Reviewed translation is ever shown to a visitor; a manual edit or a freshly-generated DeepL draft always needs an explicit Review step first.
- Rename it — a separate action from editing the Tag's other fields, since a rename can affect more than this one Tag. It corrects the canonical spelling everywhere at once, across every Post and every historical Version that has ever used it, rather than only affecting new edits going forward. If the new name is already in use by a different Tag, this becomes a merge instead: every Post carrying the old Tag now carries the existing one (a Post that already had both keeps just the one, never a duplicate), any translation conflicts between the two are shown for you to resolve explicitly, and the old Tag is removed. Renaming a Reviewed translation marks it stale rather than erasing it, the same as renaming a Category does — a starting point to re-review rather than a lost translation. A Tag's own address (
/_tags/<tagname>) moves with the rename; the old address simply stops showing results, the same as any Tag that's never been used, since Tags — unlike Posts and Categories — keep no redirect history. - Delete it entirely — detaches it from every Post at once and removes its translations. This never deletes any Post, Version, or content — only the Tag itself and its associations. Shown alongside the Post and Archive Media usage counts, and requires explicit confirmation first — the same confirmation dialog "Deleting a Tag from the matrix," above, describes.
Translated display labels are also valid addresses. Once a Tag has a Reviewed translation, that translation's own spelling becomes a second, permanent address for the same Tag's page (/_tags/<translated-spelling>) alongside the original — visiting either one shows the same Posts, with no redirect from one to the other, the same "an old or alternate address keeps silently working" principle Posts and Categories already follow for a renamed uid (see Domains, UIDs and addresses). A Post's own #tag link beneath its content always points at the Tag's original address regardless of which language the Post is being viewed in — only the visible label switches to the Reviewed translation; the link target doesn't.
Categories and Tags on media
A media item — a Post's own Image/Video/Audio/Attachment, or an item catalogued in the Media Archive (see Media and the Media Archive) — can also belong to Categories and Tags, using these exact same Categories and Tags, not a separate set. Unlike a Post, which belongs to at most one Category, a media item can belong to any number of Categories, and any number of Tags — assign and remove them from the media item's own editing surface (Post Media's Categories/Tags column, or an Archive Media item's detail panel).
A Category or Tag's admin listing shows Posts and Media as two separate counts plus a combined total, so it's clear at a glance how much of each a Category or Tag actually covers. Renaming, translating, merging, or deleting a Tag — and re-parenting or deleting a Category — carries through to every media item that uses it exactly the same way it already does for Posts: a merge repoints a media item's relationship to the surviving Tag, and a deleted Category's media relationships move up to its parent, the same as its Posts and child Categories do. Removing a Category or Tag from a media item never deletes the media item itself — only the relationship.
Archive Media's own pre-existing single Category field and free-text Tags (see Media and the Media Archive's "Archive Media") are a separate, simpler feature and unaffected by this — an Archive Media item that already had a Category set that way starts out with the same Category also reflected here, as a starting point you're free to change.
An Archive Media item can also pick up a Category automatically, not just by hand: see Media and the Media Archive's "Folders under Temaer/Begivenheder become Categories automatically." A folder-derived assignment behaves like any other Category relationship above — it's just added by a scan instead of by you — and a Category you assigned yourself is never touched by one.
List, Map, Gallery, and Chronology views
Both a Category's own page and a Tag's page (/_tags/<tagname>) show a List / Map / Gallery / Chronology selector in the top-right corner. List is the usual Brief-card feed, paginated; Map plots those same Posts by location; Gallery is a thumbnail grid; Chronology plots them (plus their directly-assigned media) on a date histogram — see "Chronology view," below.
- For a Category, which view a visitor sees first is its "Default display mode" (see "Creating and editing a Category," above) — List, Map, Gallery, or Chronology, set from the Category editor.
- For a Tag, which has no settings of any kind (see "Tags," above), the first view is always List.
Switching the selector only changes how that one visit sees the collection — it's part of that page's own address (so it survives a reload, and the specific view can be linked or bookmarked), but it never changes which Posts or media belong to the collection, a Post's own content, or its geometry, and nothing about the choice is saved anywhere. A period selected on the Chronology view (below) is the one exception carried across a mode switch: it stays applied to List, Gallery, and Map until explicitly cleared, the same way any other active filter would.
Each Brief card's title and brief resolve to the same effective language as the rest of the page — an explicit ?lang=, else a visitor's own selected language, else the visiting Domain's default — falling back to a Post's original language field-by-field when no complete translation exists for it yet, the same rule a Post's own Full page uses (see Languages and translations).
Media alongside Posts in List and Gallery
List and Gallery both also show a Category's or Tag's own directly-assigned media (see "Categories and Tags on media," above) alongside its Posts, not just Posts on their own:
- A Post's own cover image is presentation for that Post — it never shows up as a separate media card in the same result. A media item only appears on its own when the item itself — not the Post that happens to use it as a cover — is directly assigned to the Category or Tag.
- List keeps every Post's existing Brief-card look, and renders each directly-assigned media item as its own Media Brief card in between — a thumbnail alternating left/right down the page (the same rhythm a Cover-bearing Article card already uses), with Title, Description, Capture date, and Capture device shown when available. A capture date that's really just when the item was added or discovered (no genuine capture timestamp exists) is labelled "Added," never presented as a real capture date. A media item with no Title falls back to a stable filename- or kind-based label instead of showing nothing.
- Gallery shows every directly-assigned, publicly eligible media item as a thumbnail, plus every Post whose current page has a cover image — a Post with no cover image simply doesn't appear in Gallery (it's unaffected everywhere else, including List).
- Posts and media interleave by the same recency ordering, newest first, whichever type of result that happens to be.
- Post Media and Archive Media follow separate public-eligibility rules — see Media and the Media Archive: Post Media is visible exactly whenever its owning Post's page is; Archive Media additionally needs Privacy set to Public and Quality set to Medium or High. Selecting a Post opens the Post; selecting a separate media card opens that item's own detail page.
Map view
Only one geometry per Post takes part in Map view: whichever Geospatial element is ranked highest among that Post's currently-published ones (see Writing and embedding content's "Roles, Rank, and Reference"), skipping past a Heatmap if that happens to be the highest-ranked one — a Heatmap only makes sense for one Post's own many-point data, not for comparing many different Posts side by side, so it's never shown on a collection map. A Post with no eligible Geospatial element at all simply doesn't appear on the map (it's unaffected everywhere else). Clicking a Post's marker or shape opens that Post; if several Posts share the exact same point, clicking it offers a short list to choose from instead of guessing which one you meant. A plain list of every included Post's title, each a link, sits below the map itself — so the same collection stays fully browsable without a mouse. A Fullscreen button opens the same map full-page, with the same list underneath and a "Show all" control to re-fit after panning or zooming around. Every title shown on the map — that linked list, a marker's own label, and the shared-point picker — resolves to the same effective language as the List view's Brief cards above, and switching language while already on the Map view updates every title at once; a Post's location, geometry, and which Posts are included are unaffected by language either way. Map view doesn't show media items.
Chronology view
Chronology plots the same mixed Posts-plus-directly-assigned-media collection List and Gallery already show, as one date histogram instead of a feed or a map — the same Time Chart used by the Post Media and Archive Media inventories (see Media and the Media Archive's "Time Chart"): one bar per time period, counted at whichever level (year, month, day, or hour) fits the span currently in view, with Unknown-date items called out as their own count alongside the bars rather than folded into them.
Each Post is placed by its own Sorting Date (the same date List and Gallery already sort by); each media item is placed by its capture date when one was found, or otherwise by the date it was added or discovered — visibly labeled as a fallback, never presented as a real capture date, the same "resolved time" rule the Media inventories' own Time Chart already follows. A Post or media item with neither is an Unknown date, always counted separately, never silently dropped or guessed at. Only publicly eligible media takes part — Post Media follows its owning Post's own Stage-based visibility, Archive Media additionally needs Privacy set to Public and Quality set to Medium or High (see Media and the Media Archive's "Privacy and Quality classification"), the same rule List and Gallery already apply; other active filters on the page carry through unchanged.
Clicking a bar, or dragging across several, narrows the chart to that period and sets it as the page's active time filter, so a link offered right there lets you jump straight to the exact matching Posts and media in List — switching to List, Gallery, or Map afterward keeps showing only that period, until it's explicitly cleared. Zoom out/Reset zoom widen what the chart displays without touching that filter. A View as table link exposes the same data as a plain accessible table, with each bar's capture-date and fallback-date counts shown side by side.