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
- Identify the Block Type: Determine which block type you want to create a template for (e.g.,
autonav,content,image). - Find the Default Template:
- Locate the original
view.phpfor the block. Usually inconcrete/blocks/block_handle/view.php. - DO NOT modify this file.
- Locate the original
- 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
- Theme:
- Create a new file in your theme or package:
- Insert Static Markup: Paste your static HTML markup into the new file.
- Inject Dynamic Data:
- Open the original
view.phpyou 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.');
- Open the original
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_listinstead oftemplate1). - Avoid Conflicts: Do not use
viewas 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.phpbecomes "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 useh()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.cssandview.jsif 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:use Concrete\Core\User\User; $u = app(User::class); if ($u->isRegistered()) { // User is logged in } - Page Object: Usually available as
$c. If not, usePage::getCurrentPage(). - URL Facade: Use
Url::to('/path')for generating links.