Advertisement
CMSs

Building your First ExpressionEngine Plugin

by

No matter how awesome a CMS is, there will be times when you are required to meet a specific need that simply doesn't work out of the box. Here we will explore creating Plugins for ExpressionEngine to meet such needs.

Version Notes

Just recently EllisLab, the creators of ExpressionEngine, announced the official release date of ExpressionEngine 2.0 as being December 1st, 2009. Please note that this tutorial is written with details specific to versions 1.6.x. Certain details such as file paths and global objects will be changing for version 2.0. While these details will be different the general application and approach to plugin creation for ExpressionEngine will remain the same.

Types of ExpressionEngine Add-Ons

Like most robust management systems available, ExpressionEngine, or "EE", comes with a number of ways for a developer to add functionality that may not be there by default. Unlike popular systems like WordPress, EE has different names for these add-ons depending on how they interact with your site. There are three primary ways you can add functionality to EE 1.6.x which are Plugins, Extensions and Modules. Plugins primarily deal with modifying your template code and tend to be more of a front-end job. Extensions typically tweak the functionality of the back-end, or Control Panel by tying into "hooks" in the system. Modules tend to be larger in scope, have their own area in the Control Panel and can also be used on the front-end of the EE website. Modules can be full blown apps sitting within EE and utilizing membership, templates, database, etc.

Required Experience

Things it would sure help to know before moving forward:

  • How to setup and install ExpressionEngine in a development environment
  • Basic understanding of ExpressionEngine's Control Panel and template parsing
  • Basic understanding of PHP and Object Oriented programming
  • How to read documentation!

Our Plugin

For this tutorial we are going to create a simple plugin that scans through the data passed to it and wraps certain strings with HTML tags. This is a very simple application of an EE plugin and should show you how easy it is to get started with plugin development. Our plugin will be used to search for and replace acronyms that we use as developers. For the sake of the example we will stick to three: HTML, CSS, and RSS. Let's call the plugin "Auto Acronym."

Where Do I Start?

The best place to start with EE Add-On development is the official ExpressionEngine Documentation. Before you dive into developing for ExpressionEngine you should read through their guidelines which, if followed, help keep the system running well. The guidelines cover things like naming conventions, performance and security. I'll give you a few minutes to read over the ExpressionEngine Add-On Development Guidelines

Okay, now that you've read that we can start looking at how we actually create the plugins and what makes up a simple one.

Pieces of the Puzzle

Every plugin requires one class and at least one function. The naming convention is very specific so we need to make sure we do it correctly and carefully. The name of our plugin is Auto Acronym and it comes into play with our file name, class name, and EE tags. The file name takes the name of your plugin and replaces all spaces with underscores while prepending "pi." to the front. All letters must be lower case. That would make our file name "pi.auto_acronym.php". All EE plugins go into a single directory located under system/plugins (imagine that).

The class name is similar to the file name with the exception of the first letter being capitalized. This makes our class name "Auto_acronym". This plugin will only need one function so it will have the same name as the class. These will also be the names we use in our EE plugin tags. Plugin tags always start with "exp:" which is telling the template parser, "Hey! I need some processing over here!". What follows will be the name of your class all lowercase giving us: "exp:auto_acronym". The third segment of a plugin tag calls the function within the plugin's class. In our example we will just be using the one function, the constructor, so we only need the class name. So far here is what we know about our plugin:

Putting it to Code

Let's see what our code is so far:

<?php

class Auto_acronym
{
   
   function Auto_acronym()
   {
      
   }
   
}

/* End of file pi.auto_acronym.php */
/* Location: ./system/plugins/pi.auto_acronym.php */

For those of you who are familiar with WordPress plugin development, you know that WordPress extracts some data from commented code when displaying details in the Plugin Manager. ExpressionEngine does something similar except with an array within your plugin file. Let's go ahead and add that to our file above the class and give it the appropriate information.

<?php

$plugin_info       = array(
   'pi_name'        => 'Auto Acronym',
   'pi_version'     => '1.0',
   'pi_author'      => 'Erik Reagan',
   'pi_author_url'  => 'http://erikreagan.com',
   'pi_description' => 'Automatically wraps certain acronyms in the HTML <acronym> tag',
   'pi_usage'       => Auto_acronym::usage()
   );

class Auto_acronym
{

