I’ve been experimenting with various integration scenarios for Enyo.  Sticking with what I have worked on so far, I decided to try my hand at writing a WordPress widget that displays an Enyo application.  You can see the results in the sidebar under “Box of Chocolates.”  The initial “widget” is just an Enyo application that has the new enyo.ImageCarousel kind with a couple of test images.  I hope to add some more functionality before our big road trip to Disney World and have it display some vacation pictures.

Anyway, I thought I’d write up the basics of how this works.  Since I’m not much of a WordPress developer, I’m sure I’ve violated all kinds of best practices, so if you’ve any suggestions on how to better accomplish this, let me know in the comments!

The Plugin

The first thing I did was to figure out I needed to create a WordPress Plugin.  All the plugin does is force-load enyo.js and enyo.css.  I spent a day trying to figure out how to load them only on pages where the widget runs, but it all resulted in failure.  If anyone has THAT suggestion, I’m all-ears.  I had also tried to get it where I could host the source and CSS for my app remotely with mixed success.  I was able to get my inital scriptto load and it appeared to load my stylesheet, but it never seemed to apply the styles.  I have a feeling that I’m using the wrong WordPress hooks and/or doing a bad job of managing my plugin.

The Widget

The widget part of the plugin is what is responsible for displaying the widget’s control panel and the widget itself.  The control panel for this widget represents the desire I had to include the source script and stylesheet anywhere, but it defaults to the local copy of those files on my server.  This is just a sub-directory of the plugin’s source.  It also lets you specify the ID and height of the <div> you want to use to render your Enyo app.  The widget code creates this <div> and then uses some WordPress magic (see next section) to hand that ID to the script that renders the Enyo app so it can render itself there.

The Special Parts

So far so good, right?  Well, there are a couple of things that you have to consider with WordPress and JavaScript plugins/widgets.  The preferred way to include these resources is by using the wp_register_script and wp_enqueue_script methods provided with WordPress.  Basically, registering a script ensures that WordPress will only include it once per page and queuing it allows WordPress to include the script “safely” (whatever that means).  There is one more trick to this, and that is using the wp_localize_script method after it has been queued.  This lets you pass an object to your script that you can then reference and is useful for passing the control panel data to your JavaScript.  I actually had to use this mechanism for both my package.js and enyo-wp-widget.js files.  In my package.js, I look for the existence of the object and then prepend the plugin_dir value to the beginning of any of the files I want to include.  In enyo-wp-widget.js I use the object to get the ID of the target <div>, create a WpWidget kind that holds my main App kind, and then render it into the target.  It’s a little of a roundabout, but it works and allows me to also develop my app in the browser by using an index.html that just renders the App kind.

The Next Thing

I still have a ways to go to refine this, but eventually I hope to have something that will let other Enyo developers who also run WordPress sites an easy way to include their apps as widgets on their sites.  I’ve gone ahead and included the most pertinent files here, but if I get everything simplified I might put it all up on GitHub or something and explain it a bit more thoroughly.

The Files

enyo.php


<?php
/*
Plugin Name: Enyo Plugin
Plugin URI: http://enyojs.com
Description: This plugin allows you to include the Enyo framework and supporting libraries for your WordPress site.
Version: 0.1_pre-alpha
Author: sugardave
Author URI: http://www.sugardave.com/
*/

error_reporting(E_ALL);
add_action('wp_head', array('Enyo', 'load_enyo'));
add_action('widgets_init', array('Enyo', 'register'));
register_activation_hook( __FILE__, array('Enyo', 'activate'));
register_deactivation_hook( __FILE__, array('Enyo', 'deactivate'));

