(created: January 22, 2015; last update: October 01, 2015)
Now that we have an admin area, it would be nice to make it look good. So let’s first create a basic template and then inject the Bootstrap CSS in it.
As you’ve probably read in “Step 11 – Creating and using page templates in CodeIgniter”, it is quite easy to create a template.
So let’s apply that to our blog admin area:
First of all let’s see what we can change in MY_Controller class. The $data and the render() method will be universal throughout our blog, and if Admin_Controller class and Public_Controller class extend MY_Controller, why not define those in there?
<?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['page_title'] = 'CI App'; $this->data['before_head'] = ''; $this->data['before_body'] =''; } 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); } } } class Admin_Controller extends MY_Controller { function __construct() { parent::__construct(); } } class Public_Controller extends MY_Controller { function __construct() { parent::__construct(); } }
As you can see, we’ve added a default page title inside page_title key. Also, one might ask: What are those before_head and before_body? Often you find yourself that you need to insert something inside the html page either before closing the <head> tag or before closing the <body> tag (things like javascripts or css styles). This way we can fill these keys with html code as values, and will be inserted into the pages. Now, for our admin area we want to use a different template so we should overwrite the MY_Controller properties. So let’s change the MY_Controller.php to accomodate the changes needed for Admin_Controller:
<?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['page_title'] = 'CI App'; $this->data['before_head'] = ''; $this->data['before_body'] =''; } 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); } } } class Admin_Controller extends MY_Controller { function __construct() { parent::__construct(); $this->data['page_title'] = 'CI App - Dashboard'; } protected function render($the_view = NULL, $template = 'admin_master') { parent::render($the_view, $template); } } class Public_Controller extends MY_Controller { function __construct() { parent::__construct(); } }
In application/views/templates we will have to create an admin_master_view.php:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); $this->load->view('templates/_parts/admin_master_header_view'); ?> <div class="container"> <?php echo $the_view_content; ?> </div> <?php $this->load->view('templates/_parts/admin_master_footer_view');?>
And after that we will create the template parts, the admin_master_header_view.php, and the admin_master_footer_view.php inside application/views/templates/_parts directory:
<?php defined('BASEPATH') OR exit('No direct script access allowed');?> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title><?php echo $page_title;?></title> </head> <body> <nav>My menu item</nav>
<footer> <p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds. <?php echo (ENVIRONMENT === 'development') ? 'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : '' ?></p> </footer> </body> </html>
Now, returning to our dashboard_view.php, we should remove the header and footer part and leave those to the master template. So the new dashboard_view.php will look like this now:
<div class="container"> <h1>Welcome to the Dashboard!</h1> </div>
But what if for some pages we would have to put some html code just before the </head> or </body> tags? For this we will create two more $data elements inside the MY_Controller class, and pass them to the master template:
Now, going to the admin_master_header_view.php, we echo the $data[‘before_head’]:
<?php defined('BASEPATH') OR exit('No direct script access allowed');?> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title><?php echo $page_title;?></title> <?php echo $before_head;?> </head> <body> <nav>My menu item</nav>
And, going to admin_master_footer_view.php, we echo the $data[‘before_footer’]:
<footer> <p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds. <?php echo (ENVIRONMENT === 'development') ? 'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : '' ?></p> </footer> <?php echo $before_body;?> </body> </html>
Now go to the Dashboard controller, in application/controllers/admin directory, and instead of calling $this->load->view(‘admin/dashboard_view’); we call the method we defined in MY_Controller and extended in Admin Controller: $this->render(‘admin/dashboard_view’).
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Dashboard extends Admin_Controller { function __construct() { parent::__construct(); } public function index() { $this->render('admin/dashboard_view'); } }
Perfect! It’s time for…
Inserting the the Bootstrap CSS into our template
First of all we should create an assets directory in which we will keep our css, javascript and site’s specific images (like logo and so on). Inside it we will also create an admin directory so that we will know that in there we can find all our admin specific assets:
-application/ -system/ -assets/ - -admin/
After we’ve downloaded Bootstrap CSS, we extract the archive inside the assets/admin directory:
-application/ -system/ -assets/ - -admin/ - - -css/ - - -fonts/ - - -js/
Let’s make sure that no one else will look at our admin assets by creating an empty index.html inside the assets/admin directory. You can also create a .htaccess file inside the assets directory (http://www.thesitewizard.com/apache/prevent-directory-listing-htaccess.shtml)
Options -Indexes
After this we should go to our admin_master_header_view.php and load the Bootstrap’s assets:
<?php defined('BASEPATH') OR exit('No direct script access allowed');?> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title><?php echo $page_title;?></title> <link href="assets/admin/css/bootstrap.min.css" rel="stylesheet"> <?php echo $before_head;?> </head> <body> <nav>My menu</nav>
Now, in admin_master_footer_view.php we load the javascripts needed for Bootstrap:
<?php defined('BASEPATH') OR exit('No direct script access allowed');?> <footer> <p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds. <?php echo (ENVIRONMENT === 'development') ? 'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : '' ?></p> </footer> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script> <script src="js/bootstrap.min.js"></script> <?php echo $before_body;?> </body> </html>
Now let’s return to our admin_master_header_view.php and create our horizontal menu:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title><?php echo $page_title;?></title> <link href="<?php echo site_url('assets/admin/css/bootstrap.min.css');?>" rel="stylesheet"> <?php echo $before_head;?> </head> <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="<?php echo site_url('admin');?>">Project name</a> </div> <div id="navbar" class="collapse navbar-collapse"> <ul class="nav navbar-nav"> <li><a href="#">A link</a></li> <li><a href="#">Another link</a></li> </ul> </div><!--/.nav-collapse --> </div> </nav>
Now, what about the “Project name”. Why not use our configuration file that we’ve made in a previous tutorial so that it will use the “cms_title” to replace the hard-coded title? So, let’s change Project title into <?php echo $this->config->item(‘cms_title’);?>.
Also, as you can see, inside the menu we’ve used site_url(). We will use a lot of URL helper functions, so let’s just add this to our autoload.php:
... $autoload['helper'] = array('url'); ...
Also, some changes inside the admin_master_view.php are necessary:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); $this->load->view('templates/_parts/admin_master_header_view'); ?> <div class="container"> <div class="main-content" style="padding-top:40px;"> <?php echo $the_view_content; ?> </div> </div> <?php $this->load->view('templates/_parts/admin_master_footer_view');?>
…and some in admin_master_footer_view…
<?php defined('BASEPATH') OR exit('No direct script access allowed');?> <footer> <div class="container"> <p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds. <?php echo (ENVIRONMENT === 'development') ? 'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : '' ?></p> </div> </footer> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script> <script src="<?php echo site_url('assets/admin/js/bootstrap.min.js');?>"></script> <?php echo $before_body;?> </body> </html>
Cool! Next we will secure our admin area.
Here is our application if you’ve followed all the previous steps and this one.
I tried this example. but unable to redirect to admin.
URL: http://localhost:81/rtpcms/admin
Error: Not Found
The requested URL /rtpcms/admin was not found on this server.
Apache/2.4.9 (Win64) PHP/5.5.12 Server at localhost Port 81
If you need source code to check I can send you.
Did you follow the previous steps? Especially this one: http://avenir.ro/codeigniter-tutorials/removing-the-index-php-from-the-url-and-allow-the-use-of-search-engine-friendly-urls/
But I got a problem
Fatal error: Class ‘Admin_Controller’ not found in /home/gyuksd/public_html/application_test/controllers/admin/Dashboard.php on line 4
A PHP Error was encountered
Severity: Warning
Message: Cannot modify header information – headers already sent by (output started at /home/gyuksd/public_html/application_test/controllers/admin/Dashboard.php:4)
Filename: core/Common.php
Line Number: 564
Backtrace:
A PHP Error was encountered
Severity: Error
Message: Class ‘Admin_Controller’ not found
Filename: admin/Dashboard.php
Line Number: 4
Backtrace:
Well… did you follow all the tutorials that were before this one? I am also referring to the one where I’m talking about extending more then one Controller: http://avenir.ro/codeigniter-tutorials/no-more-my_controller-how-you-can-create-more-than-one-base-controller/
hi nice tutorial
unable to login with admin@admin.com password , i have put ci 3.0 system folder plz help me
Did you follow the previous tutorial? If you simply copy/pasted what I’ve written in the tutorials you can login by using “administrator” as username and “password” as password.
something missing in this tutorial (MY_Controller.php) :
$this->data[‘before_head’] = ”;
$this->data[‘before_body’] = ”;
but in your ciapp.zip it’s completed. thanks.
Well… In my defense, what you see here is just a tutorial, which means is only a proof of concept. If you really want to see the final product (or at least the last version I’ve come with), you can at any time go to my Github Repository (https://github.com/avenirer/CodeIgniter-multilanguage-site)
sir,
I need your help, i found a problem, i was trying to figure out why and i am pretty sure that i have done all your instruction. The error message is shown below:
A PHP Error was encountered
Severity: Error
Message: Call to undefined function site_url()
Filename: _parts/admin_master_header_view.php
Line Number: 8
Backtrace:
You didn’t load the url helper…
after i fill the helper with url,
$autoload[‘helper’] = array(‘url’);
the error continues
Severity: Notice
Message: Undefined variable: before_head
Filename: _parts/admin_master_header_view.php
Line Number: 9
Oh… sorry about that. I’ve changed the tutorial a bit now… You define them inside the MY_Controller’s constructor;
data[‘page_title’] = ‘CI App’;
$this->data[‘before_head’] = ”;
$this->data[‘before_body’] =”;
}
…
Thank you for reporting me this.
It perfectly works Sir,
Thanks a ton,
no! it is not a ton, a hundred million tons LOL
Thank you. Anytime you have a problem from my tutorials just tell me. I can tame them… 😉
Hi, you have a typo at the end of this page…
config->item(‘cms_title’);?>
Should be $this
Thank you.
Please send me your email
avenir.ro@gmail.com
It’s always really useful to read and read again such great tutorial.
Just a question about the following code:
if($template == ‘json’ || $this->input->is_ajax_request())
{
header(‘Content-Type: application/json’);
echo json_encode($this->data);
}
I don’t understand how to use it…even if, of course, I understand it’s AJAX related. Right now, for, AJAX code, I add a json_encode row in my controllers and some Javascript code in the view to get and parse the returned code. Didn’t use so far the code above but now I’m just asking if I could use it improving my scripts.
Thanks a lot for any feedback
I was assuming that sometimes you would have some methods that would return json data. So, instead of doing json_encode($array_of_data), you could store the data inside $this->data and then call the same $this->render(NULL,’json’);