Concrete5 Facebook Comments Block Tutorial

Warning! This tutorial is for deprecated Concrete5 versions 5.6 and below. Many of the examples and methods are no longer relevant to modern Concrete5.

In this multi-part tutorial you will learn how to build a basic block from the ground up. These detailed instructions will show you how to plan and execute your block and include tutorials on the add.php, edit.php, xml.db, and controller.php files. When you have completed this tutorial you will have a working Facebook Comments Social Plugin block that will allow website visitors to comment on any of your pages using their Facebook login.

Part 1. Preparing for the build

This step by step tutorial will teach you how to build a simple block that outputs the appropriate html to integrate Facebook connect comments. You can see the results of this tutorial at the bottom of this page. There are no files to be downloaded, this tutorial is designed to teach you how to build a block and can be adapted to any number of other applications. If you don’t want to build the block yourself you can download a functional Facebook comments block from the concrete5 marketplace.

click image to enlarge

click image to enlarge

click image to enlarge

Step 1. Get an application ID from Facebook

The first and unique step for our block will be to register our website with Facebook. This step is required to integrate Facebook connect with your domain. To register visit the following URL:http://www.facebook.com/developers . You will need to log in with your Facebook account to access this portion of Facebook. Currently, there is a “Set Up New Application” button. Click there and create your “application”. Enter an Application name and then create. After solving a Captcha your application will be ready. Click into the “Facebook Integration” Tab and take note of your “Application ID”.

click image to enlarge

click image to enlarge

Step 2. Get the Facebook Comments Snippet

Facebook comments work by inserting a piece of html into your page which in turn loads some JavaScript and requests Facebook to display that pages unique comments. To get the code we need to visit the Facebook plugins page here: http://developers.facebook.com/plugins . This page has a list of all the ready-made Facebook plugins you can use on your website. Click into the “Comments” plugin. Let’s get our snippet by entering “totally_unique_id” into the “Unique ID” text box and then clicking “Get Code”. The resulting popup will have your html snippet.

Step 3. Plan the Concrete5 Block

Now that we have the piece of code that needs to be entered into our pages to show the comments lets analyze it and determine what parts will have to be controlled by our Concrete5 block.

<div id="fb-root"></div>
<script src="http://connect.facebook.net/en_US/all.js#appId=APP_ID&xfbml=1"></script>
<fb:comments xid="totally_unique_id" numposts="10" width="425" publish_feed="true"></fb:comments>

APP_ID: This is the Application ID you created in Step 1. This will need to be the same for every comment block on your entire site, but since we may want to take this block and use it on a different site we can store it as a user entered variable.

xid: This is a unique string that is used by Facebook to identify the comments you want to retrieve. This will need to be different for every instance of the block on your website. Because the Facebook comments block will most likely be automatically created using pagetype defaults this variable should be generated automatically.

numposts: The number of comments that should be displayed on initial load. Additional comments will be paginated. This should be a user defined variable.

width: How wide, in pixels the comments box will be. Also a user defined variable.

publish_feed: Whether or not the “Post comment to my Facebook profile” checkbox should be checked or not. Also should be a user defined variable.

So, after looking at the data required for the Facebook comments snippet it appears we need to allow for the block user to input their Application ID, Number of Posts, Width, and Publish Feed defaults.

Step 4. Preparing the custom concrete5 block directory structure

Finally, fire up your web hosting file manager or FTP client and create a brand new directory beneath the “blocks” directory with the block name in lower case with underscores between the words. In our case we can use “facebook_comments” as the directory name. This block name should remain consistent within all the files we create in this segment but it will typically be CamelCased. Camel Casing is where all underscores and spaces are removed and the proceeding letter is capitalized instead. So within our php files “facebook_comments” will end up being “FacebookComments”.

In the next segment we will begin populating our new block with the files required to make it work.

Part 2: Creating the add.php and auto.js files for user interface and validation

December 1st, 2010

In the last segment “Preparing to build a Facebook Comments Concrete5 Block” we generated our Facebook Application ID , analyzed the snippet required to display the Facebook Comments, and created your new custom block directory. In this part we will create the necessary files for the users interface.

Step 1. Create the add.php file

