Raven CMS Channels
This document explains Raven's Channel system for both panel users and developers/agents.
Maintenance note: keep this file updated whenever channel structure, channel routes, or Channel panel views change (private/tpl/panel/channel/*, channel controller/repository behavior, or channel public routing).
1) Panel Guide (Create And Edit Channels)
Where To Go
- Open panel sidebar:
Taxonomy->Channels.
Channel List (/channel)
What you can do:
New Channel(top and bottom action bars): opens create form.Delete Selected(top and bottom action bars): deletes checked rows after confirmation.Searchfilter: filters rows byID,Title, orSlugas you type.- Row checkbox: marks a non-stock channel for bulk delete.
- Clickable table headers (
ID,Title,Slug,Pages): client-side sort. - Row
Editbutton (pencil icon): opens channel editor for custom channels. - Row
Deletebutton (trash icon): deletes one custom channel after confirmation.
Columns shown:
IDTitleSlugPages(count of linked pages)Actions
Channel Editor (/channel/edit and /channel/edit/{id})
Top and bottom action bars (same controls in both places):
Save ChannelBack to ChannelsDelete Channel(existing channels only)
Fields/options:
Name(required)Slug(required)Parent(defaults to<root>; shown as a root-first indented tree with each canonical parent path in parentheses)Description(optional)Category Setscheckbox list withUse System DefaultandAll SetsTag Setscheckbox list withUse System DefaultandAll SetsCover Image(optional, single file)Preview Image(optional, single file)Remove current cover imagecheckbox (shown when a cover image exists)Remove current preview imagecheckbox (shown when a preview image exists)ThemeSyndicationandEnable dedicated sub-feeds for this channel.(Content tab; shown only when global feeds are enabled)Channel Index Route:Automatic,No Trailing Slash,Use Trailing Slash, orRedirectRoute ModeRoute Separator
Image behavior notes:
- Upload limits/extensions/variant sizes follow
media.images.*config (same as Page Editor image rules). - Channel media is stored under
public/uploads/channels/{id}/. - Only one cover image and one preview image can be attached at a time.
Feed behavior notes:
Enable Feed?opts that channel into channel-specific public feeds.- When
feed.rssis configured globally, enabled channels expose/{feed.rss}/{channel-slug}. - When
feed.atomis configured globally, enabled channels expose/{feed.atom}/{channel-slug}. - When global
feed.enabledis off, channel feed routes are disabled and the editor hides the toggle.
Theme behavior notes:
Themedefaults toInherit, which follows the configured global public theme.- The remaining options list every installed public theme in alphabetical order by display name.
- An explicit theme applies to the channel landing page and every page published in that channel.
- Theme lookup uses the same fallback chain as the global theme: the selected child theme, its parent themes, then the global child/parent/core fallback templates and assets.
- If a selected theme is removed later, the channel safely falls back to the global system default.
Parent behavior notes:
Parentlists the stock<root>channel first, followed by available channels in alphabetical sibling order.- Nested channels appear directly beneath their parent with indentation.
- The edited channel and its descendants are omitted from its own parent selector to prevent circular hierarchies.
- New channels default to the stock
<root>channel.
The editor tabs are Basic, Content, Media, and Routing in alphabetical order. Basic contains Name, Slug, Parent, and Description; the Media tab ends with Theme; the Content tab contains Editor Override and Syndication; the Routing tab begins with Index, followed by Route Mode and Route Separator. Each setting includes a short inline explanation in the editor.
Taxonomy set behavior notes:
- New channels default to
Use System Default, which stores no explicit set selection and falls back tocategory.set/tag.setfrom System Configuration. - Channels can explicitly switch to
All Setsor an explicit subset of category/tag sets. - When
All Setsis checked, the UI keeps every set visibly checked but only stores the0sentinel in the channel record. - Those assignments control which categories and tags remain available in the Page Editor when that channel is selected.
- Channel records store those assignments in
private/dat/channel/{id}_{slug}.php.
Delete behavior note:
- Deleting a channel detaches linked pages and redirects to root scope; it does not delete pages/redirects.
- Deleting a channel also reparents its direct child channels to the stock
<root>channel. - Raven keeps one stock
<root>channel with reserved id0and placeholder slugroot; it is protected from edit/delete actions and is not used as a public route segment.
Index behavior notes:
Automaticmakes the channel root canonical using the systemsite.routingtrailing-slash policy.No Trailing Slashmakes the channel root canonical without a trailing slash, overridingsite.routingfor this channel index only.Use Trailing Slashmakes the channel root canonical with a trailing slash, overridingsite.routingfor this channel index only.Redirectsends the channel root to/{channel_path}/homewhen a publishedhomepage exists, otherwise to/{channel_path}/indexwhen a publishedindexpage exists.- These settings change only the channel index route. They do not change routing or canonicalization for other pages assigned to the channel.
2) Developer And Agent Internals
Key Files
- Panel views:
private/tpl/panel/channel/list.phpprivate/tpl/panel/channel/edit.php- Panel controller:
private/sys/Controller/Panel/ChannelListController.phpprivate/sys/Controller/Panel/ChannelEditController.php- Persistence:
private/sys/Repository/ChannelRead.php, private/sys/Repository/ChannelWrite.php
Panel Routes
Declared in private/sys/Router/Panel/ChannelRouter.php:
GET /channel-> listGET /channel/edit-> create formGET /channel/edit/{id}-> edit formPOST /channel/save-> create/updatePOST /channel/delete-> delete (single or bulk)
All state-changing routes use CSRF validation.
Controller Flow
Split channel handlers:
channelList()- Owned by
ChannelListController. - Requires login + channel route
viewpermission. - Renders list via
ChannelRead::listPage(...). channelEdit(?int $id)- Owned by
ChannelEditController. - Loads existing row when id is provided.
- Missing id row triggers flash error + redirect to
/channel. channelSave(array $post, array $files = [])- Owned by
ChannelEditController. - Validates CSRF.
- Sanitizes/normalizes
id,name,slug,descriptionviaInputSanitizer. - Requires non-empty
nameand validslug. - Rejects attempts to create/edit the reserved stock
<root>channel. - Persists optional
feed_enabledwhen global feeds are enabled; existing channel feed flags are preserved when global feeds are disabled. - Saves text fields via
ChannelWrite::save(...). - Processes optional
cover_imageandpreview_imageuploads (single-file each), optional remove flags, and writes image-path columns viaChannelWrite::updateImagePaths(...). - Upload files/variants are stored under
public/uploads/channels/{id}/using configuredmedia.images.*rules. channelDelete(array $post)- Owned by
ChannelEditController. - Validates CSRF.
- Supports single delete (
id) and bulk delete (selected_ids[]). - Refuses to delete the stock
<root>channel. - Removes associated stored cover/preview image files for deleted channels.
- Reports deleted/failed counts for bulk operations.
Data Model And Repository Behavior
ChannelRead + ChannelWrite behavior:
listAll()returns channels with page counts and includes the stock<root>channel first.listOptions()excludes the stock<root>channel because it is only an internal root-scope placeholder.ChannelWrite::save(...)handles create/update in one method.- Channel records include one file-backed
feed_enabledflag for channel-specific feed routes. - Channel records also include file-backed
category_setsandtag_setsselections. - Channel records include a file-backed
theme_overrideslug, orinheritto use the global system theme. - Channel records include a file-backed numeric
parent_id, defaulting to0for the stock<root>channel. ChannelWrite::updateImagePaths(...)persists cover/preview source + variant paths.ChannelWrite::deleteById(...)runs in a transaction:- updates
pages.channel_idto0 - updates
redirects.channelto0 - deletes channel row
listRecords()ensuresprivate/dat/channel/0_root.phpexists with reserved id0, name<root>, and slugroot.
Storage detail:
- SQLite mode uses the shared
private/dat/db.sqlitedatabase. - Non-SQLite mode uses configured table prefix.
Public Routing Touchpoints
- Channel landing routes use the complete parent-aware path
/{channel_path}with page fallback rules. A channel namedalphaundernewstherefore lands at/news/alpha. - Channel index routes use the
Indexmode from the editor.Automaticfollows system slash rules at/{channel_path}; the two explicit slash modes override them;Redirectsends that root to the existing publishedhomeorindexpage route, prioritizinghome. These modes do not apply to other channel pages. - Channel pages resolve at
/{channel_path}/{segment}, where{segment}depends on the leaf channel's effectiveroute_mode. Paths may continue through any number of channel-parent levels. - Every channel segment must resolve as a direct child of the preceding segment; a child slug is not treated as a root channel or resolved globally.
- When global feeds are enabled and a channel has
feed_enabled = true, that channel also exposes/{feed.rss}/{channel_slug}and/or/{feed.atom}/{channel_slug}. - The stock
<root>channel is not routable; root-scope pages/redirects stay at/...instead of/root/.... - When a channel is set to
inherit, it uses the globalcontent.selectordefault (slugorid). Canonical trailing-slash behavior is controlled independently bysite.routing. - Supported channel page-route segments:
/{channel_path}/{page-slug}/{channel_path}/{YYYY-MM-DD}-{page-slug}/{channel_path}/{YYYY-MM}-{page-slug}/{channel_path}/{page-id}/{channel_path}/{YYYY-MM-DD}-{page-id}/{channel_path}/{YYYY-MM}-{page-id}- Channel landing template priority:
tpl/channel/{channel_slug}.phpthentpl/channel/index.php. - Channel landing and channel-page rendering use the channel's effective
theme_override; missing templates/assets continue through the selected theme's parent chain and then the global child/parent/core fallback chain.
Security/Validation Expectations
- Permission gate: channel route permissions (
view,create,edit,delete). - CSRF on POST actions.
- Sanitization via centralized
InputSanitizer. - Repository operations use prepared statements.
Update Discipline
When channel behavior changes, update this document in the same task. That includes list/editor UI controls, routes, save/delete behavior, channel detach semantics, and channel-route behavior.
UI Labels Reference
BasicContentMediaRoutingEditor OverrideThemeRoute ModeRoute SeparatorRouting SettingsTaxonomy AssignmentsChannel Index RouteAutomaticNo Trailing SlashUse Trailing SlashRedirectUse System DefaultUse Global DefaultInherit- (Hyphen)_ (Underscore)/{channel}/{page-slug}/{channel}/{YYYY-MM-DD}-{page-slug}/{channel}/{YYYY-MM}-{page-slug}/{channel}/{page-id}/{channel}/{YYYY-MM-DD}-{page-id}/{channel}/{YYYY-MM}-{page-id}Rich Text (TinyMCE)CodePlaintextMarkdownAutoNextPrevious