Recently I came across an interesting feature in RoR which is known as layout yielding. To understand what it is just imagine that you have a particular template file (layout) specific to your controller, and in that layout file you have a special block called yield. After that whenever there is some output from any method in your controller will be yielded exactly to that block in that layout. Which means all output from your controller will be first replaced into that “yield” block inside that layout, and then whole data will be displayed right away.
So what is the benefit of using that. Simple, it will help to design your website more flexibly. You have a layout, and inside that layout at a particular position you can output all data. This will just minimize the need of splitting a single template into smaller pieces like “header”, “body”, “footer” and so forth, and finally turning them into a single piece manually before rendering the final output.
Let’s have a look at the following image to understand the fact more clearly.

This is a typical website payout where some of its sections are marked. In this layout which sections you think changes most frequently? Definitely the section marked as p3. Now what usually happens when you design a site.
1. Either you write the whole file as template and change the parts you need
2. Or you split them into smaller components and merge those parts while delivering the final output.
Now, with this yield feature all we do is we create a single html file exactly as the design keeping the div of P3 blank. But inside that P3 container div, we will just write some text “{yield}”. Now because of this yield feature, whenever our controller generate some output using any view, CodeIgniter will automatically load that layout file first, then take the output from the view and merge them together.
To enable this excellent yield feature into CodeIgniter we need to write some hook. First, open the file named application/config/hooks.php and add the following line in it.
$hook['display_override'][] = array(
'class' => 'Yielder',
'function' => 'yield',
'filename' => 'Yielder.php',
'filepath' => 'hooks'
);
After that, inside application/hooks folder create a file named “Yielder.php” and inside that file, write the following code.
<? if (!defined('BASEPATH')) exit('No direct script access allowed');
class Yielder
{
function yield()
{
$ci= & get_instance();
$current_output = $ci->output->get_output();
$controller = $ci->uri->segment(1);
$layout = "system/application/layouts/{$controller}.php";
if (file_exists($layout)){
$output = $ci->load->file($layout,true);
$output = str_replace("{yield}",$current_output,$output);
}
else
$output = $current_output;
echo $output;
}
}
?>
And that’s it!! You are done.
Now all you have to do is create a folder inside your application folder named “layouts” and place the layout file named same as controller. For example if your controller name is “abcd” then your layout should be “abcd.php” – But remember to keep a section named {yield} inside that layout. Lets take a look at the complete example below
Controller: controllers/abcd.php
<?
class abcd extends Controller
{
function help()
{
$title = "";
for($i=0; $i";
}
$this->load->view("myviews",array("title"=>$title));
}
}
?>
View : views/myview.php
<?
echo $title;
?>
Layout : layouts/abcd.php
<h1>
Hi there
</h1>
{yield}
<h1>
Happy Ending
</h1>
And the final Output is
/****************************
Hi there
0
1
2
3
4
5
6
7
8
9
Happy Ending
****************************/














