Features

The following Yii components are pre-configured to work in your WordPress:

Screenshots

// TODO

Installation

Download the latest release or development version and uncompress the wp-content/plugins folder into your wordpress.

Requirements

The application has been tested with the following software versions, however should work with any minor revision change:

Installation

Browse to the plugin manager in the WordPress admin, then press Activate next to Yii Embed.

If Yii was not found you will be prompted to perform an Automatic Download or a Manual Download.

You can use an alternative path to Yii by browsing to the Yii Embed section under the WordPress admin Settings page.

Search Engine Friendly permalinks must be enabled, see this page for instructions.

Configuration

...

Usage

Creating a Plugin

In this example we will create a WordPress plugin called Foo. It will contain a controller called FooBarController with basic functionality.

Directory Structure

wp-content/plugins/foo/              -- folder containing your plugin
    foo.php                          -- the plugin loader
    includes/                        -- wordpress helper classes
        Foo.php                      -- main static helper class
        FooAdmin.php                 -- admin static helper class
        FooSettings.php              -- admin options page
    app/                             -- yii application
        assets/                      -- assets folder
            css/                     -- stylesheet files
                foo_admin.css        -- front end stylesheet
                foo_front.css        -- front end stylesheet
            img/                     -- image files
            js/                      -- javascript files
        components/                  -- application components (auto loaded)
            FooController.php        -- base controller
        controllers/                 -- controller classes
            FooBarController.php     -- example controller
        models/                      -- model classes
            FooBar.php               -- example model
        views/                       -- view files
            fooBar/                  -- view files for FooBarController
                _form.php            -- form partial
                _view.php            -- view partial
                admin.php            -- admin page
                create.php           -- create page
                index.php            -- front page
                update.php           -- update page
                view.php             -- view page

Database Schema

CREATE TABLE `wp_foo_bar` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `name` varchar(255) NOT NULL,
    `description` text NOT NULL,
    PRIMARY KEY (`id`)
);

wp-content/plugins/foo/foo.php

<?php
/**
 * Plugin Name: Foo
 */

// do not allow direct entry here
if (!function_exists('wp')) {
    echo 'cannot be called directly';
    exit;
}

// define constants
define('FOO_URL', plugin_dir_url(__FILE__));
define('FOO_PATH', __DIR__ . '/');

// load plugin
require_once(FOO_PATH . 'includes/Foo.php');
Foo::init();

wp-content/plugins/foo/includes/Foo.php

<?php
/**
 * Foo is the static helper class for Foo Plugin functionality.
 */
class Foo
{

    /**
     * Initialize Foo
     */
    public static function init()
    {
        // load language
        load_plugin_textdomain('foo', false, basename(FOO_PATH) . '/languages');
        // runs when plugin is activated
        register_activation_hook(FOO_PATH . 'foo.php', 'Foo::activation');
        // runs on plugin deactivation
        register_deactivation_hook(FOO_PATH . 'foo.php', 'Foo::deactivation');
        // setup admin pages
        if (is_admin()) {
            require_once(FOO_PATH . 'includes/FooAdmin.php');
            FooAdmin::init();
        }
        // init Yii
        add_action('init', 'Foo::yiiInit');
    }

    /**
     * Callback when the plugin is activated
     */
    public static function activation()
    {
        // add options
        delete_option('foo');
        add_option('foo', array(
            'dummy' => '',
        ));
    }

    /**
     * Callback when the plugin is deactivated
     */
    public static function deactivation()
    {
        // delete options
        delete_option('foo');
    }

    /**
     * Initialize Yii
     */
    public static function yiiInit()
    {
        // only run if Yii was found
        if (!defined('YII_EMBED_YII_VERSION') || !YII_EMBED_YII_VERSION)
            return;

        // setup aliases
        Yii::setPathOfAlias('foo', FOO_PATH . 'app');
        Yii::import('foo.components.*');
        Yii::import('foo.models.*');

        // setup controller map
        foreach (glob(Yii::getPathOfAlias('foo.controllers') . '/*') as $controller) {
            Yii::app()->controllerMap[lcfirst(str_replace('Controller.php', '', basename($controller)))] = strtr($controller, array(FOO_PATH . 'app' => 'foo', '.php' => '', '/' => '.', '\\' => '.'));
        }

        // setup custom routes
        Yii::app()->urlManager->rules['bar/<action:(\w+)>*'] = 'fooBar/<action>';
        Yii::app()->urlManager->rules['bar'] = 'fooBar/index';
        Yii::app()->urlManager->init();

        // register scripts
        self::registerScripts();
    }

