building-block-templates · git:20260913.db96265 · 2026-09-13 · sha256 1a24aad3848fc02c
building-block-templates git:20260913.db96265A
Immutable. This exact content is served forever at /api/v1/blob/1a24aad3848fc02c.
---
name: building-block-templates
description: Create custom templates for Concrete CMS block types. Use this skill when you need to change the markup of an existing block type without modifying its core files.
---
# Building Block Templates
Custom templates allow you to override the default view of a block type. This is useful for styling blocks to match your theme or adding specific functionality.
## Basic Workflow: Static Markup to Custom Template
1. **Identify the Block Type**: Determine which block type you want to create a template for (e.g., `autonav`, `content`, `image`).
2. **Find the Default Template**:
- Locate the original `view.php` for the block. Usually in `concrete/blocks/block_handle/view.php`.
- **DO NOT** modify this file.
3. **Create the Custom Template File**:
- Create a new file in your theme or package:
- Theme: `application/themes/your_theme/blocks/block_handle/templates/your_custom_template_name.php`
- Package: `packages/your_package/blocks/block_handle/templates/your_custom_template_name.php`
4. **Insert Static Markup**: Paste your static HTML markup into the new file.
5. **Inject Dynamic Data**:
- Open the original `view.php` you found in step 2.
- Identify the variables used (e.g., `$controller`, `$bID`, `$content`).
- Replace the static parts of your markup with the PHP code from the default template to output the actual block data.
- Ensure you include the mandatory header: `defined('C5_EXECUTE') or die('Access Denied.');`
## Custom Template Naming Rules
- **Format**: Use `snake_case` (e.g., `feature_grid`, `hero_banner`).
- **Descriptive**: Choose a name that clearly describes the purpose or appearance (e.g., `simple_list` instead of `template1`).
- **Avoid Conflicts**: Do not use `view` as a template name, as it is reserved for the default view.
- **Display Name**: Concrete CMS will automatically convert the filename to a readable name in the UI (e.g., `feature_grid.php` becomes "Feature Grid").
## Basic Checklist for Block Templates
- [ ] **Access Check**: Does the file start with `defined('C5_EXECUTE') or die('Access Denied.');`?
- [ ] **XSS Prevention**: Are you escaping data correctly? Use the shorthand `<?= h($variable) ?>` for **ALL** output that shouldn't contain trusted HTML. Even if you think the data is safe, it's a best practice to use `h()` to prevent potential XSS vulnerabilities.
- [ ] **Localization**: Are strings wrapped in the translation function? Use `<?= t('Your String') ?>`.
- [ ] **Edit Mode Support**: Does the block still look/work correctly when the page is in edit mode? Sometimes you need to wrap JS-heavy templates in a check: `if (!$c->isEditMode()) { ... }`.
- [ ] **Asset Loading**: If the template requires specific CSS or JS, are they being required properly via the controller or by adding them to the template directory (Concrete will auto-load `view.css` and `view.js` if they are in the template folder)?
- [ ] **Empty State**: Does the template handle empty data gracefully?
## Commonly Used Data and Performance
- **User State**: To check if a user is logged in, use the application container and the `isRegistered()` method for better performance and to avoid deprecated methods:
```php
use Concrete\Core\User\User;
$u = app(User::class);
if ($u->isRegistered()) {
// User is logged in
}
```
- **Page Object**: Usually available as `$c`. If not, use `Page::getCurrentPage()`.
- **URL Facade**: Use `Url::to('/path')` for generating links.