Categories bundle: categories managed in the editor as Hugo term pages, used by news #152
Labels
No labels
bug
enhancement
needs-triage
ready-for-agent
ready-for-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/deckle#152
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Add a
categoriesfeature bundle that makes categories a site-wide part of deckle instead of a news detail. Each category is a Hugo term page undercontent/categories/. Editors create, rename and delete categories in a Categories module. A newcategoriesfield type lets a page type or an element pick from that list. The news bundle uses it for news items and for the "Latest news" filter, replacing its two hand-kept option lists.Current behavior
Categories exist only in the news bundle, as two copies of one option list:
news-item.yamldeclares acategoriesmultiselect withoptions: [announcements, company, events, product];news-list.yamldeclares a single-valuedcategoryselect with the same list.The sidecar comments and
harness add newssay to keep the two "in lockstep by hand". Only a repo test (TestNewsBundleSidecarsLoad) compares the shipped copies.Editors can't add, rename or delete a category, because the list lives in sidecars.
The news bundle enables Hugo's
categoriestaxonomy throughhugo.tomledits (thedisableKinds,taxonomiesandoutputssteps of itsfeatureConfigentry ininternal/addcmd). It also shipslayouts/taxonomy.htmlandlayouts/term.html, which list news items only.The editor shows the raw value (
company), while Hugo shows the term title-cased (Company).On save, a news item's multiselect keeps only values that are in the list. A "Latest news" element that stores a value no longer in the list can't be saved (422 "must be one of…").
Desired behavior
The categories bundle
categories(scaffold/features/categories/).harness add categoriesinstalls it andharness remove categoriesremoves it. It ships:/categories/page,content/categories/_index.md, so it always sits where Hugo needs it. It stays out of the site's main navigation;editor/modules/categories.yaml;/categories/and/categories/<slug>/;hugo.tomledits that enable thecategoriestaxonomy, which move here from the news bundle: re-enable thetaxonomyandtermkinds, declarecategory = 'categories', and limit both kinds' output to HTML.Categories
content/categories/. Pages store its folder name (the slug). Its title is the name shown everywhere: in the editor, and on the site, where Hugo reads term-page titles itself./categories/page in the tree, then list, create, rename and delete categories, sorted by title. The entry editor has only a Properties tab, and categories have no Enable/Disable.categoriesfront matter and in every element'scategoriesparam.categoriesfront matter and every element'scategoriesparam:The
categoriesfield typecategories, allowed in page-typefields:and in elementparams:. A field or param of this type must be namedcategories, and a field or param namedcategoriesmust be of this type. This way, deleting and renaming know exactly where category values are stored.options:and nodefault:.categories: [company, product]. Element params store the slugs comma-separated, because shortcode params can't hold lists:categories="company,product".tags,filters), and they show category titles.News
news-item'scategoriesfield becomestype: categories.categoryselect with acategoriesparam. It shows the news items that are in any of the chosen categories, and its limit applies after filtering.hugo.tomledits (it keepsbuildFuture) and no longer ships the/categories/templates.versiongoes up by one. The sidecar comments and the next stepsharness add newsprints no longer mention hand-kept lists.Category pages on the site
/categories/lists the categories that have at least one published page, by title, each with its count./categories/<slug>/shows the category's title and lists its published pages, newest first, paginated at the site's page size. News items render as the news cards they have today. Other pages render as a title link with their summary.Docs
scaffold/site/AGENTS.mdand the README document (CLAUDE.md rule):categoriesfield type and its naming rule;Decisions
categories:), and Hugo builds/categories/and one page per category. Each category's term page holds its title, and Hugo shows that title everywhere (the page heading,<title>, links) without template lookups.categories, for every field and param that holds categories. This is the maintainer's requirement, so that delete and rename know where to search. It is also Hugo's taxonomy key.harness initinstalls it, is #157./categories/page and starts with no categories. Re-runningharness addrestores missing bundle files, so shipped category files would come back after an editor deleted them.Key interfaces
FieldType,validFieldTypes,buildParam,ParamSource,ValidateValuesandCoerceValuesininternal/element. Page-type fields reuse them (internal/pagetype). The AGENTS.md drift test (internal/element/agentsdoc_test.go) requires the manual to name the new type.type: page(CheckPageParamsininternal/pageops). The client needs each category's slug and title, through the schema endpoints (/api/pagetypes,/api/elements) or an endpoint of its own.internal/pageops;renamePageToandDeleteDialogin the web app) and the site-wide link rewriting on rename (internal/linkrefs) are the precedent for rewritingcategoriesvalues across pages.pageActionsandpageActionItemsinweb/src/pageactions.ts, for leaving out Enable/Disable on categories.fields.tsx(canonicalMultiselectValue,MultiselectField,buildFieldValues) and the module screen's columns, cards and filters.checkPlacementandbuildFilterininternal/editormodule, and filter matching ininternal/server/modules.go.featureConfigand the taxonomy steps ininternal/addcmd(config.go,taxonomy.go; the step IDs are part of the receipt format), andfeatureHints. In-use detection is ininternal/removecmd.scaffold/features/news/andinternal/theme/news_test.go.Acceptance criteria
harness add categorieson a fresh site writes the bundle, includingcontent/categories/_index.md, enables thecategoriestaxonomy inhugo.toml, and records everything in the receipt.harness remove categoriesundoes it. Right after an add, with no categories created and nothing customised, the remove succeeds without--purge.content/categories/company-news/_index.md, and the category then appears in a news item's properties and in the "Latest news" category picker, with no sidecar edit.categories: [company-news, product], and clearing them removes the key. A stored value that names no category isn't shown, and it is gone after the next save.categories="company-news,product". It shows only the news items in either category, newest first, with the limit applied after filtering.categoriesthat isn't namedcategories;categorieswith another type;options:ordefault:on acategoriesfield./categories/page lists the categories that have published pages, by title, with counts. A category page shows its title and its published pages newest first, with news items as news cards.hugo.tomledits and ships no/categories/templates, and itsversionis bumped.How to verify
make test. It buildsweb/distfirst, whichgo test ./...needs. The theme's Hugo build tests run only withhugoon PATH (CI installs 0.163.3).cd web && npm test.harness serveon a fresh site withharness add categoriesandharness add news:/categories/and one category page in the preview;Assumptions to check
typeon new pages. Check that Hugo 0.163 still renders typed category pages, and the/categories/page, through the bundle's templates..Render) are one way. Check how they behave under Hugo 0.163's template system.site.Home.Pages, which the theme's header navigation iterates over, includes the/categories/page, and what keeps that page out of the navigation.internal/removecmdcounts pages of a bundle's page types as content in use. The shipped/categories/page alone must not block removing a bundle that has no categories. deckle-hosted'sTestRealHarnessLifecycle(harness/real_test.go, run whenDECKLE_HOSTED_TEST_HARNESSis set) adds and removes the first feature the harness lists, and that becomescategories.[a-z0-9-]) are exactly what Hugo derives for a term's URL, so a stored slug always matches its term page.Out of scope
harness init(#157).Blocked by
news-list.yamland its template, so this issue lands after it)dominik.polakovics referenced this issue2026-10-06 23:42:12 +02:00
Category system shared by every element and page type that uses categoriesto Categories bundle: categories managed in the editor as Hugo term pages, used by news