Step 12 – Creating and using page templates in CodeIgniter

(created at: January 9, 2015; last update: January 23, 2015)

In the previous step (Creating the famous MY_Controller) I left you with a bad taste on your mouth… An ugly as hell invocation of the view.

Usually, when I want to output something to the browser, I simply do a $this->load->view(‘the_view’, $data); and that’s it. Inside the the_view.php I also load the parts that stay unchanged, like the header and footer, with the same $this->load->view(‘the_header’); and $this->load->view(‘the_footer’). But, that is a repetition in itself, isn’t it?

So why not, instead of using $this->load->view… we only call a rendering function that will apply the master template to the specific view/content requested by a method ? Being something that will be repeated across a lot of methods, we will define the rendering function inside the MY_Controller. We will take over the code from our previous step and work on it:

<?php defined('BASEPATH') OR exit('No direct script access allowed');

class MY_Controller extends CI_Controller
{
  protected $data = array();
  function __construct()
  {
    parent::__construct();
    $this->data['pagetitle'] = 'My CodeIgniter App';
  }

  protected function render()
  {
    $this->load->view('templates/master_view', $this->data);
  }
}

Now, that we’ve asked for it, let’s create the master_view.php. As you can see we ask the the view from the templates folder, which will have to be created inside the views directory.

Let’s look in the views directory:

-application/
- -views/
- - -errors/
- - -welcome_message.php

As you can see, there are a lot of “errors” in there. Those files belong to the CodeIgniter and are served when an error appear inside our app. Of course, you can change their look.

In there we also see the welcome_message.php which also comes with the framework, being served by the default controller.

Inside views directory let’s create a directory named templates and inside the templates we will create master_view.php. For the moment, we will create a basic html structure:

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title>My CodeIgniter App</title>
</head>
<body>

  <header>
    <nav>
      <ul>
        <li>My menu item</li>
      </ul>
    </nav>
  </header>

  <section>
    <p>Here is where i will put the text</p>
  </section>

  <aside> 
    <p>Here is a sidebar</p>
  </aside>

  <footer>
    <p>Copyright 2009 My CodeIgniter app</p>
  </footer>

</body>
</html>

If we did everything right we should see our page if we visit http://localhost/

Now we have to optimise the code.

So let’s separate header, sidebar and footer from our master_view.php. To do this we will create a directory inside templates named _parts and the files inside the _parts will be:

master_header_view.php:

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title>My CodeIgniter App</title>
</head>
<body>

  <header>
    <nav>
      <ul>
        <li>My menu item</li>
      </ul>
    </nav>
  </header>

master_sidebar_view.php:

<aside>
  <p>Here is a sidebar</p>
</aside>

master_footer_view.php:

  <footer>
    <p>Copyright 2009 My CodeIgniter app</p>
  </footer>
</body>
</html>

Now, the master_view.php will look like:

<section>
  <p>Here is where I will put the text</p>
</section>

But we need to append those header, sidebar and footer views to the master view:

<?php
  $this->load->view('templates/_parts/master_header_view');
?>
<section>
  <p>Here is where I will put the text</p>
</section>
<?php
$this->load->view('templates/_parts/master_sidebar_view');
$this->load->view(templates/_parts/'master_footer_view');
?>

Now, on the render method we request for the master template:

protected function render()
{
  $this->load->view('templates/master_view', $this->data);
}

Apply the master template to pages

Well… we rendered the master template, but where will the content of pages fit into this? Let’s pass the page’s view as parameter to the render method:

protected function render($the_view = NULL)
{
$this->data['the_view_content'] = (is_null($the_view)) ? '' : $this->load->view($the_view,$this->data, TRUE);
$this->load->view('templates/master_view', $this->data); }

The $the_view variable should contain a view that is particular to the controller’s method. So let’s create one named homepage_view.php:

<h1>Hello from homepage</h1>

<p>testing homepage view</p>

Now we have to change the master_view.php a bit to insert the page view:

<?php
$this->load->view('templates/_parts/master_header_view');
?>
<section>
  <?php echo $the_view_content;?>
</section>
<?php
$this->load->view('templates/_parts/master_sidebar_view');
$this->load->view('templates/_parts/master_footer_view');
?>

Using more than one template?

Now, let’s put this into perspective. What if our site will use two or more templates. Let’s say, we have a one column template for static pages and two column template for posts? Then we can change the render() method to receive another parameter that will decide what template will be used:

protected function render($the_view = NULL, $template = 'master')
{
  $this->data['the_view_content'] = (is_null($the_view)) ? '' : $this->load->view($the_view,$this->data, TRUE);
  $this->load->view('templates/'.$template.'_view', $this->data);
}

Simple, no?

Now let’s return to our header…

The page title…

In the header we have the title tag. We already defined the generic title in the MY_Controller class, so why not replace the hard-coded title with the generic title:

<title><?php echo $pagetitle;?></title>

Return JSON instead of a page? Why not?

I don’t know if this can be part of this specific step, but why not allow the render method to decide if it returns a html page or a JSON string. Until I decide if this will be a new step let’s modify the render() method a bit:

