Creating an ExpressionEngine Add-On

MacBook Code

Image courtesy of Christopher Gower

ExpressionEngine Add-Ons mean no more PHP in templates!

I’m going to explain the use of ExpressionEngine Add-Ons, namely plugins, and how they’ll help remove PHP from your site templates. In short, your life will be changed completely! (unless you already know how to build plugins or don’t even use ExpressionEngine, in which case your life will be exactly the same.)

Coming from a WordPress background I was initially confused by the selection of Add-Ons that can be installed onto an ExpressionEngine website. For that reason, I’ll run through them all quickly for you now, in layman’s terms.

Modules

These are the ‘big boys’. If you want to create an Add-On with settings; database modification and template tags this is the route to go down. Modules allow you to create new sections within the admin area alongside database tables for all that sweet data management.

Extensions

Extensions simply extend an existing module allowing you to call your own functions alongside them. This is usually done with hooks, something that a large number of modules make use of.

Fieldtypes

This too is pretty self-explanatory. A fieldtype allows you to create a custom field which can then be assigned to a channel and populated when managing entries. This could include things such as WYSIWYG editors, standard text input fields, etc.

Plugins

A plugin, unlike in WordPress, is a simple Add-On that allows you to display information. You cannot modify or add data to a database using a plugin, instead, you can grab data from the database and manipulate it to display on your site. Plugins are not just limited to only database output, you can output any HTML from within a plugin.

Each of ExpressionEngine’s Add-Ons has something in common. They’re all built using PHP. This allows us to separate PHP from the HTML/EE Code templates which make for a cleaner site.

Creating a plugin

Firstly you’ll need to create a new folder under system/user/addons/ You can name this folder whatever you like but it needs to be lowercase and it needs to match the main class of the plugin (see below).

Since ExpressionEngine 3, each Add-On requires an addon.setup.php file:

<?php

return array(
	'author'      => 'Kieran McClung',
	'author_url'  => 'https://kieranmcclung.co.uk',
	'name'        => 'Example Plugin',
	'description' => 'This plugin does very little.',
	'version'     => '0.0.1',
	'namespace'   => 'KM\Example_plugin'
);

This needs to be saved directly within the folder you created above.

The addon.setup.php file is relatively straight-forward and really just serves a purpose to display information about the Add-On. The above example shows all required keys for the array but you can find more over on the ExpressionEngine documentation.

Next, you’ll need to create the main plugin file. This file must be named after the main class (again, see below). You’ll also need to prefix the file name with pi. This tells ExpressionEngine that the file is a plugin.

In my example I now have the following:

  • A folder under the system/user/addons directory called example_plugin
  • Contained within this directory are two files:
    • addon.setup.php
    • pi.example_plugin.php

Make the plugin do something

I’ve created an incredibly basic plugin for this post which will grab an entry’s title and trim it down to a specific length. Whilst simple, it does show a number of key things that can be done with an ExpressionEngine plugin.

<?php

class Example_plugin {

	public function truncate()
	{
		// Create variables from EE parameters
		$entry_id = ee()->TMPL->fetch_param('entry_id');
		$limit    = ee()->TMPL->fetch_param('limit') ? : 30;

		// Check whether $entry_id is empty
		if (empty($entry_id))
		{
			return 'Entry ID is missing.';
		}

		// Query the database
		$query = ee()->db->select('title')
			->where('entry_id', $entry_id)
			->get('channel_titles');

		if ($query->num_rows() === 0)
		{
			return 'Sorry, no entry has been found with that ID';
		}
		else
		{
			// Get the title
			$title  = $query->row('title');
			$length = strlen($title);

			// Check whether the title's length is greater than our limit
			if ($length > $limit)
			{
				return substr($title, 0, $limit) . '…';
			}
			else
			{
				return $title;
			}
		}
	}
}

Line 3: This is the famed class that I’ve been mentioning throughout the post. Just to reiterate, this needs to be named exactly like the plugin filename but can contain mixed-case characters.

Line 5: Here we create a public function called truncate. This will allow us to the use following code within our ExpressionEngine template: {exp:example_plugin:truncate}. Anything returned from this function will be shown once the plugin tag has been parsed.

