Difference between #5 and #4 of Integrating Wordpress and Yii: yet another approach

unchanged
Title
Integrating Wordpress and Yii: yet another approach
unchanged
Category
How-tos
unchanged
Tags
wordpress, yii, integration
changed
Content
* Este artigo está disponível também [em português do
Brasil](http://goncin.wordpress.com/2011/07/01/integrando-wordpress-e-yii-framework-uma-nova-abordagem/
"").

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 had donehave
achieved doing it, after a lot of hard thinking and many work hours spent.

My starting point was reading
[imasia's](http://www.yiiframework.com/wiki/144/run-an-yii-application-inside-an-wordpress-page/
"imasia's article") and
[isekream's](http://www.yiiframework.com/wiki/202/integrating-yii-with-wordpress/
"isekream's article") 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]
<?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]
<?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]
<?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]
<?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]
<?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!