Get the FREE Ultimate OpenClaw Setup Guide →

building-singlepages

npx machina-cli add skill MacareuxDigital/concretecms-skills/building-singlepages --openclaw
Files (1)
SKILL.md
4.3 KB

Building Single Pages in Packages

Single pages are unique pages within a Concrete CMS site that are typically used for administrative dashboards, custom application logic, or specific landing pages that don't follow the standard page type/template system.

Creating a Single Page in a Package

1. File Structure

  • Controller: packages/your_package/controllers/single_page/your_page.php
  • View: packages/your_package/single_pages/your_page.php

The path to the single page is relative to these directories. For example, for a page at /dashboard/my_module/settings:

  • Controller: packages/your_package/controllers/single_page/dashboard/my_module/settings.php
  • View: packages/your_package/single_pages/dashboard/my_module/settings.php

2. Implementation

Controller

The controller should extend Concrete\Core\Page\Controller\DashboardPageController for dashboard pages, or Concrete\Core\Page\Controller\PageController for frontend pages.

<?php
namespace Concrete\Package\YourPackage\Controller\SinglePage\Dashboard\MyModule;

use Concrete\Core\Page\Controller\DashboardPageController;
use Concrete\Core\Package\PackageService;
use Concrete\Core\Config\Repository\Liaison;

class Settings extends DashboardPageController
{
    /**
     * Get package-specific configuration repository.
     */
    protected function getConfig(): ?Liaison
    {
        /** @var PackageService $packageService */
        $packageService = $this->app->make(PackageService::class);
        $package = $packageService->getClass('your_package_handle');
        if ($package) {
            return $package->getFileConfig();
        }

        return null;
    }

    public function view()
    {
        $config = $this->getConfig();
        $settingValue = $config->get('my_module.setting_key', 'default');
        $this->set('settingValue', $settingValue);
    }

    public function save()
    {
        if (!$this->token->validate('save_settings')) {
            $this->error->add($this->token->getErrorMessage());
        }

        if (!$this->error->has()) {
            $config = $this->getConfig();
            $config->save('my_module.setting_key', $this->post('settingValue'));
            $this->flash('success', t('Settings saved successfully.'));
            return $this->buildRedirect($this->action('view'));
        }
        
        $this->view();
    }
}

View

The view is a standard PHP file. For dashboard pages, it's typically wrapped in the dashboard theme.

<?php defined('C5_EXECUTE') or die("Access Denied."); ?>

<form method="post" action="<?= $view->action('save') ?>">
    <?= $token->output('save_settings') ?>
    
    <div class="form-group">
        <?= $form->label('settingValue', t('My Setting')) ?>
        <?= $form->text('settingValue', $settingValue) ?>
    </div>

    <div class="ccm-dashboard-form-actions-wrapper">
        <div class="ccm-dashboard-form-actions">
            <button class="float-end btn btn-primary" type="submit"><?= t('Save') ?></button>
        </div>
    </div>
</form>

3. Installation

In your package controller's install() or upgrade() method:

use Concrete\Core\Page\Single as SinglePage;

public function install()
{
    $pkg = parent::install();
    $page = SinglePage::add('/dashboard/my_module/settings', $pkg);
    if ($page) {
        $page->update(['cName' => 'My Settings']);
    }
    return $pkg;
}

Best Practices

  • Configuration: Use $package->getFileConfig() to get a configuration repository specific to your package. This avoids prefixing all keys with package.your_package_handle..
  • Security: Always use CSRF tokens ($token->output(), $token->validate()) in forms.
  • Redirection: For parent dashboard pages that should just redirect to a child, use $this->buildRedirectToFirstAccessibleChildPage() in the view() method of the parent controller and provide an empty view file. This approach ensures that the user is redirected only to a page they have permission to view.

Source

git clone https://github.com/MacareuxDigital/concretecms-skills/blob/main/building-singlepages/SKILL.mdView on GitHub

Overview

Single pages are unique pages used for admin dashboards, custom application logic, or landing pages that don’t follow the standard page type/template system. This skill covers the file structure, controller/view patterns, and installation steps to add such pages from a package.

How This Skill Works

Place a controller under packages/your_package/controllers/single_page/your_page.php that extends DashboardPageController for dashboards or PageController for frontend pages, and a corresponding view at packages/your_package/single_pages/your_page.php. Use a package-specific config repository via getFileConfig to read/write settings, implement view() to load data, and save() with token validation to persist changes. Register the page during install with SinglePage::add('/dashboard/your_module/settings', $pkg) and optionally rename it to reflect its purpose.

When to Use It

  • Add a dashboard settings page for a Concrete CMS package
  • Create a frontend page that handles custom application logic outside standard templates
  • Provide package-scoped configuration accessible from a single page
  • Automatically install a single page during package install or upgrade
  • Create admin-facing pages that don’t map to standard page types

Quick Start

  1. Step 1: Create the controller at packages/your_package/controllers/single_page/your_page.php and the view at packages/your_package/single_pages/your_page.php
  2. Step 2: Extend DashboardPageController for dashboard pages or PageController for frontend pages; implement view() and save() with proper config access and token checks
  3. Step 3: Install the page by adding it in the package install() with SinglePage::add('/dashboard/your_module/settings', $pkg) and rename it if needed

Best Practices

  • Configuration: Use the package's file config repository via getFileConfig to avoid key prefixing
  • Controller choice: Extend DashboardPageController for dashboard pages or PageController for frontend pages
  • Directory structure: Place controllers in controllers/single_page and views in single_pages following the naming convention
  • Security: Implement token validation in post handlers (e.g., save) to protect actions
  • Installation: Use SinglePage::add('/dashboard/your_module/settings', $pkg) and set a clear cName

Example Use Cases

  • Dashboard page at /dashboard/my_module/settings implemented by a Settings controller extending DashboardPageController
  • getConfig() retrieves package-specific configuration using getFileConfig and stores it into a local variable
  • View form saves settings via a save() action with token validation and a success flash message
  • During install, the page is created with SinglePage::add('/dashboard/my_module/settings', $pkg) and labeled My Settings
  • cName is updated to 'My Settings' to provide a friendly label in the dashboard

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers