Changing Existing Block Types

Improvements?

Let us know by posting here.

Modifying Core Block Type's Default View Template

In Concrete CMS, you can adjust the HTML of core block types for custom projects. This is useful when provided with custom HTML that doesn't match the core block's default output.

For instance, consider this provided HTML with an icon, title, and description:

<div class="thumbnailitem">
    <div class="itemtitle"><span><i class="icon icon-link"></i></span> This is my Item</div>
    <div class="description">This is the description.</div>
</div>

It may seem fitting to use the Feature block type, but its markup is different:

<div class="ccm-block-feature-item">
    <h4><i class="fa fa-pencil"></i> Easy to Edit</h4>
    <p> ... </p>
</div>

Instead of adapting your custom stylesheet to Concrete's elements, you can change the block's output to align with the given HTML.

Example: Customizing the Image Slider Block

For a site using a modified Enterprise theme from Themeforest, it's preferable to use the theme's image slider HTML when the Concrete image slider block is added. The Enterprise theme's CSS is opinionated, and adapting it to Concrete's image slider markup could be challenging.

The theme's image slider's desired look:

Mismatch with Concrete's Image Slider block:

The discrepancy is due to the HTML differences. Instead of modifying the CSS, it's easier to align the HTML output with the theme's expectations.

To do this:

  1. Disable overrides caching in Dashboard > System & Settings > Optimization > Cache & Speed Settings.
  2. Create an override directory in application/blocks for the image slider block.
  3. Copy the Image Slider view template into this directory.
  4. Adjust the PHP in the view.php template without altering the core directory.

For the Enterprise theme's image slider, ensure the variable names set by the block (like the $rows array) remain unchanged. It's mainly the surrounding HTML that requires adjustments. Also, any new data isn't accessible in this view template, so some hardcoded data, like "Travel, PHOTOGRAPHY," may need edits or removal.

Remember: this change affects the Image Slider view HTML everywhere the block is used, except where a custom template is applied.

This method helps adjust a block's output for custom requirements. Ideally, align your themes with Concrete's CSS classes and markup for consistent rendering. But when working with fixed HTML, it's often simpler to adjust the block output than to tweak the CSS to match Concrete's default markup.

Custom View Templates in Concrete CMS

When using core block types in Concrete CMS, there may be situations where you don't want to modify the default view template globally. Instead, you'd prefer to create custom block view templates that can be applied selectively. Here's a guide to achieve that:

Creating a Custom Template File

  1. Disable overrides caching by navigating to Dashboard > System & Settings > Optimization > Cache & Speed Settings.

  2. Set up the directory for your custom template:

    • Create the path: application/blocks/autonav/templates.
    • Name your template file (e.g., for a "Site Map Tree" template: site_map_tree.php).
    • Copy the default view file:
     cp concrete/blocks/autonav/view.php application/blocks/autonav/templates/site_map_tree.php
    
  3. Within the Concrete CMS, when editing the Auto-Nav block, your custom template will be available under the "Design & Custom Template" menu.

Automatically Including CSS and JavaScript in Custom Templates

If your custom template depends on additional CSS or JavaScript, you can include it directly:

  1. Organize your custom template directory:

    mkdir application/blocks/autonav/templates/site_map_tree
    mv application/blocks/autonav/templates/site_map_tree.php application/blocks/autonav/templates/site_map_tree/view.php
    touch application/blocks/autonav/templates/site_map_tree/view.js
    touch application/blocks/autonav/templates/site_map_tree/view.css
    
  2. For greater flexibility, place any *.js files in a js/ directory and any *.css files in a css/ directory within the custom template directory.

Disabling Asset Inclusion at the Theme Level

Themes may include their own CSS styling, potentially making certain view.js or view.css files redundant. To prevent specific files from loading:

public function registerAssets() {
    $this->providesAsset('css', 'blocks/form');
    //... other assets
}

Packaging Custom Templates

For theme developers, the Concrete package format facilitates bundling themes, blocks, and other functionalities. To include custom block templates:

  1. Create appropriate directories within the theme package, e.g., for the Auto-Nav and Page List block:
    • packages/theme_urbanic/blocks/autonav
    • packages/theme_urbanic/blocks/page_list