Within your custom "blocks/facebook_comments" directory, create a file named "add.php". This is a required block file that provides Concrete5 with the form inputs to be presented to the user when they decide to add our block.

Lets start our file with the standard Concrete5 code that only allows our file to be run by the Concrete5 system.

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

In the last segment we decided there were 4 key variables we wanted the user to provide our block. Lets add some html form inputs for each variable.

<div id="facebook_comments_interface">
	<div class="interface_item">
		<p><?php echo t('Facebook Application ID:')?></p>
		<input id="AppID" type="text" name="application_ID" size="20">
	</div>
 
	<div class="interface_item">
		<p><?php echo t('Number of Posts to be displayed per page:')?></p>
		<input type="text" name="num_posts" size="5" value="10">
	</div>
 
	<div class="interface_item">
		<p><?php echo t('Width in Pixels:')?></p>
		<input id="WidgetWidth" type="text" name="width" size="5" value="500">
	</div>
 
	<div class="interface_item">
		<p><?php echo t('Publish Feed Checked by Default:')?></p>
		<input type="checkbox" name="publish_feed"/>
	</div>
</div>

I setup a simple DIV layout for each of our interface items, and then populated those DIVs with a title and then the appropriate form input.. Lets analyze the Application ID form input.

<input id="AppID" type="text" name="application_ID" size="20">

Your Facebook Application ID was a string of numbers so a normal textbox seemed to be the most appropriate input type. There are two paremeters that I want you to pay attention to.

The name="application_ID" parameter will be used to fetch the user submitted data in the controller file. Just give it a good descriptive name.

The id="AppID" paremeter assigns the element a unique ID. This is required only if you want that particular input to be validated against some criteria (not blank for instance). In this block we are going to validate the Application ID and the Width, so you will notice I have created ID's for both of those inputs.

Finally, in order to make the form look halfway decent I have added some CSS styling. This code floats the individual interface elements next to eachother.

<style type="text/css">
	#facebook_comments_interface .interface_item {
	width:100%;
	padding-bottom:30px;
	clear:both;
	}
	#facebook_comments_interface .interface_item p {
	float:left;
	margin: 0 10px 0 0;
	}
	#facebook_comments_interface .interface_item input {
	float:left;
	}
</style>

That completes the add.php file. Later on we will populate a very similar file called edit.php which is used to draw the user interface for a block in edit mode. Before we do that we need to create the validation file so the user can't accidentally break our block.

Step 2. Creating the auto.js validation file

In this step we will be programming some client-side validation for our add.php file. First let me show you the entire file.

// JavaScript Document
 
var FacebookCommentsBlock ={
 
	validate:function(){
		var failed=0; 
 
		var appID=$('#AppID').val();
		if(!appID || appID.length==0){
			alert('Facebook Application ID is Required.');
			$('#AppID').focus();
			failed=1;
		}
		var wWidth=$('#WidgetWidth').val();
		if(!wWidth || wWidth.length==0 || isNaN(wWidth)){
			alert('You must enter a numeric width.');
			$('#WidgetWidth').focus();
			failed=1;
		}
 
		if(failed){
			ccm_isBlockError=1;
			return false;
		}
		return true;
	} 
}
 
ccmValidateBlockForm = function() { return FacebookCommentsBlock.validate(); }

Much of the code above is going to be the same in every auto.js file you build. There is a basic structure to the code that Concrete5 uses to automatically validate your form inputs. I'm only going to zero in on the two custom portions of the file. The "width" validation in particular.

  1. var wWidth=$('#WidgetWidth').val();
  2. if(!wWidth || wWidth.length==0 || isNaN(wWidth)){
  3. alert('You must enter a numeric width.');
  4. $('#WidgetWidth').focus();
  5. failed=1;
  6. }

This should be the basic structure of any form input validation you require.

  • Line 1 : We use a JQuery selector to assign the textbox value to our variable "wWidth".
  • Line 2 : We perform our tests on the data. If I were to convert this line into a sentence, it would read. "IF the wWidth variable doesn't exist OR if the wWidth variable is zero characters in length OR the wWidth variable is not a number execute the statements between the curly braces {}"
  • Line 3 : This line is responsible for alerting the user to what is wrong with his form input.
  • Line 4 : Here we set the web browsers focus to the offending input box. Focus in this case refers to cursor location.
  • Line 5 : Finally, we set the failed variable to true so that Concrete5 knows not to process the form.

Now that we have built the bulk of the user interface files completed we need to create a place for the submitted data to be stored. In the next segment I will describe the importance of the db.xml file and how it is used to create a place for your user variables in the Concrete5 database.

Part 3: Building the db.xml file so Concrete5 knows where to store your data

In Part 1 and Part 2 we prepared for and began building our custom Concrete5 block that integrates the Facebook Comments social plugin. In this segment we will build the db.xml file which is a required block element that tells Concrete5 how to setup the database to store your data.

Step 1. Creating the db.xml file

Go ahead and create a new file in your /blocks/facebook_comments directory named db.xml. An XML file is basic text file that uses tags and structure similar to an html file. The db.xml file is written in a format known as AXMLS. When your block is installed onto your website, Concrete5 parses the contents of this file and uses it as instructions to create new database tables for your blocks data. In Part 2 we created the add.php file which provided the form inputs required from the user. Now we need a place to store those data inputs. Here is what I came up with for our Facebook Comments block.

<?xml version="1.0"?>
<schema version="0.3">
	<table name="btFacebookComments">
		<field name="bID" type="I">
			<key ></key>
			<unsigned ></unsigned>
		</field>
		<field name="application_ID" type="C" size="32">
		</field>
		<field name="num_posts" type="I">
		</field>
		<field name="width" type="I">
		</field>
		<field name="publish_feed" type="L">
		</field>
	</table>
</schema>

The first couple of lines will remain the same for any db.xml file you create. The first line of note is where we use the

tag and define the name parameter as "btFacebookComments" . This tells Concrete5 to create a new table with this name. All table names created for blocks should begin with "bt" and then the Camel Cased block name.

After creating the table we go on to create the fields within the table. The first table field is mandatory for all blocks and is used by Concrete5 to uniquely identify each block instance on the website. The field name is bID and has a data type of "I" or integer. Within the tag there are two additional parameters assigned in the bID field, is shorthand for and assigns this field as the tables primary key. is also shorthand and tells the database that the integer should be a positive number only.

Now let's start creating fields for our user data.

  1. <field name="application_ID" type="C" size="32">
  2. </field>

The first field I created is for our Facebook Application ID. To make things easy name it the same as you did in the html input within the add.php file. The next parameter "type" has been set to "C" which is AXMLS shorthand for VARCHAR or Variable Characters. This allows the field to accept alphanumeric characters as input. The last property "size" is required for the VARCHAR data type. Here I set it to 32 characters, more than enough for the Facebook Application I received.

When deciding on data types for your fields just keep in mind that you are building a standard SQL database table and all the rules and options like Auto Increment, Default, etc. The MYSQL manual is a good place to find out more about the data types available. Because we are using AXMLS you will need to find the appropriate code for the "type" parameter. You can find a bunch more Concrete5 specific information in the C5 db.xml Documentation.

  1. <field name="num_posts" type="I">
  2. </field>
  3. <field name="width" type="I">
  4. </field>
  5. <field name="publish_feed" type="L">
  6. </field>

I decided that the "I" Integer data type would work well for the num_posts and width fields. I used the "L" data type for the publish_feed field which creates a "TINYINT" field. This allows us to store a boolean 1 or 0 to indicate true or false.

That wraps up the db.xml file. This is a common place for things to go wrong, and if your block won't install and throws an ADODB error, you should probably look into your db.xml file for the problem.

Now that we have built an interface for the user to enter the required block variable, and a place to store them in the database it is time to move onto the brain of the block. In the next segment we will build the controller.php file and start putting things into action.

Part 4: Building the controller.php file

December 3rd, 2010

In Part 1, Part 2, and Part 3 of this tutorial we began building our custom Concrete5 block by planning, creating the user interface and preparing the database. In this segment we will begin working on the "brain" of the block. The controller.php file performs many important functions within a Concrete5 block and is usually where the majority of your custom programming will be located.

Step 1. Controller.php basics

First go ahead a create and file within your blocks/facebook_comments folder names controller.php. There are several mandatory functions within the controller.php file that Concrete5 uses to set basic block parameters. Lets start with those.

