Pages Controllers
While the "Front-end" documentation explains how to create custom Page Controllers from scratch, this section dives into the Core Controllers provided by Pragma CMS natively, how they work under the hood, and how you can safely override them.
The Core Controllers Directory
Pragma CMS ships with a complete set of default front-end controllers located in /cms-versions/[version]/pages/.
These files act as fallback controllers. If you create a page in the Admin panel but do not provide a custom template or controller in your site's directory, the CMS Router will automatically fall back to these core files to render the content dynamically.
/cms-versions/[version]/pages/ directory. Any changes made here are part of the core system layer and will be overwritten during the next CMS update.The Override System (How to Customize)
Pragma CMS uses a smart cascading resolution system (resolveCascadingPath). If you need to customize the logic of a default controller (for example, modifying how single.php fetches data, or adding custom logic to account/profile.php), you must use the Override System:
- Copy the file you want to customize from the core directory (
/cms-versions/[version]/pages/). - Paste it into your specific site directory:
/sites/<your-site>/pages/ - Edit the copied file.
The CMS Router will automatically detect your overridden file and use it instead of the core controller. This mechanism allows full back-end customization without breaking future updates.
Core Controllers Overview
Here is a breakdown of the default controllers handled by the Core engine:
Content Rendering
list.php: Displays a list of entries from a Collection or a Structure. Handles pagination, sorting, filters, and hierarchical navigation context.single.php: Displays a unique entry. It expects a dynamic{slug}in the URL and automatically resolves parent/child relationships.page.php(The Universal Resolver): Renders all generic pages. It automatically detects and supports three modes:- Static: Simple text pages managed via Summernote.
- Builder: Modular pages built with Editor.js blocks.
- Dynamic (Single): Unique pages linked to a specific Content Type Single (e.g., a "Pricing" or "Contact" page with custom fields).
taxonomy_terms.php: The controller for the front.taxonomies.terms.index route. It fetches the taxonomy metadata and builds the hierarchical tree of terms.taxonomy_term.php(The Term Resolver): This controller handles the display of a specific term. Its logic is polymorphic:- Data Fetching: It retrieves the term's metadata (SEO, icons, images).
- Extensible Logic: It uses the
TAXONOMY_TERM_PAGE_HANDLERShook. This allows extensions to register themselves to be displayed on term pages. For example, the Blog extension tells this controller: "If you find articles linked to this term, here is how to count them, fetch them, and which card template to use." - Multi-Content Support: A single term page can theoretically display multiple types of content (e.g., a "Christmas" tag could display both "Articles" and "Products" in separate sections).
Authentication & Account Area
auth/login.php,auth/register.php,auth/reset_password.php: Standard authentication controllers.account/dashboard.php,account/profile.php,account/settings.php: Secure user-area controllers.
System & Utility
home.php: The dedicated fallback homepage controller.maintenance.php: Returns an HTTP 503 Service Unavailable screen. It preserves SEO and allows bypass access for logged-in administrators.search.php: Global search engine controller handling polymorphic searches across all public content types.
SEO & Crawling
robots.php: Dynamicrobots.txtgenerator adapting to the domain and language, pointing to the correct sitemaps.sitemap.php: Dynamic XML index generator that handles multi-language URLs and pagination for massive websites (>50k URLs).feed.php: RSS / Atom feed generator.
Anatomy of a Core Controller
If you open a core controller like page.php, you will notice a strict, linear execution flow. Pragma CMS controllers are designed to be read from top to bottom.
Understanding this lifecycle is crucial if you intend to override them or inject hooks.
1. Context Resolution
The controller first retrieves the context injected by the Router:
$slug = $page->currentRoute['params']['slug'] ?? '';
$routeHandle = $page->currentRoute['handle'];
2. Data Fetching
It queries the Managers to retrieve the necessary data. If nothing is found, it safely triggers a 404 error.
$pageData = PageManager::getPageBySlug($slug, $_SESSION["lang_id"]);
if (!$pageData || ($pageData['status'] != 1 && !UserManager::isUserAdmin())) {
displayError(getTranslation("The page does not exist"), 404);
exit;
}
3. Data Processing & Hook Injection
Before the data is sent to the view, the core applies Filters. If you are building an extension, this is where you can intercept and modify the page data without overriding the whole file:
// Hook: Allows extensions to modify the $page object before processing
$page = Hooks::applyFilters(Hook::BEFORE_STATIC_PAGE_RENDER, $page);
// ... data resolution logic (Editor.js parsing, native HTML rendering) ...
// Hook: Allows extensions to inject extra view data (e.g., a contact form)
$page->viewData = Hooks::applyFilters(Hook::FILTER_STATIC_PAGE_VIEW_DATA, $page->viewData ?? [], $page);
4. SEO & Core Configuration
The controller automatically builds the canonical URLs, Open Graph tags, and Multilingual Hreflang maps using the SeoManager and LanguageManager.
$page = SeoManager::configureForSingleEntry($page, $page->entry, $site, $routeHandle, $_SESSION["lang_id"]);
$page->hreflangLinks = LanguageManager::getHreflangLinks(
$routeHandle,
$page->entry['page_id'],
$GLOBALS['supported_languages']
);
5. Final Rendering
Finally, the controller defines the layout components (Header, Main, Footer) and executes the template engine.
$page->header = renderHeader($page);
$page->footer = renderFooter($page);
$page->template = $pageData["template_path"] ?? '';
$page->main = renderMain($page);
// Render the final output via base.php
if (strtoupper($_SERVER["REQUEST_METHOD"]) === "GET") {
echo render_template("base.php", $page);
}