Integrating Wordpress and Yii: yet another approach

  1. On Wordpress
  2. On Yii

It seems many people is trying to make Wordpress and Yii work together. I got stuck with the same problem, but now I think I have achieved doing it, after a lot of hard thinking and many work hours spent.

My starting point was reading imasia's and isekream's articles. The principle of both researches is calling the Yii application from inside Wordpress. The solution I propose goes on the opposite way: use Wordpress as page template for the Yii application, so the end-user won't even realize he left the former and entered the latter.

Let's proceed.

On Wordpress

My Wordpress installation is themed with a child theme of Twentyten (Wordpress 3.x default). For the purpose of this tutorial, let's assume that our WP installation is on http://yourserver.com/wp. When applying it, change the path accordingly.

First step is creating a file under your WP theme folder, and name it yii-template.php.

File: [wp-root]/wp-content/themes/[yourtheme]/yii-template.php

<?php
/**
 * Template Name: Yii Template
 *
 * Template for Yii-powered pages
 *
 * The "Template Name:" bit above allows this to be selectable
 * from a dropdown menu on the edit page screen.
 *
 * @package WordPress
 * @subpackage Twenty_Ten
 * @since Twenty Ten 1.0
 */
get_header();
?>

<div id="container">
  <div id="content" role="main">

    <?php
    /*
     * The placeholder below will be replaced by Yii-generated content later.
     */
    ?>
    <!-- ###yii-content-placeholder### -->

  </div><!-- #content -->
</div><!-- #container -->

<?php get_sidebar(); ?>
<?php get_footer(); ?>

We have just created a new template for Wordpress pages.

Second step is creating a Wordpress page that will use the brand-new template. Access your WP admin panel, create a page and choose "Yii Template" (should be listed) as the page template. Title it yiipage, and leave the page content empty. After saving, you should be able to see the page using the uri http://yourserver.com/wp/yiipage (assuming your permalinks are in path mode).

That's all for Wordpress.

On Yii

Create a Yii application (using yiic) under WP root, on a folder named yii. You should see the familiar Yii application frontpage by accessing http://yourserver.com/wp/yii.

We'll need a custom ClientScript class. Let's create it under [yii-root]/protected/components.

File: [yii-root]/protected/components/ClientScript.php

<?php

class ClientScript extends CClientScript {

  public function renderHead(&$output) {
    $html = '';
    foreach ($this->metaTags as $meta) $html.=CHtml::metaTag($meta['content'], null, null, $meta) . "\n";
    foreach ($this->linkTags as $link) $html.=CHtml::linkTag(null, null, null, null, $link) . "\n";
    foreach ($this->cssFiles as $url => $media) $html.=CHtml::cssFile($url, $media) . "\n";
    foreach ($this->css as $css) $html.=CHtml::css($css[0], $css[1]) . "\n";
    if ($this->enableJavaScript) {
      if (isset($this->scriptFiles[self::POS_HEAD])) {
        foreach ($this->scriptFiles[self::POS_HEAD] as $scriptFile) $html.=CHtml::scriptFile($scriptFile) . "\n";
      }

      if (isset($this->scripts[self::POS_HEAD])) $html.=CHtml::script(implode("\n", $this->scripts[self::POS_HEAD])) . "\n";
    }

    if ($html !== '') {
      $count = 0;
      /*
       * The line below ensures that everything registered by Yii at POS_HEAD goes just before
       * the head ending (</head>). This way, Yii styles and scripts will be rendered *BELOW* and
       * *AFTER* those of Wordpress.
       * 
       * The original line in parent reads:
       * $output = preg_replace('/(<title\b[^>]*>|<\\/head\s*>)/is', '<###head###>$1', $output, 1, $count);
       * 
       */
      $output = preg_replace('/(<\\/head\s*>)/is', '<###head###>$1', $output, 1, $count);
      if ($count) $output = str_replace('<###head###>', $html, $output);
      else $output=$html . $output;
    }
  }

}

