After many requests (and a few promises) I am finally putting together a series of blog posts on building a complex plugin for the Mura CMS. Plugins are basically stand-alone applications that take advantage of Mura's extensibility hooks to integrate themselves into the CMS and web site. This feature set has matured greatly over the last year, and allows developers a great deal of latitude over how they can achieve this and in what tools they can use. This series of posts will be as much about building the plugin as introducing developers to the many facets of Mura extensibility.
In this series I'm going to explore in depth the topic of building a plugin that integrates directly into the Mura CMS. Specifically, I'll be building the Meld Gallery application using FW/1 and ColdSpring. Once complete, the plugin will include the following functionality:
- The ability to install the plugin (including its database) into any current version of Mura
- The ability to upload images and arrange and organize them into any number of image "sets"
- The ability to display these image "sets" in a wide variety of formats via configurable "displays"
- The ability to easily build and add custom "displays" to the plugin (i.e. jQuery slide shows, Flash slide shows, ShadowBox ... you get the picture)
The process will expose developers to some of the more intricate details of Mura plugin development, including the PluginManager and general Mura API, the creation of configurable display objects, use of Mura events (broadcast and interception), and the process of building an installable plugin that requires a database. It should offer something to anybody interested in developing plugins for Mura, but generally the more experience you have with ColdFusion, FW/1 and ColdSpring the more you will get out of it. Also, you may want to review the programmer's guide to Mura CMS.
What this series won't do is explore FW/1 or ColdSpring in any depth beyond how they apply specifically to the plugin. Just as important, I should note that this is not intended to be an 'introductory' series, as several good resources already exist on that topic. Instead, I will be discussing the actual process far more than the code itself, though everything in the downloadable examples will be heavily commented.
Finally, Meld Gallery will be a fully functional application when it is complete, licensed under the GPL 2 license. It will be licensed this way because it will be using code from the Meld Solutions Meld Manager plugin.
The Core
The beginning of our new Meld Gallery plugin is going to be based upon what I call the "core". This is essentially an installable, empty plugin that includes all of the foundation elements that I will be building upon (download the core for MeldGallery). The core we will be working with is based upon the FW/1 plugin template originally developed by Bob Silverberg and the Mura team. Typically I begin creating a new plugin by:
- Copying the blank 'core' plugin to a new directory (Directory A)
- Updating the basic identity/name settings for the plugin
- 'Zipping' up the entire contents of the directory (this creates my installable plugin package)
- Installing this into a current, virgin copy of Mura
- Making the directory of the newly installed plugin (Directory B) my work environment for the project (it should be found in /[mura]/plugins/MeldGallery_1/ or similar)
- Deleting the original directory (Directory A) as it will no longer be used
This allows you to start your development in a working environment that you can immediately test and play with. Now, there is one very important issue with doing you development this way: the dreaded "delete plugin" button. The thought of having a single, easily clickable button that can nuke all of my hard work is disconcerting, so I typically either a) delete the 'delete' link or b) delete the 'delete me' code in the PluginManager function. Also, the best practice of using version control like SVN or Git will protect your work should the worst happen.
Identity
To establish the unique identity for your plugin, there are several files you will have to update. The first, config.xml, is found in the /plugin directory. If you open this page, you will find the following block of code at the top (/plugins/config.xml):
The most important value to remember is the Package value. The Package value is the unique identifier for your application, and we will refer to it many times in our code to identify both our application in the Mura Scope as well as the 'root' for our application.
Below this you will also see a series of settings (/plugins/config.xml):
These settings are in the 'core' because they provide the five key values we will use in connecting to our database. DSNType is used in our code to customise our queries to the appropriate engine, DSNPrefix lets users install the plugin's database tables in an existing DSN without having to worry about over-writing existing tables, and the rest of the values are for the DSN identity/permissions. The final block of code in the config.xml that is key is the onApplicationLoad event handler. This initiates the setup for our FW/1 plugin, and really is the only event that has to be hard-coded into our setup.
The next file we have to alter is the configuration settings at the top of the /Application.cfc file (/Application.cfc):
You will notice that the applicationKey and Package values are identical; this is crucial. The "base" value is the basically the root mapping for our plugin and again is based upon the Package value. Now, our plugin might not use "SubSystems", but for the purpose of this series we are going to assume that we are. These can be handy for isolating your display objects, for making your plugin itself more modular, and just generally for organizing your plugin application code. Finally, we have set reloadApplicationOnEveryRequest to 'true' so that our changes during development will be reflected immediately.
Packaging & Install
You can now go ahead and install this plugin in your Mura site. To create the "installable" package, select all of the files/directories in the plugin directory (i.e. everything inside of MeldGallery) and zip it up into a Zip archive. A very common mistake is to include the root directory as well, which will cause Mura to throw an error. In other words, in your zip file you should see /plugin, /assets, /Application.cfc etc. as opposed to a single directory that contains them.
Now that you have your install package, go to Mura Admin > Site Settings and click on the "Plugins" tab, then select and "Deploy" your plugin. The setup screen should display the values entered in the config.xml, and ask for your DSN information (you can fill out junk for now). Make sure and check off the "Default" site, then click "Update". The plugin is now installed!
SUGGESTED ACTION: at this time you should create your own 'core' plugin by renaming the values in the downloaded example and installing it into Mura.
Towards the Future
Admittedly we haven't covered much new ground so far, but have at least established the foundation we will be building upon. In the next post of the series I'll be putting the first part of the core ColdSpring service into place. The post will cover adding our base services, reviewing how they are integrated into the FW/1 framework, and taking a closer look at the Mura / FW/1 relationship. In the coming weeks we'll be adding a lot of functional code, remote proxies, resource bundles for internationalization, jQuery administrative tools, fully 'pluggable' and configurable display objects, and finally building our install package so that others can easily use our new application.

