





















































(For more resources related to this topic, see here.)
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.
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.
The steps for creating a custom block type are as follows:
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!'); } }
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>
<?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>
<?php include('form.php') ?>
<h1><?php echo $title ?></h1> <div class="content"> <?php echo $content ?> </div>
content { background: #eee; padding: 20px; margin: 20px 0; border-radius: 10px; }
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.
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.
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.
The steps for using block controller callback functions are as follows:
public function on_start() { }
die('hello world');
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.
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.
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.
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.
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.
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:
public function view() { }
$this->set('name', 'John Doe');
<div class="content"> <?php echo $name ?> </div>
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).
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.
The steps for adding items to the page header and footer from the block controller are as follows:
body { background: #000 !important; }
alert('Hello!');
public function on_page_view() { }
$html = Loader::helper('html');
$this->addHeaderItem($html->css('testing.css'));
$this->addFooterItem($html->javascript('test.js'));
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.
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.
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.
The steps for creating custom block templates are as follows:
<div class="content"> <?php echo $content ?> </div>
Click on "Custom Template".
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.
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.
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.
The steps for including JavaScript in block forms are as follows:
alert('Hello!');
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.
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.
We will continue working with the block that was created in the first recipe of this article.
The steps for including JavaScript in the block view are as follows:
alert('This is the view!');
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.
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.
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.
The steps for including CSS in the block view are as follows:
body { background: #000 !important; }
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.
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.
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.
The steps for loading a block type by its handle are as follows:
$handle = 'hello_world';
$block = BlockType::getByHandle($handle);
print_r($block); exit;
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.
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.
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.
The steps for adding a block to a page are as follows:
$page = Page::getByPath('/about');
$block = BlockType::getByHandle('hello_world');
$data = array( 'title' => 'An Exciting Title', 'content' => 'This is the content!' );
$page->addBlock($block, 'content', $data);
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".
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.
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.
The steps for getting the blocks from an area are as follows:
$page = Page::getByPath('/about');
$blocks = $page->getBlocks('content');
foreach ($blocks as $block) { echo $block->getBlockTypeHandle().'<br />'; }
exit;
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.
This article discussed how to create custom block types and integrate blocks in your own website using concrete5's blocks.