Creating a Block in concrete5

Published on March 1, 2013 by

Creating a block in concrete5 might seem difficult at first, but once you get the hang of it, it is not difficult at all. Please note that a block can easily be installed within a package. However, this tutorial focuses only on creating a new block. By creating a block, webmasters can easily add and remove it from anywhere on a site as well as make changes to it.

Making the Skeleton

Start by creating a new folder within your project root’s blocks folder. The name should match the name of the block, so if you wish to implement a contact form, then an appropriate block name would be “contact”. This is the example we will be using in this tutorial.

Secondly, we have to add a controller class for the block. If you are familiar with the MVC pattern, then the purpose of a controller is nothing new to you. Put very simply, a controller is controlling the flow of an application; it takes requests, processes them and forwards the results to the view, which is often referred to as the presentation layer. Within the newly created directory, create a file named controller.php and put in the following content for now. Remember to include the PHP start tag. An explanation will follow.

defined('C5_EXECUTE') or die("Access Denied.");

class ContactBlockController extends BlockController
{
	protected $btTable = 'btContact';

	/**
	 * Used for internationalization (i18n). If we want to localize the name/description, we have to include this
	 */
	public function getBlockTypeDescription() {
		return t('Displays a contact form which users can use to send e-mail messages to the site owner.');
	}

	public function getBlockTypeName() {
		return t('Contact');
	}

	public function view() {
		// Executed when the block is rendered
	}
	
	public function add() {
		// Executed when the block is added to a page
	}
	
	public function edit() {
		// Executed when a block instance is edited
	}
}

First, we check to see if C5_EXECUTE is defined. This is concrete5’s way of ensuring that the file called through index.php in the project root and not directly. There are numerous disadvantages to this approach and it is arguably a poor one, but it is nevertheless the recommended way of doing this in concrete5.

Moving along to the name of our class, we can see that it has the form of [block_name]BlockController where the first letter of the block name is capitalized by using Pascal case. Pascal case is the same as camel case except that the first letter is always capitalized. The class extends the class BlockController, which is responsible for installing the block, saving its data and rendering templates.

We should specify the name of the database table in which the block data will be saved. There are a number of other properties that can be defined to override the default values, but this is not necessary at the moment. Then we have methods for retrieving the name and description of the block. These can be defined as properties as well, but implementing these methods allows us to make the strings translatable. The view(), add() and edit() methods will be discussed in a moment. That is all we need to have in our controller to get started.

We then need to create three new files within our block folder; add.php, edit.php and view.php. As you might have guessed, add.php is rendered when users wish to add the block to a page, edit.php when an existing block instance is edited and view.php when the block is displayed on a page.

Dynamically Rendering Templates

Sometimes it may be necessary to have more than one template file and dynamically decide which one to make use of based on certain conditions. For this purpose, the BlockController class provides a render($view) method which takes the view – or template – file name (without the .php extension) as its single parameter. Within controller.php, one could do like this:

public function view() {
	// Use a different view file if the request is a postback
	if ($this->isPost()) {
		$this->render('block_postback_view');
	}
}

A file with the name block_postback_view.php will then be rendered instead of view.php, given that the request is a postback.

Displaying the Contact Form

In view.php, you can basically put any HTML or PHP you want, but we often need to show dynamic content. To do this, we can make use of our controller. We will show how to do this in just a moment, but first let us simply display the contact form by adding the following code.

<?php defined('C5_EXECUTE') or die("Access Denied.");

global $c; ?>

<form method="post" action="<?php echo $this->action('contact_submit'); ?>">
	<label for="txtContactTitle"></label>
	<input type="text" name="txtContactTitle" />
	
	<br /><br />
	
	<label for="txtFromEmail"></label>
	<input type="text" name="txtFromEmail" />

	<br /><br />
	
	<label for="taContactMessage"></label>
	<textarea name="taContactMessage"></textarea>
	
	<br /><br />
	
	<input type="submit" name="btnContactSubmit" />
</form>

Please note that you would normally make use of the Form helper to generate the HTML markup, but for the sake of simplicity, we have just hard coded the HTML markup. By using the form helper, values are automatically refilled into the form elements on postback.

