Integrating Yii with Wordpress

Well I finally had some time and tinkered a bit with the notion of integrating wordpress and Yii. Now for me I wanted to use Yii as a framework to develop wordpress plugins. Using some tips from imasia Article I was able to do a simple integration of yii as a wordpress plugin. The integration was very basic and i just used yii with its default installation site. I don;t know how it will really react with CRUD application as yet but it was fairly easy to integrate after reading the article...

So here is what I did...

  1. first intall yii into the plugins directory
  2. in the config file I did this
<?php

// uncomment the following to define a path alias
//Yii::setPathOfAlias('wp-includes', ABSPATH . 'wp-includes');

// This is the main Web application configuration. Any writable
// CWebApplication properties can be configured here.
$plugins = parse_url(WP_PLUGIN_URL);
return array(
        'basePath'=>dirname(__FILE__) . DIRECTORY_SEPARATOR.'..',
        //'baseUrl'=> WP_PLUGIN_URL,
        'name'=>'My Web Application',
        //'aliases'=>array(
         //  'wp-plugins'=> ABSPATH . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins',
   // ),
        // preloading 'log' component
        'preload'=>array('log'),

        // autoloading model and component classes
        'import'=>array(
                'application.models.*',
                'application.components.*',
                //'wordpress.*',
        ),
        'defaultController'=>'site', 
        'modules'=>array(
                // uncomment the following to enable the Gii tool
                /*
                'gii'=>array(
                        'class'=>'system.gii.GiiModule',
                        'password'=>'Enter Your Password Here',
                ),
                */
        ),

        // application components
        'components'=>array(
                'user'=>array(
                        // enable cookie-based authentication
                        'allowAutoLogin'=>true,
                ),
                'request'=>array(
                        //'class'=>'WPHttpRequest',
                        'baseUrl'=> WP_PLUGIN_URL . '/yiiplugin',
                        'scriptUrl'=>  $plugins['path']  . '/yiiplugin/yii.php',
                ),
                // uncomment the following to enable URLs in path-format
                'assetManager'=>array(
                'basePath'=>dirname(__FILE__) . DIRECTORY_SEPARATOR.'..\..\assets',
                        'baseUrl'=>$plugins['path'] . '/yiiplugins/assets',
                        ),
                'urlManager'=>array(
                        //'urlFormat'=>'path',
                        'routeVar'=>'page',
                        
                        /*'rules'=>array(
                                '<controller:\w+>/<id:\d+>'=>'<controller>/view',
                                '<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
                                '<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
                        ),*/
                ),
                /*
                'db'=>array(
                        'connectionString' => 'sqlite:'.dirname(__FILE__).'/../data/testdrive.db',
                ),*/
                // uncomment the following to use a MySQL database
                /*
                'db'=>array(
                        'connectionString' => 'mysql:host=localhost;dbname=testdrive',
                        'emulatePrepare' => true,
                        'username' => 'root',
                        'password' => '',
                        'charset' => 'utf8',
                ),
                */
                'errorHandler'=>array(
                        // use 'site/error' action to display errors
            'errorAction'=>'site/error',
        ),
                'log'=>array(
                        'class'=>'CLogRouter',
                        'routes'=>array(
                                array(
                                        'class'=>'CFileLogRoute',
                                        'levels'=>'error, warning',
                                ),
                                // uncomment the following to show log messages on web pages
                                /*
                                array(
                                        'class'=>'CWebLogRoute',
                                ),
                                */
                        ),
                ),
        ),

        // application-level parameters that can be accessed
        // using Yii::app()->params['paramName']
        'params'=>array(
                // this is used in contact page
                'adminEmail'=>'webmaster@example.com',
        ),
);

It was tricky at first...I had to make sure the "baseUrl" and path related variables were correct (using relative in instances really help) and I had to change the route variable name... wordpress in admin starts off like wp-admin/admin.php?page=site/contact Yii is more /index.php?r=site/contact. I thought changing the path format would have helped but didn't...no need to anyway. setting the aliases and stuff is not necessary either ( i need to take it out so as to not misguide anyone)

  1. with the index.php file I did the following
