This post has been up for a while and I think it’s time to make this note. The comments of this post have taken on a life of their own in terms of information. This means that the comments are just as, or nearly more important than the post itself. Please, read through the comments before giving anything a try or commenting yourself.
Thank you.
Recently I’ve been trying to solve a problem that I’m sure has encountered before: how to combine two rather large PHP applications running and based on different frameworks. These applications being WordPress and CodeIgniter. Before any comments, suggestions, or questions arise about why anyone would want to do this in the first place, don’t bother. This isn’t a post answering the why, it is solely about answering the how.
The first thing to tackle is the question of which framework to use as the master. In other words, which framework should load the other within itself. Most people might think CodeIgniter, because it is a basic framework used to create any web application, and it should certainly be ok to load WordPress. This is all true, but I do not want to lose WordPress’ core functionality, that being what is called “The Query”. When you bootstrap WordPress into another framework, you are losing all of the automation it does when parsing a request into the “The Query”. Nobody should want that, so lets look at another option, bootstrapping CodeIgniter into WordPress. This is the route I chose to take which allows for the least amount of code, the most automation from both platforms, and still uses CodeIgniter in such way that my blog specific views can be integrated with the code I have already written for the rest of my site.
Now where to start in WordPress? The answer is in one of two places, either a WordPress plugin or theme. If you know WordPress inside and out, then you may skip most of this, and go your own way. I chose the theme route because I can be assured that all plugins have been loaded, and the WordPress core is primed and ready. Within WordPress templates load after all the core actions and before any output is returned to the browser. What we should be going for is the most minimalist theme we can, which still requires three files:
- style.css
- functions.php
- index.php
All need to be located within our WordPress theme’s directory located somewhere like this…
/blog/wp-content/themes/codeigniter-bootstrap-theme
I will not review the style.css file here. There are plenty of tutorials about how to create a WordPress theme. Here is a quick summary: provide the required info necessary for a WordPress theme wthin this file’s comment header.
I will review the next item listed, the functions.php file. It is very important because it is the only part of any WordPress theme that is loaded around the same time a plugin, essentially making themes a type of plugin themselves. Within this file we must put in the following code to start the process of bootstrapping CodeIgniter:
<?php // This file is required to define a WordPress theme, Don't do anything in here you don't have to function codeigniter_bootstrap() { require_once( 'index.php' ); } // Add the action before any templates load, but after all other WordPress system actions run add_action( 'template_redirect', 'codeigniter_bootstrap' ); ?>
The outcome of that code is a global WordPress template redirect to the index.php file within our theme, for all WordPress requests. This is necessary for three reasons:
- We want CodeIgniter to handle all views, not WordPress
- WordPress themes require at least one template by the name of index.php (contrary to popular belief)
- CodeIgniter MUST be bootstrapped from within a script file, NOT from a function
Once that code is in place, and we have an empty index.php file within our theme, we should activate our theme now. You should see a blank page for every request to your WordPress client-side view, and your WordPress admin should still remain perfectly functional.
Next, the contents of the index.php file:
<?php // This file is required to define a WordPress theme, DON'T DO ANYTHING IN HERE!!!! $_GET['/blog/'] = null; end($_GET); require_once( dirname( ABSPATH ) . '/index.php' ); ?>
This may look weird to most developers, but let me explain. CodeIgniter by default requires a webserver override, or in most cases an apache .htaccess file to redirect all requests to the CodeIgniter bootstrap. This bootstrap then parses the requested URI by any means available to the server’s version of PHP. When using something like an .htaccess file, like the one provided by CodeIgniter’s user guide you will notice the line:
RewriteRule ^(.*)$ index.php?/$1 [L]
This basically takes the string following your rewrite base and appends it to the URI’s search parameters. This means that for an example request URI of …
http://mydomain.com/rewritebase/controller/action/
This actually appears to CodeIgniter as…
http://mydomain.com/rewritebase/index.php?/controller/action/
How CodeIgniter actually grabs this data is very simple. First it checks for any entries within the $_GET
super global. If found, it grabs the first entry using the PHP array iterator function of key($GET)
. This returns the key of the current iteration within the array, which is what CodeIgniter assumes is exactly what it needs to parse.
That all being said, I hope these lines make more sense to you:
$_GET['/blog/'] = null; end($_GET);
I am entering a manual entry into the super global with $_GET['/blog/']
, which is the actual part of the URI I want CodeIgniter to parse into the respective controller and action. The next line of end($_GET)
, ensures that CodeIgniter will retrieve the correct key using the key()
function.
All of these lines of course are subject to change within your own environment, but the next one especially:
require_once( dirname( ABSPATH ) . '/index.php' );
At this point I am loading the CodeIgniter bootstrap manually. It happens to be within my document root, which is one directory above my WordPress installation. This is why I know I can rely on the call of dirname( ABSPATH )
, but this may change depending on your own setup. Just be sure that the file you are looking for is the CodeIgniter bootstrap. You shouldn’t need anything else.
With all of the previous setup in place, there are a couple more things to do within WordPress to make things work smoothly. These include WordPress’ usage of permalinks. If you wish to use custom permalinks, be sure to set these up within the WordPress admin, as well as putting another .htaccess file within the root of the WordPress installation. If you wish to use the default setting for WordPress permalinks (just query strings), you need to enable query strings within your CodeIgniter config.
Now you should see a default CodeIgniter 404 page when viewing any WordPress response. If you do, you know the bootstrap is working correctly, if you do not, go back over the steps to see if you missed something.
The error page is most likely the result of calling a controller that doesn’t exist within your CodeIgniter application. For my example, I forced CodeIgniter to load “/blog/”, therefore I need a controller by the name of “blog”. My default controller for CodeIgniter is set to “home” in my config, this may also be different for your setup, but for this one I needed to define a controller here, /system/application/controllers/blog/home.php
. Of course along with the class, you need your standard index()
method for the default controller action. I like using the subdirectory route for this controller particularly because WordPress can get massive pretty fast, better safe than messy. Then I setup a corresponding view here /system/application/views/blog/home.php
.
Now you may notice that everything seems to be working except for one thing, all of your WordPress views point to one view, and you have lost that bit of automation that WordPress does for you. Don’t panic yet, we just have to pull a little WordPress logic into our controller. This logic is within the WordPress file of wp-includes/template-loader.php
. If you have never seen or looked at this file, you may be surprised. All of that beautiful automation is just one big if
conditional statement, yuck! Well… whether or not it is pretty, it does its job, and we want to do the same from within CodeIgniter. So what I am showing you here, is my interpretation of the logic from within that file, translated within the index()
method of my blog controller:
function index() { $this->load->view('common/header' ); // The following is similar to WordPress's template-loader.php - Use that as reference for this logic // Notice the mixture of WordPress API with the CodeIgniter API // Start template-loader if ( is_robots() ) { do_action('do_robots'); return; } else if ( is_feed() ) { do_feed(); return; } else if ( is_trackback() ) { include(ABSPATH . 'wp-trackback.php'); return; } else if ( is_404() ) { // show Code Igniter 404 show_404(); // OR load a view // $this->load->view('404' ); } else if ( is_search() ) { $this->load->view('blog/search' ); } else if ( is_tax() ) { $this->load->view('blog/taxonomy' ); } else if ( is_home() ) { $this->load->view('blog/index' ); } else if ( is_attachment() ) { remove_filter('the_content', 'prepend_attachment'); $this->load->view('blog/attachment' ); } else if ( is_single() ) { $this->load->view('blog/single' ); } else if ( is_page() ) { $this->load->view('blog/page' ); } else if ( is_category() ) { $this->load->view('blog/category' ); } else if ( is_tag() ) { $this->load->view('blog/tag' ); } else if ( is_author() ) { $this->load->view('blog/author' ); } else if ( is_date() ) { $this->load->view('blog/date' ); } else if ( is_archive() ) { $this->load->view('blog/archive' ); } else if ( is_comments_popup() ) { $this->load->view('blog/comments_popup' ); } else if ( is_paged() ) { $this->load->view('blog/paged' ); } else { $this->load->view('blog/index' ); } // End template-loader $this->load->view('common/footer' ); }
From the code above, you may have noticed the views look a lot like a normal WordPress theme. This is intentional so we may still feel comfortable in our habits while using both frameworks simultaneously. The difference is, now we are loading the views from a CodeIgniter controller, we have full control of the MVC pattern from within WordPress, we don’t have to rewrite any views for two frameworks, and we have access to the full API of each framework equally.
The end.
Leave a Reply