    /**
     * Registers the css and js scripts
     * @return string
     */
    public static function registerScripts()
    {
        // only run if Yii was found
        if (!defined('YII_EMBED_YII_VERSION') || !YII_EMBED_YII_VERSION)
            return;
        // register css/js files
        if (is_admin()) {
            Yii::app()->clientScript->registerCssFile(self::assetsUrl() . '/css/foo_admin.css');
        }
        else {
            Yii::app()->clientScript->registerCssFile(self::assetsUrl() . '/css/foo_front.css');
        }
    }

    /**
     * Returns the assets url
     * @return string
     */
    public static function assetsUrl()
    {
        static $assetsUrl;
        if ($assetsUrl !== null)
            return $assetsUrl;

        // only run if Yii was found
        if (!defined('YII_EMBED_YII_VERSION') || !YII_EMBED_YII_VERSION)
            return $assetsUrl = false;

        // publish the assets
        return $assetsUrl = Yii::app()->assetManager->publish(Yii::getPathOfAlias('foo.assets'), true, -1, YII_DEBUG);
    }

}

wp-content/plugins/foo/includes/FooAdmin.php

<?php
/**
 * FooAdmin is the static helper class for Foo Plugin administration functionality.
 */
class FooAdmin
{

    /**
     * Initialize the Admin callbacks and messages.
     */
    public static function init()
    {
        // add action for notices
        add_action('foo_admin_notice', 'FooAdmin::notice', 10, 2);

        // check if yii-embed is installed
        add_action('init', 'FooAdmin::yiiEmbedCheck');

        // add admin menu pages
        add_action('admin_menu', 'FooAdmin::menu');

        // register settings page
        require_once(FOO_PATH . 'includes/FooSettings.php');
        new FooSettings();
    }

    /**
     * Callback to and menus and pages.
     * Admin page format is: yii_embed_[controller]_[action]
     */
    public static function menu()
    {
        // add page for FooBarController::actionAdmin()
        add_menu_page(__('Foo'), __('Foo'), 'administrator', 'yii_embed_fooBar_admin', 'YiiEmbedAdmin::page');
        if (isset($_GET['page']) && strpos($_GET['page'], 'yii_embed_fooBar_') === 0) {
            add_submenu_page('yii_embed_fooBar_admin', '', '', 'administrator', $_GET['page'], 'YiiEmbedAdmin::page');
        }
    }

    /**
     * Callback for foo_admin_notice.
     *
     * Example:
     * do_action('foo_admin_notice', __('<p>Hello world!</p>'));
     * do_action('foo_admin_notice', __('<p>An error occurred.</p>'), 'error');
     *
     * @param string $message HTML message to display on the admin page.
     * @param string $class CSS class to wrap the message in, either "updated" or "error".
     */
    public static function notice($message, $class = 'updated')
    {
        add_action('admin_notices', create_function('', 'echo \'<div class="' . addslashes($class) . '">' . str_replace("'", "\\'", $message) . '</div>\';'));
    }

    /**
     * Callback to see if yii-embed is installed.
     */
    public static function yiiEmbedCheck()
    {
        if (!defined('YII_EMBED_VERSION')) {
            $message = strtr(__('<p><b>Could not find Yii Embed plugin!</b><br/>Download it using the button below and move it into your <b>wp-content/plugins</b> folder, then visit the <a href=":plugins_href"><strong>Plugins</strong></a> page to enable it:</p><p>:download</p>'), array(
                ':settings_href' => get_admin_url() . 'admin.php?page=yii_embed_settings',
                ':download' => '<a href="https://github.com/cornernote/yii-embed-wordpress/archive/master.zip" class="button-primary">' . __('Download Yii Embed') . '</a>',
            ));
            do_action('foo_admin_notice', $message, 'error');
        }
    }

}

wp-content/plugins/foo/includes/FooSettings.php

<?php
/**
 * FooSettings manages the setup and callbacks for the administration options page.
 */
class FooSettings
{

    /**
     * @var array values to be used in the fields callbacks.
     */
    private $options;

    /**
     * Add callbacks to add admin menu and setup options form.
     */
    public function __construct()
    {
        // add admin menu
        add_action('admin_menu', array($this, 'admin_menu'));

        // setup options form
        add_action('admin_init', array($this, 'admin_init'));
    }

    /**
     * Callback to add the admin menu page under "WPAdmin > Settings".
     */
    public function admin_menu()
    {
        // add options page to the menu
        add_options_page(__('Foo Settings'), __('Foo'), 'manage_options', 'foo_settings', array($this, 'options_page'));
    }

    /**
     * Callback to register and add sections and settings
     */
    public function admin_init()
    {
        // register the setting and validation callback
        register_setting('foo', 'foo', array($this, 'validate'));

        // add the settings section
        add_settings_section('foo', '', array($this, 'settings_section_foo'), 'foo_settings');

        // add the dummy field
        add_settings_field('foo_dummy', __('Dummy Setting'), array($this, 'settings_field_dummy'), 'foo_settings', 'foo');
    }

