20 min read

(For more resources related to this topic, see here.)

Creating a custom block type

Creating block types is a great way to add custom functionality to a website. This is the preferred way to add things like calendars, dealer locators, or any other type of content that is visible and repeatable on the frontend of the website.

Getting ready

The code for this recipe is available to download from the book’s website for free. We are going to create a fully functioning block type that will display content on our website.

How to do it…

The steps for creating a custom block type are as follows:

  1. First, you will need to create a directory in your website’s root /blocks directory. The name of the directory should be underscored and will be used to refer to the block throughout the code. In this case, we will create a new directory called /hello_world.

  2. Once you have created the hello_world directory, you will need to create the following files:
    • controller.php
    • db.xml
    • form.php
    • add.php
    • edit.php
    • view.php
    • view.css
  3. Now, we will add code to each of the files. First, we need to set up the controller file. The controller file is what powers the block. Since this is a very basic block, our controller only will contain information to tell concrete5 some details about our block, such as its name and description.
  4. Add the following code to controller.php:

    class HelloWorldBlockController extends BlockController { protected $btTable = “btHelloWorld”; protected $btInterfaceWidth = “300”; protected $btInterfaceHeight = “300”; public function getBlockTypeName() { return t(‘Hello World’); } public function getBlockTypeDescription() { return t(‘A basic Hello World block type!’); } }

    
    
  5. Notice that the class name is HelloWorldBlockController. concrete5 conventions dictate that you should name your block controllers with the same name as the block directory in camel case (for example: CamelCase) form, and followed by BlockController. The btTable class variable is important, as it tells concrete5 what database table should be used for this block. It is important that this table doesn’t already exist in the database, so it’s a good idea to give it a name of bt (short for “block type”) plus the camel cased version of the block name.
  6. Now that the controller is set up, we need to set up the db.xml file. This file is based off of the ADOXMLS format, which is documented at http://phplens.com/lens/adodb/docs-datadict.htm#xmlschema. This XML file will tell concrete5 which database tables and fields should be created for this new block type (and which tables and fields should get updated when your block type gets updated).
  7. Add the following XML code to your db.xml file:

    lt;?xml version=”1.0″?> <schema version=”0.3″> <table name=”btHelloWorld”> <field name=”bID” type=”I”> <key /> <unsigned /> </field> <field name=”title” type=”C” size=”255″> <default value=”” /> </field> <field name=”content” type=”X2″> <default value=”” /> </field> </table> </schema>

    
    
  8. concrete5 blocks typically have both an add.php and edit.php file, both of which often do the same thing: show the form containing the block’s settings. Since we don’t want to repeat code, we will enter our form HTML in a third file, form.php, and

    <?php $form = Loader::helper(‘form’); ?> <div> <label for=”title”>Title</label> <?php echo $form->text(‘title’, $title); ?> </div> <div> <label for=”content”>Content</label> <?php echo $form->textarea(‘content’, $content); ?> </div>

    
    
  9. Once that is all set, add this line of code to both add.php and edit.php to have this HTML code appear when users add and edit the block:

    <?php include(‘form.php’) ?>

    
    
  10. Add the following HTML to your view.php file:

    <h1><?php echo $title ?></h1> <div class=”content”> <?php echo $content ?> </div>

    
    
  11. Finally, for a little visual appeal, add the following code to view.css:

    content { background: #eee; padding: 20px; margin: 20px 0; border-radius: 10px; }

    
    
  12. Now all of the files have been filled with the code to make our Hello World block function. Now we need to install this block in concrete5 so we can add it to our pages.
  13. To install the new block, you will need to sign into your concrete5 website and navigate to /dashboard/blocks/types/. If you happen to get a PHP fatal error here, clear your concrete5 cache by visiting /dashboard/system/optimization/clear_cache (it is always a good idea to disable the cache while developing in concrete5).
  14. At the top of the Block Types screen, you should see your Hello World block, ready to install. Click on the Install button.

  15. Now the block is installed and ready to add to your site!

How it works…

Let’s go through the code that we just wrote, step-by-step.

In controller.php, there are a few protected variables at the top of the class. The $btTable variable tells concrete5 which table in the database holds the data for this block type. The $btInterfaceWidth and $btInterfaceHeight variables determine the initial size of the dialog window that appears when users add your block to a page on their site.

We put the block’s description and name in special getter functions for one reason, to potentially support for translations down the road. It’s best practice to wrap any strings that appear in concrete5 in the global t() function.

The db.xml file tells concrete5 what database tables should be created when this block gets installed. This file uses the ADOXMLS format to generate tables and fields. In this file, we are telling concrete5 to create a table called btHelloWorld. That table should contain three fields, an ID field, the title field, and the content field. The names of these fields should be noted, because concrete5 will require them to match up with the names of the fields in the HTML form.

In form.php, we are setting up the settings form that users will fill out to save the block’s content. We are using the Form Helper to generate the HTML for the various fields. Notice how we are able to use the $title and $content variables without them being declared yet. concrete5 automatically exposes those variables to the form whenever the block is added or edited. We then include this form in the add.php and edit.php files.

The view.php file is a template file that contains the HTML that the end users will see on the website. We are just wrapping the title in an <h1> tag and the content in a <div> with a class of .content.

concrete5 will automatically include view.css (and view.js, if it happens to exist) if they are present in your block’s directory. Also, if you include an auto.js file, it will automatically be included when the block is in edit mode. We added some basic styling to the .content class and concrete5 takes care of adding this CSS file to your site’s <head> tag.

Using block controller callback functions

The block controller class contains a couple of special functions that get automatically called at different points throughout the page load process. You can look into these callbacks to power different functionalities of your block type.

Getting ready

To get started, you will need a block type created and installed. See the previous recipe for a lesson on creating a custom block type. We will be adding some methods to controller.php.

How to do it…

The steps for using block controller callback functions are as follows:

  1. Open your block’s controller.php file.
  2. Add a new function called on_start():

    public function on_start() { }

    
    
  3. Write a die statement that will get fired when the controller is loaded.

    die(‘hello world’);

    
    
  4. Refresh any page containing the block type. The page should stop rendering before it is complete with your debug message.
  5. Be sure to remove the die statement, otherwise your block won’t work anymore!

How it works…

concrete5 will call the various callback functions at different points during the page load process. The on_start() function is the first to get called. It is a good place to put things that you want to happen before the block is rendered.

The next function that gets called depends on how you are interacting with the block. If you are just viewing it on a page, the view() function gets called. If you are adding or editing the block, then the add() or edit() functions will get called as appropriate. These functions are a good place to send variables to the view, which we will show how to do in the next recipe. The save() and delete() functions also get called automatically at this point, if the block is performing either of those functions.

After that, concrete5 will call the on_before_render() function. This is a good time to add items to the page header and footer, since it is before concrete5 renders the HTML for the page. We will be doing this later on in the article.

Finally, the on_page_view() function is called. This is actually run once the page is being rendered, so it is the last place where you have the code executed in your block controller. This is helpful when adding HTML items to the page.

There’s more…

The following functions can be added to your controller class and they will get called automatically at different points throughout the block’s loading process.

  • on_start
  • on_before_render
  • view
  • add
  • edit
  • on_page_view
  • save
  • delete

For a complete list of the callback functions available, check out the source for the block controller library, located in /concrete/core/libraries/block_controller.php.

Sending variables from the controller to the view

A common task in MVC programming is the concept of setting variables from a controller to a view. In concrete5, blocks follow the same principles. Fortunately, setting variables to the view is quite easy.

Getting ready

This recipe will use the block type that was created in the first recipe of this article. Feel free to adapt this code to work in any block controller, though.

How to do it…

In your block’s controller, use the set() function of the controller class to send a variable and a value to the view. Note that the view doesn’t necessarily have to be the view.php template of your block. You can send variables to add.php and edit.php as well. In this recipe, we will send a variable to view.php. The steps are as follows:

  1. Open your block’s controller.php file.
  2. Add a function called view() if it doesn’t already exist:

    public function view() { }

    
    
  3. Set a variable called name to the view.

    $this->set(‘name’, ‘John Doe’);

    
    
  4. Open view.php in your block’s directory.
  5. Output the value of the name variable.

    <div class=”content”> <?php echo $name ?> </div>

    
    

Adding items to the page header and footer from the block controller

An important part of block development is being able to add JavaScript and CSS files to the page in the appropriate places. Consider a block that is using a jQuery plugin to create a slideshow widget. You will need to include the plugin’s JavaScript and CSS files in order for it to work.

In this recipe, we will add a CSS <link> tag to the page’s <head> element, and a JavaScript <script> tag to bottom of the page (just before the closing </body> tag).

Getting ready

This recipe will continue working with the block that was created in the first recipe of this article. If you need to download a copy of that block, it is included with the code samples from this book’s website.

This recipe also makes a reference to a CSS file and a JavaScript file. Those files are available for download in the code on this book’s website as well.

How to do it…

The steps for adding items to the page header and footer from the block controller are as follows:

  1. Open your block’s controller.php file.
  2. Create a CSS file in /css called test.css.
  3. Set a rule to change the background color of the site to black.

    body { background: #000 !important; }

    
    
  4. Create a JavaScript file in /js called test.js.
  5. Create an alert message in the JavaScript file.

    alert(‘Hello!’);

    
    
  6. In controller.php, create a new function called on_page_view().

    public function on_page_view() { }

    
    
  7. Load the HTML helper:

    $html = Loader::helper(‘html’);

    
    
  8. Add a CSS file to the page header:

    $this->addHeaderItem($html->css(‘testing.css’));

    
    
  9. Add a JavaScript file to the page footer:

    $this->addFooterItem($html->javascript(‘test.js’));

    
    
  10. Visit a page on your site that contains this block. You should see your JavaScript alert as well as a black background.

How it works…

As mentioned in the Using block controller callback function recipe, the ideal place to add items to the header (the page’s <head> tag) and footer (just before the closing </body> tag) is the on_before_render() callback function. The addHeaderItem and addFooterItem functions are used to place strings of text in those positions of the web document. Rather than type out <script> and <link> tags in our PHP, we will use the built-in HTML helper to generate those strings. The files should be located in the site’s root /css and /js directories.

Since it is typically best practice for CSS files to get loaded first and for JavaScript files to get loaded last, we place each of those items in the areas of the page that make the most sense.

Creating custom block templates

All blocks come with a default view template, view.php. concrete5 also supports alternative templates, which users can enable through the concrete5 interface. You can also enable these alternative templates through your custom PHP code.

Getting ready

You will need a block type created and installed already. In this recipe, we are going to add a template to the block type that we created at the beginning of the article.

How to do it…

The steps for creating custom block templates are as follows:

  1. Open your block’s directory.
  2. Create a new directory in your block’s directory called templates/.
  3. Create a file called no_title.php in templates/.
  4. Add the following HTML code to no_title.php:

    <div class=”content”> <?php echo $content ?> </div>

    
    
  5. Activate the template by visiting a page that contains this block.
  6. Enter edit mode on the page and click on the block.

    Click on “Custom Template”.

     

     

    
    

  7. Choose “No Title” and save your changes.

There’s more…

You can specify alternative templates right from the block controller, so you can automatically render a different template depending on certain settings, conditions, or just about anything you can think of. Simply use the render() function in a callback that gets called before the view is rendered.

public function view() { $this->render(‘templates/no_title’); }


This will use the no_title.php file instead of view.php to render the block. Notice that adding the .php file extension is not required. Just like the block’s regular view.php file, developers can include view.css and view.js files in their template directories to have those files automatically included on the page.

See also

  • The Using block controller callback functions recipe
  • The Creating a custom block type recipe

Including JavaScript in block forms

When adding or editing blocks, it is often desired to include more advanced functionality in the form of client-side JavaScript. concrete5 makes it extremely easy to automatically add a JavaScript file to a block’s editor form.

Getting ready

We will be working with the block that was created in the first recipe of this article. If you need to catch up, feel free to download the code from this book’s website.

How to do it…

The steps for including JavaScript in block forms are as follows:

  1. Open your block’s directory.
  2. Create a new file called auto.js.
  3. Add a basic alert function to auto.js:

    alert(‘Hello!’);

    
    
  4. Visit a page that contains your block.
  5. Enter edit mode and edit the block.
  6. You should see your alert message appear as shown in the following screenshot:

How it works…

concrete5 automatically looks for the auto.js file when it enters add or edit mode on a block. Developers can use this to their advantage to contain special client-side functionality for the block’s edit mode.

Including JavaScript in the block view

In addition to being able to include JavaScript in the block’s add and edit forms, developers can also automatically include a JavaScript file when the block is viewed on the frontend. In this recipe, we will create a simple JavaScript file that will create an alert whenever the block is viewed.

Getting ready

We will continue working with the block that was created in the first recipe of this article.

How to do it…

The steps for including JavaScript in the block view are as follows:

  1. Open your block’s directory.
  2. Create a new file called view.js.
  3. Add an alert to view.js:

    alert(‘This is the view!’);

    
    
  4. Visit the page containing your block.
  5. You should see the new alert appear.

How it works…

Much like the auto.js file discussed in the previous recipe, concrete5 will automatically include the view.js file if it exists. This allows developers to easily embed jQuery plugins or other client-side logic into their blocks very easily.

Including CSS in the block view

Developers and designers working on custom concrete5 block types can have a CSS file automatically included. In this recipe, we will automatically include a CSS file that will change our background to black.

Getting ready

We are still working with the block that was created earlier in the article. Please make sure that block exists, or adapt this recipe to suit your own concrete5 environment.

How to do it…

The steps for including CSS in the block view are as follows:

  1. Open your block’s directory.
  2. Create a new file called view.css, if it doesn’t exist.
  3. Add a rule to change the background color of the site to black:

    body { background: #000 !important; }

    
    
  4. Visit the page containing your block.
  5. The background should now be black!

How it works…

Just like it does with JavaScript, concrete5 will automatically include view.css in the page’s header if it exists in your block directory. This is a great way to save some time with styles that only apply to your block.

Loading a block type by its handle

Block types are objects in concrete5 just like most things. This means that they have IDs in the database, as well as human-readable handles. In this recipe, we will load the instance of the block type that we created in the first recipe of this article.

Getting ready

We will need a place to run some arbitrary code. We will rely on /config/site_post.php once again to execute some random code. This recipe also assumes that a block with a handle of hello_world exists in your concrete5 site. Feel free to adjust that handle as needed.

How to do it…

The steps for loading a block type by its handle are as follows:

  1. Open /config/site_post.php in your preferred code editor.
  2. Define the handle of the block to load:

    $handle = ‘hello_world’;

    
    
  3. Load the block by its handle:

    $block = BlockType::getByHandle($handle);

    
    
  4. Dump the contents of the block to make sure it loaded correctly:

    print_r($block); exit;

    
    

How it works…

concrete5 will simply query the database for you when a handle is provided. It will then return a BlockType object that contains several methods and properties that can be useful in development.

Adding a block to a page

Users can use the intuitive concrete5 interface to add blocks to the various areas of pages on the website. You can also programmatically add blocks to pages using the concrete5 API.

Getting ready

The code in this article can be run anywhere that you would like to create a block. To keep things simple, we are going to use the /config/site_post.php file to run some arbitrary code.

This example assumes that a page with a path of /about exists on your concrete5 site. Feel free to create that page, or adapt this recipe to suit your needs. Also, this recipe assumes that /about has a content area called content. Again, adapt according to your own website’s configuration.

We will be using the block that was created at the beginning of this article.

How to do it…

The steps for adding a block to a page are as follows:

  1. Open /config/site_post.php in your code editor.
  2. Load the page that you would like to add a block to:

    $page = Page::getByPath(‘/about’);

    
    
  3. Load the block by its handle:

    $block = BlockType::getByHandle(‘hello_world’);

    
    
  4. Define the data that will be sent to the block:

    $data = array( ‘title’ => ‘An Exciting Title’, ‘content’ => ‘This is the content!’ );

    
    
  5. Add the block to the page’s content area:

    $page->addBlock($block, ‘content’, $data);

    
    

How it works…

First you need to get the target page. In this recipe, we get it by its path, but you can use this function on any Page object. Next, we need to load the block type that we are adding. In this case, we are using the one that was created earlier in the article. The block type handle is the same as the directory name for the block.

We are using the $data variable to pass in the block’s configuration options. If there are no options, you will need to pass in an empty array, as concrete5 does not allow that parameter to be blank. Finally, you will need to know the name of the content area; in this case, the content area is called “content”.

Getting the blocks from an area

concrete5 pages can have several different areas where blocks can be added. Developers can programmatically get an array of all of the block objects in an area. In this recipe, we will load a page and get a list of all of the blocks in its main content area.

Getting ready

We will be using /config/site_post.php to run some arbitrary code here. You can place this code wherever you find appropriate, though.

This example assumes the presence of a page with a path of /about, and with a content area called content. Make the necessary adjustments in the code as needed.

How to do it…

The steps for getting the blocks from an area are as follows:

  1. Open /config/site_post.php in your code editor.
  2. Load the page by its path:

    $page = Page::getByPath(‘/about’);

    
    
  3. Get the array of blocks in the page’s content area.

    $blocks = $page->getBlocks(‘content’);

    
    
  4. Loop through the array, printing each block’s handle.

    foreach ($blocks as $block) { echo $block->getBlockTypeHandle().'<br />’; }

    
    
  5. Exit the process.

    exit;

    
    

How it works…

concrete5 will return an array of block objects for every block that is contained within a content area. Developers can then loop through this array to manipulate or read the block objects.

Summary

This article discussed how to create custom block types and integrate blocks in your own website using concrete5’s blocks.

Resources for Article :


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here