<?php
defined('C5_EXECUTE') or die("Access Denied.");
class FacebookCommentsBlockController extends BlockController {
 
	protected $btTable = 'btFacebookComments';
	protected $btInterfaceWidth = "325";
	protected $btInterfaceHeight = "175";
	protected $btCacheBlockOutput = true;
	protected $btCacheBlockOutputOnPost = true;
	protected $btCacheBlockOutputForRegisteredUsers = true;
 
}
?>

The first item you should note is that all of the proceeding code will fall within the class we define here on line 3. That means all of the code we add in the proceeding steps should be pasted within the classes curly braces {}.

On the topic of the class, take note of the naming convention. All block classes should be the Camel Cased version of your block name with "BlockController" appended to the end. byextending the BlockController class we inherit all of its methods which is required so don't change anything except your class name.

Next up we set up some internal variables. Here are some brief explanations:

  • $btTable : Make sure this variable is set to the table name you choose when building the db.xml file.
  • $btInterfaceWidth : this is the width in pixels you want Concrete5 to make the interface popup when a user adds or edits your block.
  • $btInterfaceHeight : See above except for height. You will probably have to tweak these a few times after you install your block to get everything looking right.
  • $btCacheBlockOutput : This tells Concrete5 whether or not the output of your block should be cached. This will really depend on your block. In our case, the same snippet will be shown everytime the page is rendered so caching it should be no problem.
  • $btCacheBlockOutputOnPost : More caching options. I am going to assume this tells Concrete5 whether or not to go back to the database if the current page has had data POSTed to it. Drop me a comment if you know otherwise.
  • $btCacheBlockOutputForRegisteredUsers : As above, more caching, this time depending on if a registered user is accessing the page.

Since we are busy assigning variables lets go ahead and plug in our custom block variables here.

public $application_ID = "";
public $num_posts = "";
public $width = "";
public $publish_feed = "";

Here we define our variables that will hold the values entered by the user. Notice they are created with "public" visibility so they can be accessed from outside of the class if necessary.

Step 2. Add the basic class methods

Now that we have all the variables set lets start by adding some required functions, or methods, as they are known within a class.

	public function getBlockTypeDescription() {
		return t("Creates a Facebook Connect Comments Block");
	}
 
	public function getBlockTypeName() {
		return t("Facebook Comments");
	}	 
 
	public function __construct($obj = null) {		
		parent::__construct($obj); 
	}

Each of these basic functions are required by Concrete5 and are used to return simple information about your block.

  • getBlockTypeDescription : This string is used to describe your block within the block listing in the dashboard.
  • getBlockTypeName : This tells Concrete5 the name of your block and shows up in the users block listing.
  • __construct : Tells PHP to use the BlockController Class constructor when initializing this object.

Basically, copy and paste these three functions into your block class and change up the Block name and description. Nothing more to it.

Step 3. Add the save() function

Now that we have the really simple stuff out of the way lets go on to the more custom functions within our class. We have our input interface and created our database. The save() function connects the two together and gets the data the user entered and stores it into the database.

public function save($data) { 
	$args['application_ID'] = isset($data['application_ID']) ? $data['application_ID'] : '';
	$args['num_posts'] = isset($data['num_posts']) ? $data['num_posts'] : '10';
	$args['width'] = isset($data['width']) ? $data['width'] : '500';
	$args['publish_feed'] = isset($data['publish_feed']) ? '1' : '0';
	parent::save($args);
}

For a lot of blocks you may not need to create a save() function. This is because when we declare a save() function within our custom block controller we are simply overriding an existing save() function built into all blocks. Concrete5 will automatically look at the $POST data from your add.php and edit.php form inputs and attempt to save the data into any matching table columns within your custom block table. This is why it is important that the "name" attribute in your form inputs exactly match the field name within your db.xml file.

In this case we are going to override the BlockControllers default save() function because of the "publish_feed" variable. If you remember in Part 3 we setup the publish_feed field with a special data type for boolean values. This means the database expects any data to be stored in the publish_feed field to be either a 1 or a 0. When an html checkbox input is submitted to Concrete5 it assigns it a value of "on" if the checkbox is checked. If we allowed the default save() function to attempt to assign the "on" value to the boolean publish_feed field we would get an ADODB error and nothing would save. So let's go over our custom save() function.

  1. $args['application_ID'] = isset($data['application_ID']) ? $data['application_ID'] : '';