<?php
/**
 * @package Yii Test Plugin
 */
/*
Plugin Name: Yii Test Plugin
*/
// change the following paths if necessary

function yiiapp_init(){
        global $yii_app;
        
        
        $config = dirname(__FILE__).'/protected/config/main.php';
        $yii_app = Yii::createWebApplication($config);  
        //$yii_app = Yii::createApplication('SiteController',$config);
        //Yii::setApplication($yii_app);
        
}

function yiiapp_admin_actions()
{
        global  $yii_app;
        add_menu_page("Yii", "Home", 1, 'site/', array(&$yii_app,"run"));
        add_submenu_page('site/', 'Yii', 'About', 1, 'site/page/view/about', array(&$yii_app,"run"));
        add_submenu_page('site/', 'Yii', 'Contact', 1, 'site/contact', array(&$yii_app,"run"));
        //add_submenu_page(basename(__FILE__), "Yii", "Contact", 3, __FILE__, array(&$yii_app,"run"));
        
}

global $yii_app;
$yii = dirname(__FILE__).'/../../../../yii/framework/yii.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',6);
require_once($yii);

if ( !defined( 'WP_AUTOLOAD_CLASSES' ) ) {
    define(
        'WP_AUTOLOAD_CLASSES',
        function_exists( 'spl_autoload_register' )
    );
}

if ( WP_AUTOLOAD_CLASSES ) {

        function wp_autoload( $class, $path = null ) {
                $classes = array('SimplePie' => ABSPATH . 'wp-includes/class-simplepie.php', 'WP_User_Search' => ABSPATH . 'wp-admin/includes/user.php');

                // Being called by PHP's autoloader
                if ( is_null( $path ) ) {
                        
                        if ( isset( $classes[$class] ) && !class_exists($class,false)) {
                                include_once( $classes[$class] );
                        } else {
                           

                        }
                        return;
                }

                // Being called by us
                // $classes[$class] = $path;
                // spl_autoload_unregister( 'wp_autoload' );
        }

    // Register it
   spl_autoload_register( 'wp_autoload' );
} else {
        function wp_autoload( $class, $path ) {
                require_once( $path );
        }
}

class YiiAutoLoad extends YiiBase {
        
         public static function autoload($className)
         {
                if(!class_exists($className,false))
                        parent::autoload($className);
         }
}

Yii::registerAutoloader(wp_autoload);

add_action('admin_init', 'yiiapp_init');
add_action('admin_menu', 'yiiapp_admin_actions');
//add_action('');
spl_autoload_unregister(array('YiiBase', 'autoload'));
spl_autoload_register(array('YiiAutoLoad','autoload'));

The above is code to generate initialize yii as a plugin and add the respective wordpress admin menus. The really obscure thing here is that yii's autoload was enabling even WP external classes. WP doesn't really have classes and the file names do not follow the same scheme. I had a simplepie on a wordpress 3.1. Yii kept trying to autoload it so you have to make your own custom autoload for WP and Yii to cater for wordpress classes and check for class_exists() in Yii. This would vary based on wp plugins and the use of OOP. Then use Yii registerAutoloader to load the custom autloaded when needed.

Adding menus that lead to yii urls paths was tricky also... but thanks to routeVar the patterns would be the same. use WP action functions to run instances of Yii and let yii sort out the url paths. didn't have to "rewrite" any htaccess and any url manager rules.

  1. I had to create a yii.php which contains the "original" markup code for yii applications
<?php
/**
 * @package Yii Test Plugin
 */
/*
Plugin Name: Yii Test Plugin
*/
// change the following paths if necessary
$yii=dirname(__FILE__).'/../../../../yii/framework/yii.php';
$config=dirname(__FILE__).'/protected/config/main.php';

// remove the following line when in production mode
defined('YII_DEBUG') or define('YII_DEBUG',true);

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

This was used for the "ccaptcha" feature on the contact page. and is the "scriptUrl" for the request component in the config

The only thing left to do is edit the layout files or create your own theme for the "content" area i.e no header html tags as wordpress would be responsible for this.

Example 1

Example 2

Example 3