class Enyo {
  function activate() {
    $data = array('enyo_wp_widget_kind_src' => plugins_url('widget_src/enyo-wp-widget.js', __FILE__), 'enyo_wp_widget_kind_css' => plugins_url('widget_src/enyo-wp-widget.css', __FILE__), 'enyo_wp_widget_render_target' => 'enyo-wp-widget-target', 'enyo_wp_widget_render_target_height' => '225px', 'onyx' => 0, 'layout' => 0, 'canvas' => 0, 'g11n' => 0);
    if (!get_option('enyo_wp_widget')) {
      add_option('enyo_wp_widget', $data);
    } else {
      update_option('enyo_wp_widget', $data);
    }
  }
  function deactivate() {
    delete_option('enyo_wp_widget');
  }
  function control() {
    $data = get_option('enyo_wp_widget');
    ?>
    <p><label>Widget location<input name="enyo_wp_widget_kind_src" type="text" value="<?php echo $data['enyo_wp_widget_kind_src']; ?>" /></label></p>
     <p><label>Widget CSS location<input name="enyo_wp_widget_kind_css" type="text" value="<?php echo $data['enyo_wp_widget_kind_css']; ?>" /></label></p>
    <p><label>Target &lt;div&gt; ID<input name="enyo_wp_widget_render_target" type="text" value="<?php echo $data['enyo_wp_widget_render_target']; ?>" /></label></p>
    <p><label>Target &lt;div&gt; height<input name="enyo_wp_widget_render_target_height" type="text" value="<?php echo $data['enyo_wp_widget_render_target_height']; ?>" /></label></p>
    <?php
    if (isset($_POST['enyo_wp_widget_kind_src'])) {
      $data['enyo_wp_widget_kind_src'] = attribute_escape($_POST['enyo_wp_widget_kind_src']);
    }
    if (isset($_POST['enyo_wp_widget_kind_css'])) {
                        $data['enyo_wp_widget_kind_css'] = attribute_escape($_POST['enyo_wp_widget_kind_css']);
                }
    if (isset($_POST['enyo_wp_widget_render_target'])) {
                        $data['enyo_wp_widget_render_target'] = attribute_escape($_POST['enyo_wp_widget_render_target']);
                }
    if (isset($_POST['enyo_wp_widget_render_target_height'])) {
                        $data['enyo_wp_widget_render_target_height'] = attribute_escape($_POST['enyo_wp_widget_render_target_height']);
                }

    update_option('enyo_wp_widget', $data);
  }
  function widget($args) {
    $data = get_option('enyo_wp_widget');
    echo $args['before_widget'];
    echo $args['before_title'] . 'Box of Chocolates' . $args['after_title'];
    echo '<span class="sub-heading">You never know what you\'re gonna get</span>';
    echo '<div id="' . $data['enyo_wp_widget_render_target'] . '" style="height: ' . $data['enyo_wp_widget_render_target_height'] . ';"></div>';
    echo $args['after_widget'];
    wp_enqueue_script('package.js', plugins_url('widget_src/package.js', __FILE__));
    wp_localize_script('package.js', 'WpInfo', array('plugin_dir' => plugins_url('/widget_src/', __FILE__)));
    wp_enqueue_script('enyo-wp-widget.js', $data['enyo_wp_widget_kind_src']);
    wp_localize_script('enyo-wp-widget.js', 'RenderInfo', $data);
  }
  function register() {
    register_sidebar_widget('Enyo Sidebar Display', array('Enyo', 'widget'));
    register_widget_control('Enyo Sidebar Display', array('Enyo', 'control'));
  }
  function load_enyo() {
    $data = get_option('enyo_wp_widget');
    echo '<script src="/frameworks/Enyo/enyo/enyo.js"></script>';
    echo '<link rel="stylesheet" type="text/css" href="/frameworks/Enyo/enyo/enyo.css" />';
    if (!$data) {
      return;
    } else {
      if ($data['enyo_wp_widget_kind_css']) {
        echo '<link rel="stylesheet" type="text/css" href="' . $data['enyo_wp_widget_kind_css'] . '" />';
      }
    }
  }
}

?>

package.js


var WpInfo = WpInfo || {
  plugin_dir: ""
}

var pd = WpInfo.plugin_dir;

enyo.depends(
  "$lib/onyx",
  "$lib/layout",

  pd + "App.js"
);

enyo-wp-widget.js


var target = enyo.dom.byId(RenderInfo.enyo_wp_widget_render_target);

enyo.kind({
  name: "enyo.WpWidget",
  kind: enyo.Control,
  classes: "enyo-unselectable enyo-fill",
  components: [
    {name: "widget", kind: "App"}
  ]
});

new enyo.WpWidget().renderInto(target);

App.js


enyo.kind({
  name: "App",
  kind: enyo.ImageCarousel,
  classes: "enyo-fill",
  wrap: true,
  components: [
    {kind: enyo.ImageView, src: "http://sugardave.com/images/sugardave_gravatar.jpg", scale: "auto", style: "width:300px; height:225px;"},
    {kind: enyo.ImageView, src: "http://sugardave.com/images/lobster.jpg", scale: "auto", style: "width:300px; height:225px;"}
  ],
  rendered: function() {
    this.inherited(arguments);
    this.heartbeat = setInterval(enyo.bind(this, "next"), 10000);
  }
});

 

2 Responses to More Enyo and WordPress Integration

  1. Will Hatfield says:

    I’ve played around with loading enyo on demand. I can do it in javascript (at least the minified, one-file version) but I’m not sure how to in php.

    • sugardave says:

      Yeah, I figured out how to arbitrarily include the .js wherever I want in my PHP stuff, it’s the stylesheets that are a problem. <link>s can only go in <head> and by the time WordPress gets around to loading my widget, the <head> is already set. At least that’s what I think is the problem. There were a number of factors that were working against me, I think. Number one was trying to host the source from my git repo. bitbucket.org’s raw source serves files as text/plain no matter what they are and the problem went away when I moved them to the local widget directory.

      Anyway, I’ll plug away at this some more when I have more free time. Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *