Integrating Wordpress and Yii: still another approach, using Yii as the router/controller

Overview

A lot of people have written posts on integrating Yii and WordPress. This article combines goncin's approach with an article I read about integrating Symfony and WordPress and applies it all to Yii and WordPress.

When you're finished following this article, you'll have a website that integrates WordPress and Yii routes in under one path. For example, you can setup /widgets and /customers to point to Yii controllers and /about-us, /contact-us, /blog/* and /faq pointing to WordPress pages.

What we're going to do is place Yii in front of WordPress to act as a router/controller. We'll then load WordPress up partially underneath the hood (enough that Yii can use headers, etc) but not hand off to WordPress unless Yii can't resolve the route. If Yii can't resolve the route, we'll have WordPress act as a custom error handler (for 404s only). Having wrapped Yii around WordPress allows us to use Yii objects / models / databases within WordPress plugins, functions and themes. It's pretty cool!

GitHub repository

The basic setup is available on Github: https://github.com/acorncom/yii-wordpress-integration

Note: there's a brief ReadMe on Github, but you may want to read on to understand what is going on :-)

WordPress setup

The easiest way to set things up is to have WordPress in a separate folder within your webroot folder, so that you don't have to worry about WordPress upgrades overwriting your files (and especially your entry script). Once WordPress is installed and setup to run smoothly out of /wordpress (path is easy to change), make sure the General Settings for WordPress are setup as follows:

Doing the above tells WordPress to set its links to all run through your Yii entry script but to set paths for images, stylesheets, js, etc. to your webroot/wordpress folder.

Yii entry script setup

Add the below code to your entry script somewhere before you create your web application:

define('WP_USE_THEMES', true);
$wp_did_header = true;
require_once('wordpress/wp-load.php');

require_once(dirname(__FILE__) . '/../protected/components/ExceptionHandler.php');
$router = new ExceptionHandler();

....

require_once($yii);
Yii::createWebApplication($config)->run();

.htaccess file

You'll also want to remove index.php from your path (if you haven't already). To do so, add a .htaccess file to your webroot folder with the following contents

RewriteEngine on

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# otherwise forward it to index.php
RewriteRule . index.php

and configure the showScriptName property of the urlManager component to be false.

There is more information on cleaning up your URLs in the guide, along with additional links.

Create our custom WordPress Exception handler

The following code handles 404 errors using WordPress instead of the Yii 404 page. If there is indeed a 404 (because WordPress can't handle it either), the 404 page will be shown in the 404 layout in WordPress.

<?php
class ExceptionHandler
{
	public function __construct()
	{
		define('YII_ENABLE_EXCEPTION_HANDLER',false);
		set_exception_handler(array($this,'handleException'));
	}

	public function handleException($exception)
	{
		// disable error capturing to avoid recursive errors
		restore_error_handler();
		restore_exception_handler();

		$event=new CExceptionEvent($this,$exception);
		if($exception instanceof CHttpException && $exception->statusCode == 404)
		{
			try
			{
				Yii::app()->runController("wp/index");
			}
			catch(Exception $e) {}
			// if we throw an exception in Wordpress on a 404, we can use
			// our main error handler to handle the error
		}

		if(!$event->handled)
		{
			Yii::app()->handleException($exception);
		}
	}
}
?>
Create a WordPress controller

Create a new controller to handle WordPress views and make sure to disable Yii layouts, as WordPress will handle its own layouts.

<?php

class WpController extends Controller
{
	public function actionIndex()
	{
		$this->layout = false; // note that we disable the layout
		try {
			$this->render('index');
			Yii::app()->end();
		}
		// if we threw an exception in a WordPress functions.php
		// when we find a 404 header, we could use our main Yii
		// error handler to handle the error, log as desired
		// and then throw the exception on up the chain and
		// let Yii handle things from here

		// without the above, WordPress becomes our 404 error
		// handler for the entire Yii app
		catch (Exception $e) {
			throw $e;
		}
	}
}

In addition, because we're using $this->render, Yii::app()->clientScript css/js files will be loaded into the WordPress header automatically after WordPress renders its content.

Create your controller view

Create a view/wp/index.php file for your WPController, which loads WordPress up all the way.

<?php
wp();
require_once( ABSPATH . WPINC . '/template-loader.php' );

At this point, going to your main URL should display the Wordpress home page and (assuming you have logging on) the Yii log info beneath. You now have access to Yii models, are able to do renderPartials, run DAO commands, etc inside of Wordpress functions, plugins, page templates, etc.

Add some comment lines to your config file
// Error handler
'errorHandler'=>array(
        // use 'site/error' action to display errors
        'errorAction'=>'site/error',
        // the above is unused for 404 errors, as those
        // are handled by Wordpress using our exception handler
),

Having WordPress handle 404 errors means you don't have to map every URL to WordPress (making adding new pages much easier for backend users). It also means we can prevent 404 headers from being sent by Yii (if you have WordPress handle errors as the errorHandler, things work properly, but a 404 header is sent for any WordPress page, which isn't ideal for SEO). NOTE: by having WordPress handle all errors, you don't ever see a 404 page inside of your Yii layout.

Setting up Yii views to be rendered in your Wordpress theme:

Finally, adjust your main layout to spit out your Wordpress header/footer around your Yii content:

<?php
get_header(); ?>

        <?php
             // echos Yii content
             echo $content;
        ?>

<?php get_footer(); ?>
Resources

Questions / thoughts / feedback / suggestions? Please post to the forum topic linked above so it's easier for other people to find. Find some bugs / snags in the article? Comments below are gladly welcomed.

19 0
24 followers
Viewed: 86 331 times
Version: 1.1
Category: How-tos
Written by: acorncom
Last updated by: acorncom
Created on: Apr 13, 2012
Last updated: 11 years ago
Update Article

Revisions

View all history

Related Articles