    /**
     * Validate and sanitize each setting that is entered into the options page.
     * @param array $input Contains all settings fields as array keys
     * @return array
     */
    public function validate($input)
    {
        // validate dummy
        if (!empty($input['dummy']))
            $input['dummy'] = trim($input['dummy']);

        // return sanitized input
        return $input;
    }

    /**
     * Callback to display the options page.
     */
    public function options_page()
    {
        // load the options
        $this->options = get_option('foo');

        // begin the options form
        echo '<div class="wrap">';
        echo '<h2>' . __('Foo Settings') . '</h2>';
        echo '<form method="post" action="options.php">';

        // render settings fields
        settings_fields('foo');
        do_settings_sections('foo_settings');

        // render submit button
        submit_button(__('Save Changes'), 'primary', 'submit', false);

        // end the options form
        echo '</form>';
        echo '</div>';
    }

    /**
     * Callback to add the section settings
     */
    public static function settings_section_foo()
    {
        //echo __('Foo Settings:');
    }

    /**
     * Callback to add the dummy setting field
     */
    public function settings_field_dummy()
    {
        echo strtr('<input type="text" id="foo_dummy" name="foo[dummy]" class="regular-text" value=":value" /><p class="description">:description</p>', array(
            ':value' => isset($this->options['dummy']) ? esc_attr($this->options['dummy']) : '',
            ':description' => __('This is a placeholder setting, will be replaced when we have settings that need to be added.'),
        ));
    }

}

wp-content/plugins/foo/app/assets/css/foo_admin.css

/** Your admin styles go here. */

wp-content/plugins/foo/app/assets/css/foo_front.css

/** Your front styles go here. */

wp-content/plugins/foo/app/components/FooController.php

<?php
/**
 * FooController is the base controller for other controllers in the Foo plugin.
 */
class FooController extends YiiEmbedController
{
    /**
     * Initialize the controller
     */
    public function init()
    {
        // parent init
        parent::init();
        // set the view path
        Yii::app()->viewPath = Yii::getPathOfAlias('foo.views');
    }
}

wp-content/plugins/foo/app/controllers/FooBarController.php

<?php
/**
 * FooBarController is an example controller.
 */
class FooBarController extends FooController
{
    /**
     * @param CAction $action
     * @return bool
     */
    public function beforeAction($action)
    {
        if (is_admin()) {
            if (in_array($action->id, array('admin', 'view', 'create', 'update', 'delete')))
                return true;
        }
        else {
            if (in_array($action->id, array('index', 'view')))
                return true;
        }
        return false;
    }

    /**
     * Admin
     */
    public function actionAdmin()
    {
        $model = new FooBar('search');
        $model->unsetAttributes(); // clear any default values
        if (isset($_GET['FooBar']))
            $model->attributes = $_GET['FooBar'];

        $this->render('admin', array(
            'model' => $model,
        ));
    }

    /**
     * Create
     */
    public function actionCreate()
    {
        $model = new FooBar('create');

        // Uncomment the following line if AJAX validation is needed
        // $this->performAjaxValidation($model);

        if (isset($_POST['FooBar'])) {
            $model->attributes = $_POST['FooBar'];
            if ($model->save())
                $this->redirect(array('view', 'id' => $model->id));
        }

        $this->render('create', array(
            'model' => $model,
        ));
    }

    /**
     * Update
     * @param integer $id the ID of the model to be updated
     */
    public function actionUpdate($id)
    {
        $model = $this->loadModel($id);

        // Uncomment the following line if AJAX validation is needed
        // $this->performAjaxValidation($model);

        if (isset($_POST['FooBar'])) {
            $model->attributes = $_POST['FooBar'];
            if ($model->save())
                $this->redirect(array('view', 'id' => $model->id));
        }

        $this->render('update', array(
            'model' => $model,
        ));
    }

    /**
     * Delete
     * @param integer $id the ID of the model to be deleted
     */
    public function actionDelete($id)
    {
        $this->loadModel($id)->delete();

        // if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
        if (!isset($_GET['ajax']))
            $this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));
    }

    /**
     * Index
     */
    public function actionIndex()
    {
        $dataProvider = new CActiveDataProvider('FooBar');
        $this->render('index', array(
            'dataProvider' => $dataProvider,
        ));
    }

    /**
     * View Page
     * @param integer $id the ID of the model to be displayed
     */
    public function actionView($id)
    {
        $this->render('view', array(
            'model' => $this->loadModel($id),
        ));
    }
}

wp-content/plugins/foo/app/models/FooBar.php

<?php
/**
 * FooBar is an example model.
 */
class FooBar extends YiiEmbedActiveRecord
{
    /**
     * Returns the static model of the specified AR class.
     * @param string $className active record class name.
     * @return FooBar the static model class
     */
    public static function model($className = __CLASS__)
    {
        return parent::model($className);
    }

