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

26 followers

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:

  • WordPress Address (URL): http://<domain info>/wordpress
  • Site Address (URL): http://<domain info>

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.

Total 20 comments

#16937 report it
acorncom at 2014/04/14 12:58pm
Re: entry script

@Bibi40k, let's move this discussion onto the forum. Once we've worked out the issues, we can update the wiki article if needed. Thanks.

#16907 report it
Bibi40k at 2014/04/12 01:07am
entry script

Thanks, it helped me understand which one is it and now more questions popped up :) Here on this page you don't mention anything about index.php located into data folder as in github although inside you put

require_once('wordpress/wp-load.php');
require_once(dirname(__FILE__) . '/../protected/components/ExceptionHandler.php');

So wordpress folder and index.php are in the same folder (folder data as on github) And you also said to set into WP config: WordPress Address (URL): http:///wordpress Site Address (URL): http:// So index.php and wordpress folder should be into root folder ...

I may be very tired and miss something... i'll check all the links inside scripts so they point proper path because in my case it still doesn't work.

#16906 report it
acorncom at 2014/04/11 03:42pm
Re: entry script

@Bibi40k, no, Yii entry script meaning the index.php file that gets run initially. That help?

#16904 report it
Bibi40k at 2014/04/11 05:56am
please help me understand :)

Hi, thanks for your work.

"Yii entry script" is yii/framework/yiic.php ?

#16775 report it
blupointmedia at 2014/03/26 08:44pm
RE: WP Title and Sidebars

@acorncom - Done. Thanks.

#16774 report it
acorncom at 2014/03/26 08:30pm
RE: WP Title and sidebars

@blupointmedia can you post on the forum post or a Github issue to discuss? Better to not use this page for troubleshooting issues. Thanks

#16773 report it
blupointmedia at 2014/03/26 06:46pm
WP Title and Sidebars

I went through and followed all your instructions. It doesn't appear that WP passes $post to yii so you can get the title, other page content as well as sidebars in the page. Any ideas on how to overcome this?

Thanks.

#16287 report it
bhawin at 2014/02/06 06:52am
problem with yii on adding wordpress

i have a problem in my event table, there is a description column in my event table the description has text hello "this" is my name after adding wordpress the description text comes like hello \"this" is my name

what can i do about it

#16161 report it
InLoveWithYii at 2014/01/23 07:05pm
wp-admin

wp-admin works but you cant build stuff in Yii in the backend with this solution as it redirects to the wordpress installation directly. I have not found a way around this yet.

#12879 report it
acorncom at 2013/04/17 11:54am
Re: So wp-admin login doesn't work with this solution?

@gvanto: yes, wp-admin logins work fine with this setup. Use /wordpress/wp-login.php If you have more problems, post over on the forum thread and we'll work it out there.

#12781 report it
gvanto at 2013/04/11 11:59pm
So wp-admin login doesn't work with this solution?

Does wp-admin work with this solution? I really really hope so :s

Any help much appreciated

#12780 report it
gvanto at 2013/04/11 11:58pm
So wp-admin login doesn't work with this solution?

Does wp-admin login work with this setup? I really need it to :s

#9699 report it
acorncom at 2012/09/04 06:36am
Re: autoload problem

@kiennguyen: regarding your CHtml problem, did you copy/paste in your code? Because you have it mis-capitalized (should be CHtml, not Chtml) in your example.

Haven't tried a Wordpress admin function yet myself, but I think that uses a whole different Wordpress entry script. So we may need to duplicate some of the WpController stuff to run it inside of our Yii controller system.

Do let me know if you get it working. Would love to update the instructions. :-)

#9698 report it
kiennguyen at 2012/09/04 06:22am
Autoload problem in wp-admin

This method does not apply to wp-admin. I tried to add to themes/twentyeleven/functions.php