protected function render($the_view = NULL, $template = 'master')
{
  if($template == 'json' || $this->input->is_ajax_request())
  {
    header('Content-Type: application/json');
    echo json_encode($this->data);
  }
  else
  {
    $this->data['the_view_content'] = (is_null($the_view)) ? '' : $this->load->view($the_view,$this->data, TRUE);
    $this->load->view('templates/'.$template.'_view', $this->data);
  }
}

I don’t know if this works, but is worth a try…

What if we don’t want any template used?

Now, what about using no templates? For this we should change it again:

protected function render($the_view = NULL, $template = 'master')
{
  if($template == 'json' || $this->input->is_ajax_request())
  {
    header('Content-Type: application/json');
    echo json_encode($this->data);
  }
  elseif(is_null($template))
  {
    $this->load->view($the_view,$this->data);
  }
  else
  {
    $this->data['the_view_content'] = (is_null($the_view)) ? '' : $this->load->view($the_view,$this->data, TRUE);
    $this->load->view('templates/'.$template.'_view', $this->data);
  }
}

 The final code

So, let’s recapitulate by re-viewing the files we created/modified:

<?php defined('BASEPATH') OR exit('No direct script access allowed');

class MY_Controller extends CI_Controller
{
  protected $data = array();
  function __construct()
  {
    parent::__construct();
    $this->data['pagetitle'] = 'My CodeIgniter App';
  }

  protected function render($the_view = NULL, $template = 'master')
  {
    if($template == 'json' || $this->input->is_ajax_request())
    {
      header('Content-Type: application/json');
      echo json_encode($this->data);
    }
    elseif(is_null($template))
    {
      $this->load->view($the_view,$this->data);
    }
    else
    {
      $this->data['the_view_content'] = (is_null($the_view)) ? '' : $this->load->view($the_view,$this->data, TRUE);;
      $this->load->view('templates/'.$template.'_view', $this->data);
    }
  }
}

 

<?php
$this->load->view('templates/_parts/master_header_view');
?>
<section>
  <?php echo $the_view_content;?>
</section>
<?php
$this->load->view('templates/_parts/master_sidebar_view');
$this->load->view('templates/_parts/master_footer_view');
?>

 

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title><?php echo $pagetitle;?></title>
</head>
<body>

<header>
<nav>
<ul>
<li>My menu item</li>
</ul>
</nav>
</header>

 

<aside>
<p>Here is a sidebar</p>
</aside>

 

<footer>
<p>Copyright 2009 My CodeIgniter app</p>
</footer>

</body>

</html>

 

<?php defined('BASEPATH') OR exit('No direct script access allowed');

class Welcome extends MY_Controller {

  function __construct()
  {
    parent::__construct();
  }

  public function index()
  {
    //$this->data['pagetitle'] = 'test'; ...you can at any time change the variables declared in the MY_Controller...
    $this->render('homepage_view');
    //$this->render(NULL, 'json'); ....if we want to render a json string. Also, if a request is made using ajax, we can simply do $this->render()
  }

}

 

<h1>Hello from homepage</h1>

<p>testing homepage view</p>

One more thing… Why not use the parser library or some kind of templating engine?

Some people might ask why not use the parser library or a templating language? My answer would be: What for? PHP is the fastest.

See you all on our next endeavor in the world of CodeIgniter.