    /**
     * @return string the associated database table name
     */
    public function tableName()
    {
        return '{{foo_bar}}';
    }

    /**
     * @return array validation rules for model attributes.
     */
    public function rules()
    {
        $rules = array();
        if ($this->scenario == 'search') {
            $rules[] = array('id, name, description', 'safe');
        }
        if (in_array($this->scenario, array('create', 'update'))) {
            $rules[] = array('name, description', 'required');
            $rules[] = array('name', 'length', 'max' => 255);
        }
        return $rules;
    }

    /**
     * Retrieves a list of models based on the current search/filter conditions.
     * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
     */
    public function search()
    {
        $criteria = new CDbCriteria;

        $criteria->compare('t.id', $this->id);
        $criteria->compare('t.name', $this->name, true);
        $criteria->compare('t.description', $this->description, true);

        return new CActiveDataProvider($this, array(
            'criteria' => $criteria,
        ));
    }
}

wp-content/plugins/foo/app/views/fooBar/_view.php

<div class="view">

            <b><?php echo CHtml::encode($data->getAttributeLabel('name')); ?>:</b>
            <?php echo CHtml::link($data->name, array('fooBar/view', 'id' => $data->id)); ?>
            <br/>

            <b><?php echo CHtml::encode($data->getAttributeLabel('description')); ?>:</b>
            <?php echo CHtml::encode($data->description); ?>
            <br/>

        </div>

wp-content/plugins/foo/app/views/fooBar/admin.php

<?php
$this->pageTitle = Yii::t('foo', 'FooBar Admin');

$this->widget('zii.widgets.grid.CGridView', array(
    'id' => 'foo-bar-grid',
    'dataProvider' => $model->search(),
    'filter' => $model,
    'columns' => array(
        'id',
        'name',
        'description',
        array(
            'class' => 'CButtonColumn',
        ),
    ),
));

wp-content/plugins/foo/app/views/fooBar/create.php

<?php
$this->pageTitle = Yii::t('foo', 'Create FooBar');

$this->renderPartial('_form', array('model' => $model));

wp-content/plugins/foo/app/views/fooBar/_form.php

<div class="form">

            <?php $form = $this->beginWidget('CActiveForm', array(
            'id' => 'foo-bar-form',
            )); ?>

            <?php echo $form->errorSummary($model); ?>

            <div class="row">
                <?php echo $form->labelEx($model, 'name'); ?>
                <?php echo $form->textField($model, 'name', array('size' => 60, 'maxlength' => 255)); ?>
                <?php echo $form->error($model, 'name'); ?>
            </div>

            <div class="row">
                <?php echo $form->labelEx($model, 'description'); ?>
                <?php echo $form->textArea($model, 'description', array('rows' => 6, 'cols' => 50)); ?>
                <?php echo $form->error($model, 'description'); ?>
            </div>

            <div class="row buttons">
                <?php echo CHtml::submitButton($model->isNewRecord ? Yii::t('foo', 'Create') : Yii::t('foo', 'Save')); ?>
            </div>

            <?php $this->endWidget(); ?>

        </div>

wp-content/plugins/foo/app/views/fooBar/index.php

<?php
$this->pageTitle = Yii::t('foo', 'FooBars');

$this->widget('zii.widgets.CListView', array(
    'dataProvider' => $dataProvider,
    'itemView' => '_view',
));

wp-content/plugins/foo/app/views/fooBar/update.php

<?php
$this->pageTitle = Yii::t('foo', 'Update FooBar #:id', array(':id' => $model->id));

$this->renderPartial('_form', array('model' => $model));

wp-content/plugins/foo/app/views/fooBar/view.php

<?php
$this->pageTitle = Yii::t('foo', 'View FooBar #:id', array(':id' => $model->id));

$this->widget('zii.widgets.CDetailView', array(
    'data' => $model,
    'attributes' => array(
        'name',
        'description',
    ),
));

Examples

// TODO

Gii Code Generator

You can use Yii's awesome code generator from your WordPress site, just like you can in any other Yii app. Simply browse to your example.com/gii.

You must set WP_DEBUG to TRUE in wp-config.php, once this is done you can use Gii without a password.

Some generators do not allow the selection of a path (for example CrudGenerator) so you will have to generate them into the wp-content/plugins/yii-embed-wordpress/app folder and then move them to your plugin app folder.

To tune the Gii configuration or security access edit wp-content/yii-embed-wordpress/app/config/main.php.

ModelDoc Generator

Use the ModelDoc Generator to replace the phpdoc blocks in your models.

Other Generators

All the default Gii Generators including Controller Generator, Crud Generator, Form Generator, Model Generator and Module Generator are also available.