We also need to override CController.beforeRender(). This can be done in the already existing file Controller.php, located under [yii-root]/protected/components.

File: [yii-root]/protected/components/Controller.php

<?php
/**
 * Controller is the customized base controller class.
 * All controller classes for this application should extend from this base class.
 */
class Controller extends CController
{
	/**
	 * @var string the default layout for the controller view. Defaults to '//layouts/column1',
	 * meaning using a single column layout. See 'protected/views/layouts/column1.php'.
	 */
	public $layout='//layouts/column1';
	/**
	 * @var array context menu items. This property will be assigned to {@link CMenu::items}.
	 */
	public $menu=array();
	/**
	 * @var array the breadcrumbs of the current page. The value of this property will
	 * be assigned to {@link CBreadcrumbs::links}. Please refer to {@link CBreadcrumbs::links}
	 * for more details on how to specify this property.
	 */
	public $breadcrumbs=array();
  
  protected function beforeRender($view) {

    /* 
     * Let's prevent Yii from registering jQuery library. We'll stick with
     * the jQuery registered by Wordpress.
    */
    Yii::app()->clientScript->scriptMap=array(
      'jquery.js'=>false,
      'jquery.min.js'=>false,
    );
    
    /*
     * Wordpress works with jQuery in no-conflict mode, i. e., it doesn't define the $ alias for
     * the jQuery object. Nevertheless, many Yii scripts and plugins assume $ to point to jQuery,
     * so let's do the assignment ourselves.
     */
    if(! Yii::app()->clientScript->isScriptRegistered('jquery-alias', CClientScript::POS_HEAD)) {
      Yii::app()->clientScript->registerScript('jquery-alias', 'var $ = jQuery', CClientScript::POS_HEAD);
    }

    /*
     * To keep the visual coherence between normal Wordpress pages and Yii-powered pages,
     * we should use the CSS provided by the Wordpress theme. However, Yii use some 
     * specific CSS for forms, so it's a good idea to register the file containing it.
     */
    Yii::app()->clientScript->registerCssFile(Yii::app()->request->baseUrl . '/css/form.css');
    
    return parent::beforeRender($view);
  }
	
}

Now, the whole idea keystone. Let's change Yii main layout file, in order to fetch the Wordpress page we have previously prepared, replacing the placeholder within it by the content generated by the framework.

File: [yii-root]/protected/views/layouts/main.php

<?php

  /*
   * Here lies the core of the magic. Instead of using the content of the main layout
   * file provided by Yii, we fetch the proper Wordpress page (as a string) and replace the
   * placeholder within it with the actual content.
   */

  echo str_replace('<!-- ###yii-content-placeholder### -->', $content, file_get_contents('http://yourserver.com/wp/yiipage'));

  /* DO NOT FORGET TO ERASE THE ORIGINAL FILE CONTENT ;) */
  
?>

Finally, let's tell Yii to use our custom ClientScript class.

File: [yii-root]/protected/config/main.php

<?php
  (...)
  'components'=>array(
      /*
     * Let's use our very own ClientScript (application.components.ClientScript).
     */
    'clientScript' => array(
      'class' => 'ClientScript'
    ),
  (...)

That's all. You should be able to see your Wordpress-themed Yii application by accessing http://yourserver.com/wp/yii, and even logging on it through http://yourserver.com/wp/yii/index.php?r=site/login. Further tweaks include adjusting your Yii configuration to use url paths and hide the script name (so your urls will look like http://yourserver.com/wp/yii/controller/action). And yes, AJAX works! __

Back onto Wordpress, the final task is creating menu items linking to Yii powered pages.

Hope this be as useful for you as it was for me. Cheers!

6 2
11 followers
Viewed: 36 035 times
Version: 1.1
Category: How-tos
Written by: goncin
Last updated by: goncin
Created on: Jul 1, 2011
Last updated: 12 years ago
Update Article

Revisions

View all history

Related Articles