34 comments

  1. Thank you for such awesome tutorials on Codeignitor 3, I am busy learning Codeignitor and rewriting the above site. I had started with Codeignitor 2.2 but am now trying to convert it to the new version. Once again thank you so much for sharing your knowledge about the new version.

    Regards

    Alan

    1. Thank you for your kind words. If you have any ideas of what other subjects I should approach in my tutorials, please leave me a comment.

  2. Hello,
    Thanks for this friendly and cool tutorial!

    But regarding to this tutorial step, I got an error about the variable:
    A PHP Error was encountered
    Severity: Notice
    Message: Undefined variable: content

    Whereas, just like yours the content variable is defined in MY_Controller class:
    $this->data[‘content’] = (is_null($the_view)) ? ” : $this->load->view($the_view, $this->data, TRUE);

    Please, would you explain to me about this? Waht I did wrong? I am confused.

    1. I wouldn’t know what to say, as nowhere in my tutorial am I talking about $this->data[‘content’]. I am talking about $this->data[‘the_view_content’] (or did I miss something and I don’t see it?)… Anyway, I would need more details regarding your script.

  3. Correction from the question before. After I delete the model I loaded in the controller, it shows this error instead:

    A PHP Error was encountered
    Severity: Notice
    Message: Array to string conversion

    Filename: core/MY_Controller.php
    Line Number: 23

    Backtrace:
    File: C:\xampp\htdocs\sidak\application\core\MY_Controller.php
    Line: 23
    Function: _error_handler

    File: C:\xampp\htdocs\sidak\index.php
    Line: 292
    Function: require_once

    More confusing than before -__-

  4. Great tutorial…as usual.
    I’m interested in learning more about
    if($template == ‘json’ || $this->input->is_ajax_request()) { header(‘Content-Type: application/json’); echo json_encode($this->data); }
    Adrian, do you think it would be possible to have a tutorial about this?
    Thanks

  5. I’m trying to add AJAX funcionality using your great render system. I’d like to use AJAX pagination to scroll a table with more then 10.000 row and I’m trying to use the following library: http://www.codexworld.com/ajax-pagination-in-codeigniter-framework/#comment-11900
    To draw the table I thought to load the view without a template, so, following your instruction in the section above rendering the table with:
    $this->render(‘admin/registrations/table_registrations_view’,NULL);
    But I got no data in page 🙁
    Any hint?

  6. I got error “Call to undefined method Welcome::render() ” on controllers/Welcome.php.

    But it works if I change from:
    class Welcome extends CI_Controller {
    to:
    class Welcome extends MY_Controller {

    PS: Thank you for your great tutorials. After I read your suggest, I started from lesson 1 🙂

  7. Hi! I have been reading your tutorials, they are very well explained. Thanks for sharing your knowledge. Greetings from Ecuador!

  8. Hi,

    Loving the tutorials, I have implemented this template system on a few projects of mine now but was just wondering if there was a way of passing data from the controller to the view whilst still using render()?

    I have tried previously and am sure it might be me missing something but any help you have to offer on the matter would be greatly appreciated! 🙂

    Thanks,

    1. What do you mean? You can pass data from controller to the view by using $this->data[‘variable’] = ‘whaetever’;

      1. Thanks for your reply,

        When I have been using $this->load->view(‘view_path’, $data); and then having variables such as $data[‘stuff’] = “stuff”; it works fine but as soon as I try to access those variables using render instead of view it throws errors saying the variables do not exist. I am also making sure that they are arrays to pass. Am I missing something?

        Thanks. 🙂

        1. Well… If you want to use the render() method, you must define the variables as $this->data (and not $data), because $this->data is actually a property defined and used in MY_Controller, and not merely a variable of your controllers.

          1. Ahhhhh, Thanks so much, I knew it was something simple I was missing but just couldn’t see what and now I look back into my controller I can see previous times I have done it correctly with $this->data instead. *slaps hands on head*

            Thank you so much!

  9. Hi Avenir,

    I have learned many things about codeigniter on your blog following these tutorials and i want to thank you.I also see that you ran out of ideas for new tutorials as you stated.Well perhaps you could expand your authentication system series with “Logging user out on browser close”.I use this config and have no clue on how to do that :
    $config[‘sess_driver’] = ‘database’;
    $config[‘sess_cookie_name’] = ‘ci_session’;
    $config[‘sess_expiration’] = 7200;
    $config[‘sess_save_path’] = ‘ci_sessions’;
    $config[‘sess_match_ip’] = FALSE;
    $config[‘sess_time_to_update’] = 300;
    $config[‘sess_regenerate_destroy’] = FALSE;

    1. As the configuration file says…
      | ‘sess_expiration’
      |
      | The number of SECONDS you want the session to last.
      | Setting to 0 (zero) means expire when the browser is closed.

      1. Strange but that didn’t work for me yesterday before i posted a question here.Then i went on googling about it and found people saying something that ‘sess_expiration’ set to 0 creates a cookie that lasts 2 years instead of doing what is supposed to do.I didn’t check if the cookie was set in my browser and now i am more confused on what happened over night 🙂 .However, everything works well now.Thank you for reply and i hope you get new ideas soon.This blog is awesome

  10. Following along your tutorial, when you get to templates, you go in separate directions

    “Step 12 – Creating and using page templates in CodeIgniter”
    http://avenir.ro/codeigniter-tutorials/creating-using-page-templates-codeigniter/

    “Fat-Free Framework – 8. Using the templating engine of the framework”
    http://avenir.ro/fat-free-framework-tutorials/fat-free-framework-8-using-templating-engine-framework/

    Which is it?

    “Step 12” would seem to be in flow of numbered steps in your tutorial, but the page you also link to is much more recent. Recommendations for the confused?

    1. Hello… I don’t know how you got from the CodeIgniter tutorial to the Fat Free Framework tutorial, which are two different series.

  11. Heloo, can any one help me pliz, am trying to use code igniter but the menu on the home page has failed to change and some items can not be hidden no more. Thax for your support and attention.

  12. why load another view in master_view.php than like codeifniter page:
    $this->load->view(‘header’);
    $this->load->view(‘menu’);
    $this->load->view(‘content’, $data);
    $this->load->view(‘footer’);
    ?

  13. Hello Future,

    I’ll come back to the discussion with Lewis.

    If we have ‘classically’ as written in the ci_user_guide:

    if ( ! $this->upload->do_upload(‘userfile’))
    {
    $error = array(‘error’ => $this->upload->display_errors());

    $this->load->view(‘upload_form’, $error);
    }

    What happens to the code using the render function?

    if ( ! $this->upload->do_upload(‘userfile’))
    {
    $this->data[‘error ‘]= array(‘error’ => $this->upload->display_errors());

    $this->render(‘upload_form’, $this->data[‘error ‘]);
    }

    ???

    I block the top for a moment … Can you help me?

Leave a Reply

Your email address will not be published. Required fields are marked *

No spam? * Time limit is exhausted. Please reload CAPTCHA.