22 responses so far ↓
jorge // March 5, 2007 at 9:47 pm |
nice! but what if you have 100 controllers and only need one layout? In your system you have to have 100 layouts. right?
hasin // March 6, 2007 at 10:59 am |
By tweaking the hook it coult be done. Make the following line linking to a fixed file
$layout = “system/application/layouts/{$controller}.php”;
matt // March 13, 2007 at 8:43 am |
This is very nice. I’m trying to figure out if you could specify a layout among a few different ones, like public.php, admin.php, etc. If you make a $type variable in the controller is there any way to access it in the hooks file?
adam // April 5, 2007 at 1:23 pm |
Thanks for the code… helped me understand hooks. I made the following modifications (also changed some class/method/variable names) to allow for more rails like behavior and respond to Jorge and Matt. You can define $layout anywhere in a controller or add it in the class definition… you could also extend CI’s Controller class. If the requested layout isn’t found, the hook rolls to a default layout. For my code to work, all layouts must be .php and live in /views/layouts/ (both easily changed).
THE HOOK:
output->get_output();
if (!preg_match(‘/(.+).php$/’, $CI->layout)){
$CI->layout .= ‘.php’;
}
if ($CI->layout)
{
$requested = BASEPATH . ‘application/views/layouts/’ . $CI->layout;
$default = BASEPATH . ‘application/views/layouts/default.php’;
if (file_exists($requested))
{
$layout = $CI->load->file($requested, true);
$view = str_replace(“{yield}”, $output, $layout);
}
else
{
$layout = $CI->load->file($default, true);
$view = str_replace(“{yield}”, $output, $layout);
}
}
else
{
$view = $output;
}
echo $view;
}
}
?>
SAMPLE CONTROLLER:
adam // April 5, 2007 at 1:25 pm |
sorry… forgot to strip the php tags…
THE HOOK:
if (!defined(‘BASEPATH’)) exit(‘No direct script access allowed’);
class Yield
{
function doYield()
{
$CI =& get_instance();
$output = $CI->output->get_output();
if (!preg_match(‘/(.+).php$/’, $CI->layout)){
$CI->layout .= ‘.php’;
}
if ($CI->layout)
{
$requested = BASEPATH . ‘application/views/layouts/’ . $CI->layout;
$default = BASEPATH . ‘application/views/layouts/default.php’;
if (file_exists($requested))
{
$layout = $CI->load->file($requested, true);
$view = str_replace(“{yield}”, $output, $layout);
}
else
{
$layout = $CI->load->file($default, true);
$view = str_replace(“{yield}”, $output, $layout);
}
}
else
{
$view = $output;
}
echo $view;
}
}
SAMPLE CONTROLLER:
class Test extends Controller
{
public $layout = ‘test’;
function index()
{
echo ‘hello’;
}
}
Rick // April 6, 2007 at 12:22 am |
Correction to the code:
Using the ‘OUT’ global replaces some standard variables like {elapsed_time} etc..
$OUT->_display( $view );
Also improved some if statements etc.
——-
function doYield()
{
global $application_folder, $OUT;
$CI =& get_instance();
$output = $CI->output->get_output();
if ( isset( $CI->layout ) )
{
$app_folder = $application_folder;
if ( !preg_match( ‘/(.+).php$/’, $CI->layout ) )
{
$CI->layout .= ‘.php’;
}
$requested = BASEPATH . $app_folder . ‘/views/layouts/’ . $CI->layout;
$default = BASEPATH . $app_folder . ‘/views/layouts/default.php’;
if (file_exists($requested))
{
$layout = $CI->load->file($requested, true);
$view = str_replace( “{yield}”, $output, $layout );
}
else
{
$layout = $CI->load->file($default, true);
$view = str_replace( “{yield}”, $output, $layout);
}
}
else
{
$view = $output;
}
$OUT->_display( $view );
}
Kalinikos // May 17, 2007 at 10:11 pm |
Nice!
Barry Christianson // July 1, 2007 at 10:45 pm |
Hi man,
Thanx for the hook, it will make my life easier… but perhaps in future make a note to warn people about copying the code from your blog…. those curly quotes cause hell:)
Edd // July 4, 2007 at 7:59 pm |
Traditionally, layouts/ would be located as a subdirectory of /views/, but that’s just me being picky. Thanks very much for this hook, it’s made my life much easier! It’s nice having frameworks like CI to use in parallel to developing on RoR.
Herakles // July 10, 2007 at 7:24 pm |
Cool.
Kostantinos // July 10, 2007 at 8:04 pm |
Cool!
Vasilis // July 11, 2007 at 12:23 am |
Interesting…
Nathanael // July 11, 2007 at 9:17 am |
Nice…
Leo // July 11, 2007 at 10:46 am |
Cool…
Sorin // July 25, 2007 at 4:07 am |
Great job, guys! And great framework for letting you inject something like layouts with such an ease…
Worked like a charm
Demetrios // August 19, 2007 at 10:00 pm |
Nice!
Guilherme Medeiros // October 26, 2007 at 1:21 pm |
Hello! Sorry for my bad English.
I liked a lot of hook and made some improvements that can be conferred on my blog: http://www.web2ponto0.com.br/codeigniter-e-templates-como-no-ror/
Thank you for sharing!
Rakibul Islam // November 15, 2007 at 3:47 pm |
Nice tutorial, will try to implement in the MIST project.
Similarities and dissimilarities between CakePHP & CodeIgniter (Part-I) « Junal on the run // December 14, 2007 at 1:31 am |
[...] CodeIgniter doesn’t have any default layout! I feel this is bad side of CI that it doesn’t have any default layout like Cake. It’s like row php code where I have to include header, footer each and every time I create a new file. To help on it I guess this post is really helpful, have a look here: http://hasin.wordpress.com/2007/03/05/adding-yield-codeigniter/#comment-55979 [...]
zabaka barabaka // January 26, 2008 at 6:37 am |
I was almost done writing same code when I stumbled upon this. Very surprised it’s not part of CI already.
Saul Lopez // July 10, 2008 at 6:12 am |
Hi, I’ve found what I think is a simpler solution for using a global layout :
http://codeigniter.com/wiki/layout_library/
kemkem // August 26, 2009 at 2:38 pm |
Thank you for sharing!