Rapid Web Interface Prototyping in Codeigniter Inspired by WordPress //
I recently built out a little setup that allows me to rapidly prototype web interfaces using the speed and agility of the Codeigniter framework. I often work in WordPress, and there are a number of handy functions that it offers. My thinking was that I could easily build a convention in Codeigniter that allowed me to create a few of these functions myself and give me a base setup to easily get up-and-running prototyping Websites and the like. Here is a list of the key functions I wanted to get me started: is_home() is_page() get_header() get_footer() get_template_part(). I couple that with a single $data array of page vars.
The real beauty of this is in Codeigniters convention-over-configuration approach. I approached this setup with the same mindset. All you have to do is know the system and it’s really fast to be slamming little previews of the what-could-be-websites together in short periods of time. Remember, this is really a simple system meant to be accompanied by stubbed and static content for the time being as it is for rapid web prototyping. Hence the title of this post. All the functions here are in a file called common.php located at application/core/common.php. In the last line of the autoload config file I simply add require( APPPATH . 'core/common.php' );
Please note that this post assumes you have a foundational knowledge of Codeigniter. For this, it really doesn’t matter if you have any working knowlege of WordPress.
What is the convention?
Good question! The convention here depends upon smart naming of your controllers and their functions. Right now the system supports page naming utilizing the /controller/function/ segments of the URI structure. Here’s how that works. Make a controller named Product and give it a function listing(). Imagine you visit /product/listing/ and you get a listing of all products. Return the $page var as product-listing and create a file in your views directory called product-listing.php and load that view. Now, anywhere on the page you can call is_page( 'product-listing' ) and it will return true or false.
Here’s is_page()
function is_page( $page ) {
$ci =& get_instance();
$pagename = NULL;
// Grab array of segments and an associative array
// of the segments after /controller/function/
$segments = $ci->uri->segment_array();
$assoc = $ci->uri->uri_to_assoc( 3 );
// Default return true if is_home
if ( is_home( $page ) ) {
return TRUE;
}
// If we have 2+ segments we can check the page name,
// here we are looking for just /controller/function/.
// Page naming is based on convention over configuration,
// so if your controller is "product" and function is "listing"
// you want to return $page as "product-listing" etc.
if ( count( $segments ) >= 2 ) {
$pagename = $ci->uri->segment( 1 ) . '-' . $ci->uri->segment( 2 );
// If we just have 1 segment we only need /controller/
} else if ( count( $segments ) == 1 ) {
$pagename = $ci->uri->segment( 1 );
}
// If the passed $page var is equal to $pagename we have a match
if ( $page == $pagename ) {
return TRUE;
// Otherwise we return false
} else {
return FALSE;
}
}
And is_home() for convenience
function is_home( $page ) {
$ci =& get_instance();
// Grab array of segments
$segments = $ci->uri->segment_array();
// Return true if is_home
if ( !count( $segments ) && $page == 'home' ) {
return TRUE;
} else {
return FALSE;
}
}
What about template parts?
Template parts is really convenient. Based on the above page naming conventions, template parts works by loading a template from the views directory using a custom prefix prepended to the page name. So from the above example we have a page called product-listing. Say we need a promo spot in the header file but it needs to be different for each page. Perfect. Using get_template_part( 'promo', $page ) will load a template from the views directory called promo-product-listing.php. You can use one header file and one line of code with no conditional blocks. As long as you name your $page var correctly and your templates correctly it works beautifully.
Here’s get_template_part()
function get_template_part( $template, $page, $data = array() ) {
// Extract our page data array
extract( $data );
// Create the file path. Here we use a $template + $page system.
// $template is passed as a unique string, such as "promo" and $page
// is the global $page var from the $data array. This is convention
// over configuration, so if $template is "promo" and $page is "product-listing"
// you want to make a template file in the "views" directory called
// "promo-product-listing.php" and so on.
$file = APPPATH . 'views/' . $template . '-' . $page . EXT;
// If the file exists we can require it on the page.
if ( file_exists( $file ) ) {
require( $file );
}
}
How the $data array works in the Controller
To understand this, lets look at a simple controller. We have the __construct() function running as well as the index() function. For this to work I need to return data to my views as an array, in fact a single array with all the data I want in it. This allows me to use PHP extract() on that array and give that data to my header and footer templates that I pull using the get_header() and get_footer() functions. As it stands the only page data I am using for this setup are $page and $title vars.
class Site extends CI_Controller {
// Class global var stores page data
var $data;
public function __construct() {
parent::__construct();
// Redundant, but we need data given to views as an array
$this->data = array();
$this->data['data'] = array();
}
public function index() {
$this->data['data']['page'] = 'home';
$this->data['data']['title'] = 'Home';
$this->load->view( 'page-login', $this->data );
}
}
Header and Footer functions
These are pretty straight forward, place a header.php and footer.php file in the views directory.
function get_header( $data ) {
// Extract our page data array for use in header.php
extract( $data );
$file = APPPATH . 'views/header' . EXT;
// If the file exists we can require it on the page.
// Requires a header.php file in the "views" directory.
if ( file_exists( $file ) ) {
require( $file );
}
}
function get_footer( $data ) {
// Extract our page data array for use in footer.php
extract( $data );
$file = APPPATH . 'views/footer' . EXT;
// If the file exists we can require it on the page.
// Requires a footer.php file in the "views" directory.
if ( file_exists( $file ) ) {
require( $file );
}
}
A couple extras for effect
Even with prototypes we want the effect, so take advantage of these to tackle some of the more subtle aspects like page title and body class. The get_body_class() function is actually really helpful. I have it set up to prepend page- to tany page name for a quick set of custom, dynamic classes that allow you to style with CSS easily.
function get_body_class( $page ) {
// Simple set body className using global $page var
return 'page-' . $page;
}
function get_page_title( $title ) {
// Simple set page title using global $title var
return $title . ' - Your Site';
}
Get the goods
Download the source files for common.php with a readme.txt file.
06 // 08 // 2011
Don't be shy, let's chat //