Lines 8 & 9: Next up we need to set two variables and we’re utilising ExpressionEngine’s Template Class to grab two parameters from the tag. If we add two parameters to our tag: {exp:example_plugin:truncate entry_id='1' limit='20'}we’ll be able to grab them both using the ee()->TMPL->fetch_param(); function.

Line 9: We can use a ternary operator here to ensure that a limit is always set. If no limit is passed as a parameter on the tag, we’ll fall back to the 30 default.

Lines 12-15: This plugin requires an entry id in order for it to function correctly so we check for this before proceeding. If an ID isn’t found we can return a helpful message to the template.

Lines 18-20: Now we need to extract the title of an entry based on the provided ID and to do this we’re going to use the Database Class. Fortunately, as was with the tag parameters, ExpressionEngine makes it very easy to make database calls. We’re going to store the database query as a variable $query so that we can do some checks later on.

Line 18: We’re initiating the database class with ee()->db followed by a select() query. In our example, we only need the title field but we could use '*' to select all fields in the database. The string entered inside the select query relates to a field name within the database. This could also be a comma-separated list of values.

Line 19: Next we need to add our where clause. We’re going to use our $entry_id variable here to make sure that we’re only getting data from a row in the database that has the value of this variable.

Line 20: Finally we tell ExpressionEngine which table we want to get the data from. In this example, we use channel_titles. ExpressionEngine will, by default, prefix all database tables with exp_. You will notice that we don’t reference this database prefix when collecting data from the specified table. ExpressionEngine will sort everything out for you which is handy for sites that use their own prefixes.

Our query is now set and stored to the $query variable. This will perform the following SQL command:

SELECT `title`
FROM `exp_channel_titles`
WHERE `entry_id` = '1' -- 1 represents the entry_id you've passed in the tag

Lines 22-25: ExpressionEngine has a handy way of checking whether anything was returned from the database call. We’ll check whether the total number of results is equal to 0 and if it is we need to return a suitable message to the template.

Line 29: Here we can grab the title from the $query. We can make an assumption here without performing any extra checks. Entry IDs are unique within the channel titles table so we know the query will have only returned 1 result. Because of that, we can grab the title using $query->row('title').

If the query had returned multiple values we would either need to loop through each of these or select the first result. You can find out more information about the Database Class over on the ExpressionEngine Documentation.

Line 30: This line is a simple bit of PHP which counts the length of the $title and stores it in the $length variable.

Lines 33-40: We can now use the $length variable to check whether it’s greater than our $limit. If it is, we need to return the trimmed string otherwise, we can just return the title as is.

Line 35: Again, this is a fairly simple PHP function which takes our $title and trims it by our $limit. I’ve included an ellipsis here to indicate that there is more to the title.

And that’s it! The plugin will now grab the entry’s title and trim it to your specified length.

And that’s a wrap

There we have it then. I’ve given you a quick explanation of the various ExpressionEngine Add-Ons, covered the anatomy of a basic ExpressionEngine plugin, and built a simple, yet functioning, plugin. Of course, there is a lot more to learn when it comes to building your own ExpressionEngine Add-Ons but this should hopefully set you on the right path.

I’ve included a few links below to various learning resources which reference the code used in this post.

Hopefully you’ve found this post interesting or dare I say helpful. If you’d like me to create a simple Module, drop a comment below and I’ll make it so.

Download the Simple ExpressionEngine Add-On

Extra credit

The plugin in this post is only for demonstration purposes and my aim was to showcase a few different options for you when developing an Add-On. If you wish to use this plugin on a site that you’re developing we can tidy it up a little.

<?php

class Example_plugin {

	public function truncate()
	{
		$title = ee()->TMPL->fetch_param('title');
		$limit = ee()->TMPL->fetch_param('limit') ? : 30;

		if ( ! empty($title))
		{
			$length = strlen($title);

			if ($length > $limit)
			{
				return substr($title, 0, $limit) . '…';
			}
			else
			{
				return $title;
			}
		}
	}
}

This plugin tag will be nested within your channel entries loop so it makes little sense to be making another database call. Instead, you can pass the {title} as a parameter to your plugin and simply check its length and carry out the trimming if necessary. Your tag would now look like {exp:example_plugin:truncate title='{title}' limit='12'}

Resources

Related

4, 8, 15, 16, 23, 42.

© Kieran McClung, 2019 Privacy & Cookies