   function Auto_acronym()
   {

   }

}

/* End of file pi.auto_acronym.php */
/* Location: ./system/plugins/pi.auto_acronym.php */

Each of the array keys should be pretty obvious as far as what they are for. The last key, however, is a little different. It's obviously not just a string like the others. It is used to tell the ExpressionEngine control panel where to find the usage, or simple documentation, for the plugin. Every EE plugin should have some basic docs within the plugin file so that those using the plugin can just view it in the Control Panel and see how to utilize the tags. This is done by adding a function to your plugin class called "usage" which . I like to put the usage function last in my class so let's go ahead and copy & paste the example from the ExpressionEngine Plugin Docs and remove the content between the ?> and <?php tags since our content will go there.


   // ----------------------------------------
   //  Plugin Usage
   // ----------------------------------------

   // This function describes how the plugin is used.
   //  Make sure and use output buffering

   function usage()
   {
   ob_start(); 
   ?>

   

   <?php
   $buffer = ob_get_contents();

   ob_end_clean(); 

   return $buffer;
   }

Our usage does will be written after we complete our plugin. For now let's just put in some text for testing purposes. Keep in mind that this text will be treated as pre-formatted and all characters are converted into HTML entities; HTML will not work. Let's look at our plugin in its entirety so far

<?php

$plugin_info       = array(
   'pi_name'        => 'Auto Acronym',
   'pi_version'     => '1.0',
   'pi_author'      => 'Erik Reagan',
   'pi_author_url'  => 'http://erikreagan.com',
   'pi_description' => 'Automatically wraps certain acronyms in the HTML <acronym> tag',
   'pi_usage'       => Auto_acronym::usage()
   );

class Auto_acronym
{

   function Auto_acronym()
   {

   }
   
   
   // ----------------------------------------
   //  Plugin Usage
   // ----------------------------------------

   // This function describes how the plugin is used.
   //  Make sure and use output buffering

   function usage()
   {
   ob_start(); 
   ?>

   This is where our simplified documentation will go

   <?php
   $buffer = ob_get_contents();

   ob_end_clean(); 

   return $buffer;
   }

}

/* End of file pi.auto_acronym.php */
/* Location: ./system/plugins/pi.auto_acronym.php */

Now that we have a bare-bones plugin file we need to save it to our system/plugins directory to make sure it's being read by the system properly. After saving it you will see it under Admin > Utilities > Plugin Manager. If you click on our new plugin you should see a page like this that contains the information we just added to our plugin

Making it Work

Now that our plugin is being pulled into the ExpressionEngine system properly, we can make it actually do something. Every plugin returns some form of data. This data will always come from a standardized variable that EE will look for called "return_data". The first thing we want to do is define it before our first function within the class. Then, just for testing purposes, we will use it within our first function to return a simple string.

class Auto_acronym
{
   
   var $return_data  = "";
   
