Run an Yii Application inside an Wordpress page

  1. Prerequisite
  2. Yii preparation
  3. Rewrite URL
  4. Conclusion

Prerequisite

Install a Wordpress site (mine is in "http://localhost/test/wordpress")

Create a folder where to place an Yii app under wordpress folder (mine is "yii')

Create a new Yii app inside previous folder

Install an WP plugin for including an PHP script (I've used "Include It")

Create a new Wordpress page (mine is "yiitest")

Place inside that page the Yii main script ("[include file=yii\index.php]")

Customize permalinks in WP (mine is "/%post_id%")

Yii preparation

Change "index.php" to override Yii autoload. Kind of hardcoded thing, you have to verify the classes that gives warnings after every new installed plugin in the main page of WP. For a new installation the next code is enough:

<?php
// change the following paths if necessary
$yii=dirname(__FILE__).'/../../path//to/framework/YiiBase.php';
$config=dirname(__FILE__).'/protected/config/main.php';

// remove the following lines when in production mode
defined('YII_DEBUG') or define('YII_DEBUG',true);
// specify how many levels of call stack should be shown in each log message
defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3);

require_once($yii);

class Yii extends YiiBase
{
	public static function autoload($className)
	{
		$wp_classes = array(
			'Translation_Entry',
			'Translations', 
			'NOOP_Translations',
			'POMO_Reader',
			'POMO_FileReader',
			'POMO_StringReader',
			'POMO_CachedFileReader',
			'POMO_CachedIntFileReader',
			'MO',
			//'',
		);
		if(!in_array($className, $wp_classes))
			YiiBase::autoload($className);
	}
}
spl_autoload_unregister(array('YiiBase', 'autoload'));
spl_autoload_register(array('Yii','autoload'));
Yii::createWebApplication($config)->run();

Change the "main.php" config file inside "componets" key

'assetManager'=>array(
	'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..\..\assets',
	'baseUrl'=>'yii/assets',
),
'request'=>array(
	'class'=>'WPHttpRequest',
	'baseUrl'=>'/test/wordpress/yiitest',
	'scriptUrl'=>'yiitest',
),
'clientScript'=>array(
	'class'=>'WPClientScript',
),
'user'=>array(
	'allowAutoLogin'=>true,
),
'urlManager'=>array(
	'urlFormat'=>'path',
	'showScriptName'=>false,
),

The previously defined components are (credit goes to zaccaria): WPHttpRequest

class WPHttpRequest extends CHttpRequest
{
 
    public function getPathInfo()
    {
        return $_GET['yiiPath'];
    }
 
}

WPClientScript:

class WPClientScript extends CClientScript
{
   public function registerCssFile($url, $media='')
   {
	  wp_enqueue_style( 'stylesheet', $url, array(), '', $media );
   }
 
   public function registerScriptFile($url, $media='')
   {
	  wp_enqueue_script( 'script', $url );
   }
}

Rewrite URL

I'm using IIS7:

<rule name="captchaRequest" stopProcessing="true">
	<match url="yiitest/([A-z_0-9/]+)/captcha/refresh/1$" ignoreCase="true" negate="false" />
	<action type="Rewrite" url="yii/index.php?yiiPath={R:1}/captcha&amp;refresh=1" appendQueryString="false" />
</rule>
		
<rule name="captchaImage" stopProcessing="true">
	<match url="yiitest/([A-z_0-9/]+)/captcha/v/([a-z_0-9]+)$" ignoreCase="true" negate="false" />
	<action type="Rewrite" url="yii/index.php?yiiPath={R:1}/captcha&amp;v={R:2}" appendQueryString="false" />
</rule>
		
<rule name="assets" stopProcessing="true">
	<match url="yiitest([A-z_0-9/.]+)(css|assets)/([A-z_0-9/.]+)\.(css|js|gif|jpg|png)$" ignoreCase="true" negate="false" />
	<action type="Rewrite" url="yii/{R:2}/{R:3}.{R:4}" appendQueryString="false" />
</rule>
		
<rule name="wordpress" stopProcessing="true">
        <match url="yiitest" negate="true" />
        <conditions logicalGrouping="MatchAll">
              <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
              <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
        </conditions>
        <action type="Rewrite" url="index.php" />
</rule>
		
<rule name="home" stopProcessing="true">
	<match url="(yiitest$|yiitest/$)" ignoreCase="true" negate="false" />
	<action type="Rewrite" url="index.php?page_id=5" appendQueryString="false" />
</rule> 
		
<rule name="ajaxResponse" stopProcessing="true">
	<match url="yiitest/([A-z_0-9/]+)/ajaxYii/1$" ignoreCase="true" negate="false" />
	<action type="Rewrite" url="yii/index.php?yiiPath={R:1}" appendQueryString="false" />
</rule>
		
<rule name="navigation" stopProcessing="true">
	<match url="yiitest/([A-z_0-9/]+)$" ignoreCase="true" negate="false" />
	<action type="Rewrite" url="index.php?page_id=5&amp;yiiPath={R:1}" appendQueryString="false" />
</rule>

The order is important but not mandatory. If you don't want to use a certain feature you can identify it by it's name and remove it.

One of the things that you have to keep in mind is for AJAX calls. As an example, for Form AJAX validation I've modified the "action" property of the CActiveForm widget "'action'=>array('', 'ajaxYii'=>true),"

Conclusion

You can have a full Yii app inside a WP page and everything (widgets, AJAX, validation, etc) have to work as expected. The URLRewrite is the key. Check for autoloading issues and JS/CSS duplicates. The two column Yii layout makes some troubles, also you have to play with the layout file (I've removed some of the tags: doctype, html, head, meta, title, body)