Integrating Wordpress and Yii,Working Out The Details.

  1. Overview
  2. WordPress Setup
  3. Setting Up A Theme Template For Yii
  4. Define An Alias For WordPress Themes Folder
  5. Setting Up Yii Controllers
  6. Conclusion
  7. Resources

Overview

This article is based on fr0d0z's article Integrating Wordpress and Yii: still another approach, using Yii as the router/controller and provides more details on how to set up this integration.To be more specific,the idea is not to use any main.php layout in Yii's controllers.This gives the advantage that we do not need to modify any Yii code when we switch a theme in WordPress admin panel,provided we have done a very basic setup which I explain below.

WordPress Setup

First things first,follow the instructions in fr0d0z's article to set up WordPress.Regarding the WpController,I did not use an index view.So the code for WpController is

class WpController extends Controller
{
    public function init()
    {
	 // note that we disable the layout
        $this->layout = false;
        parent::init();
    }

    public function actionIndex()
    {   
        try {
            wp();
            require_once(ABSPATH . WPINC . '/template-loader.php');
            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;
        }
    }
}
?>

Setting Up A Theme Template For Yii

Next we do a very simple set up for the template Yii will use in Wordpress to wrap the controller views.This is replacing Yii's main.php layout.To do that,we locate a generic template in Wordpress theme's folder that includes the header and footer.Let's take for example the twentyeleven theme,the page.php template is simply

<?php
get_header(); ?>
   <div id="primary">
	<div id="content" role="main">
	    <?php while ( have_posts() ) : the_post(); ?>
		<?php get_template_part( 'content', 'page' ); ?>
		 <?php comments_template( '', true ); ?>
	     <?php endwhile; // end of the loop. ?>
	  </div><!-- #content -->
     </div><!-- #primary -->
<?php get_footer(); ?>

The loop ouputs the main content for Wordpress and it will be replaced by Yii's output. So make a copy of this page.php file,rename it as page-yii.php,and save it in the same folder as page.php,(theme's root). Then replace the loop with

<?php $this->renderPartial($view,($params)?$params:null); ?>

So page-yii.php looks like:

<?php
get_header(); ?>
    <div id="primary">
	<div id="content" role="main">	
             <?php   $this->renderPartial($view,($params)?$params:null);  ?>
	 </div><!-- #content -->
     </div><!-- #primary -->
<?php get_footer(); ?>

Define An Alias For WordPress Themes Folder

In config/main.php:

'aliases'=>array(
      ...
    'wp_themes'=>'webroot.wp.wp-content.themes',
      ...
    ),

Setting Up Yii Controllers

In SiteController disable the main layout in init().

public function init(){
       $this->layout=false;
       parent::init();
    }

In actionIndex replace

$this->render('index');

with

$this->render('wp_themes.'.get_template().'.page-yii',array('view'=>'index'));

get_template() is a Wordpress function.Surreal,we are inside a Yii controller,right?But Wordpress has already "started" since Yii's bootstrap script index.php ran,it just has not rendered a template,so it's possible to use this function.It simply returns the Wordpress activated theme folder name.In our case it's just "twentyeleven" string.So render function will find our page-yii.php template that we wrote earlier,and it will pass 'index' as value for the view parameter. Inside page-yii.php,we are still in SiteController's scope (surreal again!) so we can use $this->renderPartial to render the index view (passed as view parameter).

<?php  $this->renderPartial($view,($params)?$params:null); ?>

and so the content of site/index.php view file will be wrapped in WordPress layout.

In the same manner,in actionLogin():

$this->render('wp_themes.'.get_template().'.page-yii',array('view'=>'login','params'=>array('model'=>$model)));

and in actionContact():

$this->render('wp_themes.'.get_template().'.page-yii',array('view'=>'contact','params'=>array('model'=>$model)));

For the static views we need a new StaticViewAction that extends CViewAction and overrides only the run() function :

class StaticViewAction  extends CViewAction
{

    public function run()
    {
        $this->resolveView($this->getRequestedView());
        $controller=$this->getController();
        if($this->layout!==null)
        {
            $layout=$controller->layout;
            $controller->layout=$this->layout;
        }

        $this->onBeforeRender($event=new CEvent($this));
        if(!$event->handled)
        {
            if($this->renderAsText)
            {
                $text=file_get_contents($controller->getViewFile($this->view));
                $controller->renderText($text);
            }
            else
           //We only changed the following line
          $controller->render('wp_themes.'. get_template() .'.page-yii',array('view'=>$this->view));
          $this->onAfterRender(new CEvent($this));
        }

        if($this->layout!==null)
            $controller->layout=$layout;
    }
}

We have only replaced the render path from the parent class run() function. Save the above class as StaticViewAction.php in components folder. Next,make sure the action is declared in SiteController's actions() function.

public function actions()
	{
	  // page action renders "static" pages stored under 'protected/views/site/pages'
	  // They can be accessed via: index.php?r=site/page&view=FileName
	   'page'=>array(
	        //'class'=>'CViewAction',we replace this
                  'class'=>'StaticViewAction',
			),
		);
	} 

And this is enough to render in Wordpress all the static view files you place in views/site/pages,like about.php for example. Because of this setup,as we mentioned in the beginning,if we change theme in Wordpress admin panel,the Yii views will still be rendered without changing any Yii code,(of course we should have created a page-yii.php file in every theme we want to activate).Please note that when you change themes back and forth,certain configurations are lost like widgets in sidebars or the menu used-this is Wordpress related issue.In this case you just re-configure. Last,go to WordPress admin panel in Appearance > Menus and add the Yii actions as custom links,to make them appear in the menu.For the login action,you can use in page-yii.php the code that displays a Login or Logout link based on whether the user is logged in or not,(see demo).

Conclusion

It's great to be able to use Yii fused with WordPress for things like blogging and Media management.Sure you could code a CMS for blogging in Yii,but chances are you can't compete with thousands of manhours that developers have spent on WordPress over the years.So it's best to leave that for WordPress and use Yii for backend management of business related critical data,like products,personell etc. As a matter of fact,since it's possible to use Yii code inside Wordpress plugins it would be a good idea to code wordpress plugins that manage data handled by Yii,with an interface rendered inside the WordPress admin panel. In addition,a gazillion WordPress themes are available both free and commercial ready to dress up your Yii application.

Resources