   function Auto_acronym()
   {
      $this->return_data = "Just making sure this works";
      
   }

Now that we have some data being returned we can test it on the front end of our website. I am using a very minimal template for testing purposes right now but you can use this within any of your ExpressionEngine templates. If you recall from earlier our plugin tag is {exp:auto_acronym} and since we only have one function we do not need to use a third segment in this plugin. Here's what my template code looks like followed by what my browser shows:

<h1>Plugin Tutorial</h1>

<p>{exp:auto_acronym}</p>

Not exactly ground-breaking but it is getting us one step closer to our goal. Now that we know how to pass data back we can look at grabbing data passed to our plugin.

Processing Data with our Plugin

The first method we will focus on with processing data is where ExpressionEngine reads all of the data between the plugin tag pair. I you don't already know, our tag pair is very similar to how HTML tag pairs work. We have an open tag followed by data followed by a close tag like this:

{exp:auto_acronym}
This gets processed
{/exp:auto_acronym}

ExpressionEngine makes it very easy to get this data with the use of the Template Object. In this case we will need to make it global within our function so that we have access to it. Then we define our variable by calling in to play the "tagdata" variable. This variable is the data between our open and close tag pair. Take a look:

function Auto_acronym()
{
   global $TMPL;

   $data = $TMPL->tagdata;
}

Now lets do something very simple with our data and make it bold since it is just text right now. We will add the <strong> tags around it and then define our return_data variable accordingly. This is what our code, template and rendered page should look like now:

Plugin:

function Auto_acronym()
{
   global $TMPL;

   $data = '<strong>'.$TMPL->tagdata.'</strong>';
   
   $this->return_data = $data;
}

Template:

<h1>Plugin Tutorial</h1>

{exp:auto_acronym}
<p>This gets processed</p>
{/exp:auto_acronym}

Rendered in Browser:

Do Something Already!

Okay, okay. Let's actually have some fun with this now. Our goal with this plugin is to scan through the data passed to it for common web development acronyms. I mentioned that we would be using 3 for the tutorial: HTML, CSS & RSS. The first this we want to do is put them all into an array within our function. Note that if we were using this array across the plugin and had multiple functions we would probably want to store this outside of the constructor so it could be called by any of the functions.

function Auto_acronym()
{
   global $TMPL;

   $data = $TMPL->tagdata;
   
   $acronyms = array(
      'HTML' => 'HyperText Markup Language',
      'CSS' => 'Cascading Style Sheets',
      'RSS' => 'Really Simple Syndication'
      );
}

Now that we have our tag data along with the array of acronyms we need to run a foreach() loop on the acronyms. The first thing we will do is run the acronym and tagdata through a strpos() function to make sure that the acronym is, in fact, within our string. The reason we do this is so that we don't run unneeded string replacements. If your acronym dictionary had hundreds of values and you were running it through a lengthy article it could risk unnecessary processing time. If and only if the acronym is within our tag data we will use the str_replace() function to actually add in the <acronym> tags. After our foreach() loop we will define our return_data variable accordingly. Here's what it looks like:

function Auto_acronym()
{
   global $TMPL;

   $data = $TMPL->tagdata;

   $acronyms = array(
      'HTML' => 'HyperText Markup Language',
      'CSS' => 'Cascading Style Sheets',
      'RSS' => 'Really Simple Syndication'
      );
      
   foreach ($acronyms as $short => $long)
   {
      if (strpos($data, $short) !== FALSE)
      {
         $data = str_replace($short, '<acronym title="'.$long.'">'.$short.'</acronym>', $data);
      }         
   }
   
   $this->return_data = $data;
   
}

In order to test this properly we will need to change our template so that it actually has some of our desired acronyms in it. I'm going to change my template to this:

<h1>Plugin Tutorial</h1>

{exp:auto_acronym}
<p>My name is Erik and I am an addict. I stay up late into the night marking up HTML and CSS with magical alignment.
Whitespace speaks volumes of my care and finesse of the code. My RSS subscribers wait on their toes for my next
example of code beauty. Okay...not really.</p>
{/exp:auto_acronym}

Saving our template and refreshing our browser should produce this:

Now We're Getting Somewhere!

Now that we are properly processing the tags between the open and close tags of our plugin, let's look at the other option: passing data within a single tag. Using a single tag with plugins will require adding in a parameter so that data is still passed through to the plugin to be process. You can name the parameter whatever you want. In our case we will use this and add it to our template:

{exp:auto_acronym data="HTML"}

Now that we have a single tag we need to find a way to use it in our plugin. Any parameter that you want to use in your plugin can be fetched using the same Template Object that we used earlier. Instead of being available via a variable you need to fetch it with a function called fetch_param(). We want our pluign to be usable with either a single tag or a tag pair so we will take that into account when we define our $data variable. This is what we will change:

// Original 
$data = $TMPL->tagdata;

// New
$data = ($TMPL->fetch_param('data')) ? $TMPL->fetch_param('data') : $TMPL->tagdata ;

If you are not familiar with this syntax is basically says "if the data parameter exists (or returns true) then use it as our data variable, otherwise use the tagdata between tag pairs." This one change will enable us to use both tag pairs and single tags with the data parameter defined. Here's what our template should render now:

Almost Done!

Now we have a fully functioning ExpressionEngine plugin. The final step in completing it is adding in useful "usage" information. Let's go down to the usage() function and add in some simple documentation for the Control Panel.

function usage()
{
   ob_start(); 
?>

The "dictionary" of acronyms is stored in an array within the plugins/pi.auto_acronym.php file.

Automatically turn a string into an HTML acronym if it is within our acronym dictionary. You can do this with individual words or large blocks of text.


Simple Example
===========================

{exp:auto_acronym data="HTML"}

This outputs:
<acronym title="Hypertext Markup Language">HTML</acronym> in your ExpressionEngine template.



Large Block Example
===========================

{exp:auto_acronym}

<p>My name is Erik and I am an addict. I stay up late into the night marking up HTML and CSS with magical alignment.
Whitespace speaks volumes of my care and finesse of the code. My RSS subscribers wait on their toes for my next
example of code beauty. Okay...not really.</p>

{/exp:auto_acronym}

This outputs:
<p>My name is Erik and I am an addict. I stay up late into the night marking up <acronym title="Hypertext Markup Language">HTML</acronym> and <acronym title="Cascading Style Sheets">CSS</acronym> with magical alignment.
Whitespace speaks volumes of my care and finesse of the code. My <acronym title="Really Simple Syndication">RSS</acronym> subscribers wait on their toes for my next
example of code beauty. Okay...not really.</p>
<?php
   $buffer         = ob_get_contents();

   ob_end_clean(); 

   return $buffer;
}

Now our control panel should look something like this:

Congratulations!

You've now completed your first ExpressionEngine plugin. Hopefully this will open up the doors for you now that you see how easy it is. Fetching and returning data is very simple and you can run a lot of your PHP magic from within the plugin itself. I am hosting this plugin on my GitHub account where you can download the full plugin code there if you would like. Next in our ExpressionEngine Add-On series we will look at creating a simple Extension for the Control Panel. Stay tuned!

P.S.

Don't forget to check out these other awesome ExpressionEngine tutorials!


Related Posts
  • Code
    Theme Development
    Custom Controls in the Theme CustomizerTheme customizer custom control 400
    In the last article, we explored the advanced controls available in the Theme Customizer, and how to implement them. We’re going to look at how to create our own custom control, allowing you to choose which Category of Posts are displayed on the home page. To get started, download version 0.6.0 of our Theme Customizer Example.Read More…
  • Code
    Theme Development
    Creating a WordPress Theme from Static HTML - Creating a Page TemplateCreating wordpress theme from html 400
    So far in this series, I've shown you how to create a fully functioning WordPress theme from static HTML. We've covered the following steps: preparing your markup for WordPress converting your HTML to PHP and splitting your file into template files editing the stylesheet and uploading your theme to WordPress adding a loop to your index file adding meta tags, the wp_head hook and the site title and description to your header file adding a navigation menu adding widget areas to the header and sidebar adding widget areas, a colophon and the wp_footer hook to the footer file. At the moment, your theme only has one template file for displaying content—the index.php file. A powerful feature of WordPress is the ability to use template files for different kinds of content.Read More…
  • Web Design
    UX
    Walk Users Through Your Website With Bootstrap TourTour retina
    When you have a web application which requires some getting used to from your users, a walkthrough of the interface is in order. Creating a walkthrough directly on top of the interface makes things very clear, so that's what we're going to build, using Bootstrap Tour.Read More…
  • Code
    PHP
    Creating a Photo Tag Wall With Twilio Picture Messaging & PHPProcedural to oop php retina preview
    Twilio's recently announced Picture Messaging has vastly opened up what we can do with text messaging, now we can attach photos to our text messages and have them get used in different ways. In our case, we are going to build a Photo Tag Wall, which will contain photos linked to tags that will be displayed on a website.Read More…
  • Code
    Theme Development
    Creating a WordPress Theme From Static HTML: Creating Template FilesCreating wordpress theme from html 400
    In the first part of this series, I showed you how to prepare your HTML and CSS files for WordPress, ensuring the structure would work, the code was valid and that the correct classes were being used. In this tutorial you'll learn how to take your index.html file and split it up into a set of template files for use by WordPress.Read More…
  • Code
    Theme Development
    Creating a WordPress Theme From Static HTML: Preparing the MarkupCreating wordpress theme from html 400
    Last year I did a small (and admittedly very un-scientific) survey among other WordPress developers. What I wanted to know was this: When they built their first WordPress theme, how did they do it? Did they hack an existing theme or did they start with their own static HTML and turn it into a theme? The majority of people I spoke to used the second approach - they were all experienced frontend developers who had built sites using HTML and CSS, and found it easiest to take their existing HTML files and convert them to a theme. Two of the people I spoke to were lecturers or teachers, and told me that this is the approach they use with students. So in this series I'm going to show you how to do just that.Read More…