Every time the block is displayed, the controller’s view() method is invoked and the above form will be displayed. When the form is submitted, we need to handle the request, i.e. verifying the element values and potentially sending off the contact message. To do this, we use the action() method in view.php to generate the action URL for us. This URL is constructed such that with the parameter contact_submit, it will map to the controller’s action_contact_submit method.

Handling Contact Requests

Now we will add some code to our controller class. Add the following method:

public function action_contact_submit() {
	if (!$this->isPost()) {
		return;
	}
	
	$post = $this->post();

	$title = $post['txtContactTitle'];
	$fromEmail = $post['txtFromEmail'];
	$message = $post['taContactMessage'];

	/* Input validation omitted */
	
	$mailHelper = Loader::helper('mail');
	$mh->setSubject($title);
	$mh->setBody($message);
	$mh->to([email protected]');
	$mh->from($fromEmail);
	$mh->sendMail();
	
	$this->set('success', t('Your message was sent successfully.'));
}

Please note that the above code is greatly simplified and omits things such as validation and error handling and should thus not be used in production. The code is kept as simple as possible for demonstration purposes. Initially, we verify that the request is a POST request; otherwise, we just disregard the rest of the code. Then we store the POST data in a $post variable for convenience, such that retrieving POST values is a little easier. The mail helper is used to send an e-mail to the site owner, and lastly, a success message is set on the view. This allows us to present feedback to the user to indicate if everything went well.

After submitting the form, we can then access this variable within view.php like shown below.

<?php if (!empty($success)) { ?>

<div class="success"><?php echo $success; ?></div>

<?php } ?>

Therefore, variables added via the controller’s set method are available with the same name within the scope of the view script.

A little trick that you are likely to come across is to use the same file for setting up your form for both add.php and edit.php. It is common practice to create a form_setup_html.php file which is then included in each of the two files, for instance like this:

// add.php or edit.php
defined('C5_EXECUTE') or die("Access Denied.");

$this->inc('form_setup_html.php');

This means that you do not have to write the same form markup twice. In the form file, you can reference the block’s data with variables that are set automatically. For instance, if you have a description column in your block’s table (defined in db.xml), then this value is available with the $description variable. It is common to use data variables to fill out the form’s inputs (e.g. text inputs) such that the existing data is filled in when editing the block (when edit.php is rendered).

Adding the Database Table

You will also have to add a db.xml file within your block’s folder in order to create a database table for the block, which can be used for block versioning. concrete5 will automatically parse this file and create a table for your block on block installation. If you do not need to store data together with your block, then the below is sufficient. Otherwise, doing so is very easy.

<?xml version="1.0"?>
<schema version="0.3">
    <table name="btContact">
        <field name="bID" type="I">
            <key />
            <unsigned />
        </field>
    </table>
</schema>

If you wish to store a description with your block, for instance, then one could simply add a line like this:

<?xml version="1.0"?>
<schema version="0.3">
    <table name="btContact">
        <field name="bID" type="I">
            <key />
            <unsigned />
        </field>

        <field name="description" type="C" size="200"></field>
    </table>
</schema>

Finished

Provided that you have followed the steps and that I have not forgotten anything, you should be able to install your block in concrete5’s dashboard.

That is a very fast explanation off the top of my head on how to create a block in concrete5. While this tutorial does not give you a complete understanding of how to create blocks in concrete5, it does serve as a decent starting point. I hope I have not forgotten anything important; otherwise, you are more than welcome to ask questions and leave comments below.

Author avatar
Bo Andersen

About the Author

I am a back-end web developer with a passion for open source technologies. I have been a PHP developer for many years, and also have experience with Java and Spring Framework. I currently work full time as a lead developer. Apart from that, I also spend time on making online courses, so be sure to check those out!

2 comments on »Creating a Block in concrete5«

  1. Wow – Thanks for this! The official C5 documentation is far from as extensive!

    One thing of note as it was a real “gotcha” for me is the function action_**() naming convention.. It’s maybe worth making a bigger point of as I totally missed it and as a result couldn’t call the method in my controller. :(

    Thanks again!

    • Hello Alex,

      I agree that the official documentation is often rather inadequate. That was also my motivation for writing up this article. Thank you for the feedback, and I am happy that this article helped you.

Leave a Reply

Your e-mail address will not be published.