if (is_admin()) {
    global $yii,$config;
    if (is_null($yii))
        $yii = ABSPATH . '../../yii/framework/yii.php';
 
 
    require_once($yii);
    Yii::createApplication('CController');
    Yii::app()->theme = null;
    $controller = new CController('site');
 
    echo CHtml::link("asdf");
 
  }

There's no way to create an Web Application here as autoload will always generates a fatal regarding YiiBase class (maybe because of wrong config), so I created a normal application with CController here instead. The CHtml class works here, but the controller cannot render any views/text/file because of getTheme() error:

Fatal error: Call to a member function getTheme() on a non-object in C:\wamp\www\yii\framework\web\CController.php on line 638

Autoload also gives warning on creating new post:

Warning: include(_WP_Editors.php) [function.include]: failed to open stream: No such file or directory
#8127 report it
rix.rix. at 2012/05/12 04:52am
Very cool

This is very cool - I was thinking about doing something very similar with Drupal but was worried about overhead. I've done a few searches and can't find anything on the subject - has anyone tried?

#8035 report it
acorncom at 2012/05/04 03:08pm
Article updated

@exien, thanks for the suggestions, those additions have been added in. I've also been doing some research on the problem @OceanWind had and believe I've got an optimization for that that I can post in a few weeks. I'll need to test it first. It's a bit complicated. :-/

#8019 report it
exien at 2012/05/04 12:20am
Excellent tutorial

This is the best way to integrate Yii and WordPress. But please make it clear that URLs for WordPress pages do not start with "/wordpress" like some of the other methods.

This method seamlessly integrates Yii pages and WordPress pages into the same path.

Note: To get path routes working (ie. without the index.php?r=), you need to add a .htaccess to the webroot. Yii doesn't automatically create one when you build a new app.

Thanks!

#7903 report it
acorncom at 2012/04/25 10:40am
Posting my response to the forum

@OceanWind: just started a new forum post to use as discussion of this article. I'll post my thoughts over there.

#7863 report it
Ocean Wind at 2012/04/23 09:29pm
Permalinks and stylesheets

So far, I really like this approach. I haven't seen a significant degradation of performance, and that makes me very happy (probably because Yii is so lean and mean).

What I have noticed is that the error logs are recording that my permalinks won't resolve, even though the pages ultimately display:

2012/04/24 01:23:31 [error] [exception.CHttpException.404] exception
'CHttpException' with message 'Unable to resolve the request
"sidebar-items/contact-sidebar".' in
/home/lfs12/yii_framework/web/CWebApplication.php:280
Stack trace:
#0 /home/lfs12/yii_framework/web/CWebApplication.php(135):
CWebApplication->runController('sidebar-items/c...')
#1 /home/lfs12/yii_framework/base/CApplication.php(162):
CWebApplication->processRequest()
#2 /home/lfs12/slowmoneycolorado.org/index.php(21):
CApplication->run()
#3 {main}
REQUEST_URI=/sidebar-items/contact-sidebar/
HTTP_REFERER=http://slowmoneycolorado.org/main-menu/blog/

Any idea what's up with that and how we could get it to not register errors (or go through the added effort of generating an error before displaying)?

I also noticed that it was looking for the Yii stylesheets, so I created aliases to them from the WP Theme folder.

#7816 report it
acorncom at 2012/04/19 07:25pm
Re: how caching is working

@OceanWind / Bill: I believe caching could / would be handled by WordPress in the standard WordPress way (but I haven't tested it). There might be ways to have Yii cache an entire WordPress page (I think this would only work if you had a Yii action per WordPress page you were interested in), but I can see running into snags with invalidating the cached WordPress page in Yii. If a user updated a page in WordPress, you'd need to figure out how to tell Yii to stop caching that page.

Probably far simpler to use WordPress cache plugins :-)

And to answer your question re: other collisions, no, I haven't run into any so far, but I haven't tested it heavily yet. Let me know if you run into anything.

Leave a comment

Please to leave your comment.

Write new article