This line sets the $args[] array's 'application_ID' element using a Ternary Comparison which is a shorthand If/Then/Else statement. That means the above code is the same as the following:

  1. if (isset($data['application_ID'])) {
  2. $args['application_ID'] = $data['application_ID'];
  3. } else {
  4. $args['application_ID'] = '';
  5. }

If the 'application_ID' element of the $data[] array is set then we will set the same element within the $args[] array to its value, otherwise set it to empty.

With any luck our auto.js form verification has already caught bad or empty inputs to the controller, but if not this statement is a backup.

We do the same thing for all of the user variables, but with num_posts and width we set a default value instead of empty string in the event of a non input.

With the publish_feed variable instead of simply passing the assigned value of "on" we pass the boolean "1" instead. If publish_feed doesn't exist we set the $args[] as 0.

The final line invokes the original BlockController save() function we overrode and passes our new massaged $args[] array as its argument. Effectively saving the users data into the database.

Step 4. Building the view() function

The final function we will write is the view() function. This code will run when the block is rendered within one of your pages.

	public function view(){ 
		$this->set('application_ID', $this->application_ID); 
		$this->set('num_posts', $this->num_posts); 
		$this->set('width', $this->width);
		$this->set('publish_feed', $this->publish_feed); 
	} 

This last section of code is fairly simple. All we are doing is calling the set() method which allows us to pass the controllers variables into the view. When we build the final major file, view.php, the user variables will be available within the names we set here.

That is everything the controller.php file needs to operate. Remember that all the functions we described here need to be contained within the FacebookCommentsBlockController Class. In the next segment we will build the final major piece of the puzzle, the view.php file.

Part 5: Building the view.php file

In Part 1, Part 2, Part 3 and Part 4 of this custom Concrete5 block tutorial we setup and began building our Facebook Comments social plugin block. With almost all of the major file work completed, this segment details the creation of the view.php file which is responsible for the final rendering of data when our custom block appears within a Concrete5 page.

Step 1. Creating our Unique xid

If you remember way back in Part 1 we decided that while most of the parameters Facebook required for displaying the Comments plugin would be requested from the user and stored in the database, one important parameter, xid, would be auto-generated so it could be unique to every instance of the block. In order to do that the first part of the view.php will be dedicated to pulling some information about the page and block instance. First off, go ahead and create a new file view.php within the blocks/facebook_comments directory. Here's what I came up with for the xid code.

<?php  defined('C5_EXECUTE') or die("Access Denied."); 
 
$page = Page::getCurrentPage();
$handle = $page->getCollectionID();
$baseurl = preg_replace("/[^A-Za-z0-9]/","",BASE_URL);
$handle =  $baseurl. $handle . $bID;

Initially we are going to get the currently rendered page object using the Page:getCurrentPage() function. Then we begin building a unique xid by creating a variable with that name and assigning it the currently rendered pages unique ID. This doesn't go far enough though, because we want to ensure that our xid is completely unique, and we need take into account the possibility of a user adding two discrete Facebook Comments block to the same page.

In order to ensure no one else on the internet is using our xid I decided to incorporate the websites base URL into the xid. The xid is alphanumeric only so using a regex we pull out any colons and slashes.

Finally we rewrite the xid to include the stripped Base URL, then the unique page ID, and finally the block ID, this should give us a totally unique xid which will ensure smooth operation of the Facebook Comments Social Plugin. The xid is how Facebook determines what comments should be pulled into the block. Generally, the page ID and block ID will never change even if a user renames a page, but because we have incorporated the base url, if for some reason the domain changes on a website using this code, all existing comments will be lost and will be started fresh. If you are worried this might happen to you it would probably be wise to simply hard code your unique component into the view.php.

Step 2. Handling the publish_feed variable.

We have one more consideration before we output our html snippet, we need to convert the publish_feed boolean to a string "true" or "false" for inclusion in the snippet.

$publish = ($publish_feed) ? "true" : "false";

I used another one of those ternary comparisons in place of a normal If/Then/Else statement. Basically, if the $publish_feed variable doesn't equal 0 or NULL it will show "true" otherwise it shows "false".