Setting Default Block to a Custom Template in a Theme

To ensure a custom template is the default for a certain block type within a theme:

  1. Move the customized default view template to the theme's package directory:
mv application/blocks/image_slider/view.php packages/enterprise/blocks/image_slider/template/enterprise_image_slider.php
  1. Update the theme's PageTheme class with the following:
public function getThemeDefaultBlockTemplates()
{
    return array(
        'image_slider' => 'enterprise_image_slider'
    );
}

This ensures that the "Enterprise Image Slider" custom template becomes the default view template for the Image Slider block in the "Enterprise" theme.

Customizing a Core Block Controller in Concrete CMS

Like a block's view template, any file in the block's directory can be duplicated in a website's application directory, and will then override that version of the core block. This includes the controller.php file. For example, say you want to change the behavior of the Search block to search just page titles, instead of all the keyword fields on a particular page. The following are the relevant lines of code that will need to be changed:

if (isset($_REQUEST['query'])) {
    $ipl->filterByKeywords($_q);
}

This is within the do_search() method. Let's override the core search block controller block type, and change this method to filterByName($_q). First, turn off overrides caching via Dashboard > System & Settings > Optimization > Cache & Speed Settings. Until this is turned off Concrete CMS won't look in the application directory unless it knows it has a file in there.

Next, we create an override directory in application/blocks for the search block. Assuming I'm in my web root directory:

mkdir application/blocks/search

Then, create an empty controller.php in this location. So now now we have an empty file at application/blocks/search/controller.php.

Next, add the proper namespace. Since this is in the Application directory, it looks like this:

<?php
namespace Application\Block\Search;

Then, we add a reference to the core search block controller, which we will be extending:

use Concrete\Block\Search\Controller as SearchBlockController;

Then create the class itself, which extends this search block controller:

class Controller extends SearchBlockController

The entire file now looks like this:

<?php
namespace Application\Block\Search;
use Concrete\Block\Search\Controller as SearchBlockController;
class Controller extends SearchBlockController
{

}

Then, all we have to do is copy the do_search() method from the original core class into this class. All other methods will be inherited from the core search class. Once the method is copied, you can change anything you like this within the class, without having to worry about the other methods in the original core class.

Embedding Blocks in a Page Template

There are times when you might want to use a block's functionality within a page without having that block editable through the CMS. For example, say you have a Blog Entry page template that always contains a tag block at a certain spot. You want to use the power of the tags block but don't really need the overhead of making that block editable through the CMS or having to worry about it always being present in page type defaults. Or perhaps you want to use an Auto-Nav block to create a site map without worrying about it being editable through the CMS by some of your editors (and without worrying about advanced permissions.) You can render a block with parameters as though it were added through the CMS by coding it directly into a page template.

Rendering by Block Type Controller

Example 1: Hard-Coding Tags Block

$bt = BlockType::getByHandle('tags');
$c = Page::getByID('/path/to/target/page');
$bt->controller->set('title', t('Tags'));
$bt->controller->set('target', $c);
$bt->render();

Example 2: Hard-Coding Auto-Nav Block with Custom Template

Render a breadcrumb navigation using the Auto-Nav block with certain options, and the built-in Breadcrumb Auto-Nav custom tempate.

$bt = BlockType::getByHandle('autonav');
$bt->controller->orderBy = 'display_asc';
$bt->controller->displayPages = 'top';
$bt->controller->displaySubPages = 'relevant_breadcrumb';
$bt->controller->displaySubPageLevels = 'all';
$bt->render('templates/breadcrumb');

Rendering a Stack

It's even easier to render the contents of a stack. This will be just as immutable on the front-end of the site, but the contents rendered can change over time. Change the stack, not the front-end.

$stack = Stack::getByName('Your Stack Name');
$stack->display();

Limitations

Blocks embedded in this way cannot be cached using block output caching (since they do not have database records, which is what block output caching relies on). They also cannot be interactive – they can post back to the page, but since the page will have no record of such a block being added to it, it can't query to see what blocks can respond to the action URL that the block posts back to.