Jun 4, 2010 at 9:41 AM Great stuff Grant--can't wait for the next one.
Jun 8, 2010 at 9:46 AM Nice post Grant. For some idea on packaging your Mura plugin see my blog post about using ANT to automate build numbers and zipping up the plugin. http://blog.adampresley.com/2010/using-ant-to-automate-a-build-version-number/
Keep up the blogging!
Jun 11, 2010 at 12:00 PM @Adam, nice post back at you, though I have to admit I have never used ANT. It's stuck in one of those "haven't got time to explore it but when I do I'm sure it will be indispensable but I haven't got time to explore it" infinite loops right now.
With packaging becoming more critical in the coming months, I think that might be the break; I need to get it into my toolbox.
Aug 2, 2010 at 9:31 AM Good post Grant, have the next parts been posted yet? Looking to create my first Mura CMS plugin with FW/1 and am using your post as a guide. Cheers
Aug 2, 2010 at 9:37 AM @jbuda: there's been a lot (a LOT) of updates to the FW/1 plugin framework recently, including bug fixes and improvements, that I'm working through with the Mura guys before continuing the series.
I'd recommend starting with Mura Tools as a starting point in building Mura plugins for now. It's an Eclipse plugin, and should get the ball rolling nicely for you.
Aug 4, 2010 at 9:28 AM Grant, im close to finishing a custom plugin using Framework 1 and Mura. However, im not sure how to access the datasource from the Mura application in my FW/1 Service?
Aug 4, 2010 at 9:36 AM @jbuda I'm not sure how to answer that. You would normally use fw/1 to create a Display Object to render the content on a Mura page, but that little sentence involves a lot of different things. You could also use an event to render the content, which can be complicated too.
Without seeing what you are trying to do or how you are doing it, I can't really give you any specifics.
I'd suggest visiting the Mura forums and posting your question with a bit of example code and a description of what you are trying to do ... I'll look for it and see if I can offer any more insight into your question. You might also want to look through the Mura developer docs.
Aug 4, 2010 at 9:47 AM Thanks for the quick response. However, i continued to look through the fw1PluginTemplate and notice that i could access the Mura PluginConfig within my custom app.
Digging a little deeper and i have come up with this #rc.pluginCongig.getConfigBean().getDatasource()# using this i can pass this into my service from the controller.
Not sure if thats the correct way to do it, but i can get to the datasource with that code snippet.
Aug 4, 2010 at 10:03 AM Ah, ok. You're trying to access the Mura datasource, not your plugin's datasource. The method you suggested is fine.
Aug 4, 2010 at 10:13 AM Ah sorry if i did not make that bit clear!!
Im running into another problem now, not sure if you can help. If i do not use the controller and try and get fw1 to get straight to the service cfc, the rc argument is not available in the function? Do i need to go controller->service, with the controller passing the dsn into the service?
Aug 4, 2010 at 2:22 PM That's correct. Services are a special animal in FW/1, and you won't be able to access rc objects like you would in the controller.
I don't use services in FW/1 (I use a bean factory, and the two aren't supposed to be used together), so you'll have to read the documentation to see what's possible.
Aug 4, 2010 at 5:25 PM I read another of your posts regarding the use of a bean factory with plugin development.
I managed to amend the application.cfc that comes with the fw1 template so that the bean factory loads in the coldspring.xml. From there I could autowire a service that extended a base cfc with the plugin config property. From this property I gained access to the datasource for use within my service.
I found your blog posts and your tinyurl plugin a valuable source of information and helped greatly in my plugin.