As of this writing the "publish_feed" variable is not supported by Facebook. It's shown in their documents and example, but just doesn't work. So although I have included it in our block, for now your "Publish to Wall" checkbox will always be checked. Hopefully they will fix this later.

Step 3. Print the HTML code

Finally, lets close up the php with the ?> tag and print out our custom HTML code.

?>
 
<div id="fb-root"></div>
<script src="http://connect.facebook.net/en_US/all.js#appId=<?php echo $application_ID; ?>&xfbml=1"></script><fb:comments xid="<?php echo $xid; ?>" numposts="<?php echo $num_posts; ?>" width="<?php echo $width; ?>" publish_feed="<?php echo $publish; ?>"></fb:comments>

If you examine the code it is a very simple matter of taking the original snippet Facebook gave us and everywhere one of our variables is supposed to go inject the PHP code to echo the appropriate variable. That's all there is to it in a simple block like this.

Now that all the major work has been completed there are a few odds and ends that need to be taken care of for our block to work properly. In the final part of this tutorial series I will show you how to create the edit.php file and add the ancillary files that Concrete5 uses when listing your block.

Part 6: Finishing up our custom block

December 6th, 2010

In Part 1, Part 2, Part 3, Part 4, and Part 5 of this tutorial we built up our very own custom Facebook Comments block for Concrete5. In this final segment we will modify the add.php file to create the edit.php file and throw in an icon as well.

Step 1. Create the edit.php file

There is one more file we need for our block to be completely functional. The add.php file contains the html inputs required when the block is first added to a page. The edit.php file is similar. It defines the inputs to be displayed when an existing block is placed into edit mode. For the most part these interfaces should be identical, but in edit mode we need to remember to put the users original values into the html inputs so they know what they currently are. To do this we need to set "value" properties for the text boxes, and we need to decide whether or not the Publish Feed checkbox should come up checked or not. Here is my edit.php in its entirety.

<?php 
defined('C5_EXECUTE') or die("Access Denied.");
if ($controller->publish_feed) {
	$publish = "CHECKED";
}
?>
 
<div id="facebook_comments_interface">
	<div class="interface_item">
		<p><?php echo t('Facebook Application ID:')?></p>
		<input id="AppID" type="text" name="application_ID" size="20" value="<?php echo $controller->application_ID ?>">
	</div>
 
	<div class="interface_item">
		<p><?php echo t('Number of Posts to be displayed per page:')?></p>
		<input type="text" name="num_posts" size="5" value="<?php echo $controller->num_posts ?>">
	</div>
 
	<div class="interface_item">
		<p><?php echo t('Width in Pixels:')?></p>
		<input id="WidgetWidth" type="text" name="width" size="5" value="<?php echo $controller->width ?>">
	</div>
 
	<div class="interface_item">
		<p><?php echo t('Publish Feed Checked by Default:')?></p>
		<input type="checkbox" name="publish_feed" <?php echo $publish ?>/>
	</div>
</div>
 
<style type="text/css">
	#facebook_comments_interface .interface_item {
	width:100%;
	padding-bottom:30px;
	clear:both;
	}
	#facebook_comments_interface .interface_item p {
	float:left;
	margin: 0 10px 0 0;
	}
	#facebook_comments_interface .interface_item input {
	float:left;
	}
</style>

For the most part we just need to add the value parameter and plug in a PHP echo that reaches back into our BlockController and prints the desired variable. The checkbox yet again proves to be the exception, so the first bit of PHP simple sets a $publish variable to "CHECKED" if the boolean returns true. The term "CHECKED" within a checkbox input sets the default state of that checkbox.

The rest of the file is pretty self-explanatory.

Step 2. Adding your Thumbnail

For that final bit of polish we can add a thumbnail that will be displayed next to our block within listings. Block icons are simple 16 x 16 png files. When I'm on the go I like to use a cool online tool known as pixlr.com to build graphics. Here is what I came up with. icon.png

Put that into the blocks/facebook_comments directory and you are ready to install.

Step 3. Installing your new block

Installing a block on your Concrete5 website is simple. After you have copied your block folder into the blocks/ directory go to your dashboard's "Add Functionality" page. Any uninstalled blocks will show up in the right column. Install and then start adding to your pages!