Writing Plugins for Vanilla 2

4 minute read

July 20, 2010

Writing Plugins for Vanilla 2

But first…

Before you get started, you’ll need to take note of an important change we’ve made to plugin files. Instead of starting your class files like this: class MyPlugin implements Gdn_IPlugin {, you’ll need to change that around and use something like this instead: class MyPlugin extends Gdn_Plugin {. This lets us add some methods to your plugin’s scope, as well as gain access to the name and location of your plugin. Once you’ve made that change, you’ll be ready to go.

Plugin Path Handling

One of the more annoying aspects of writing a plugin has been managing the various secondary asset files that go along with developing an application for the web. CSS, JavaScript, Views, Images… you need to know where each of these resources is located and then build paths to those files. Sometimes you’ll want a URL directly to your CSS file, other times you want to check if a certain file exists on the server, so a filesystem path is needed. Each of these tasks requires the use of different Vanilla constants and generates a lot of pointless boilerplate code.

When you extend Gdn_Plugin, you gain access to several new methods that help you to deal with your plugin’s files:

  • GetResource: GetResource($Filepath, $Include = FALSE, $Absolute = TRUE)This method takes a relative $Filepath (relative to the top of your plugin’s folder) and returns the path to that file relative to Document root. Optionally, you can have the method include() the file as well. Finally, by supplying FALSE as the third parameter, you can return a file path relative to Vanilla’s root instead of the Document root.

    For example: $Sender->AddJsFile($this->GetResource('js/quotes.js', FALSE, FALSE));

  • GetWebResource: GetWebResource($Filepath)This method also takes a relative $Filepath but instead of also returning a filesystem path, it creates a web-accessible URL that points to the specified file. This is great for Images, CSS and JS files that need to be included from your plugin.

    For example: <img src="<?php echo $this->GetWebResource('images/gear.png'); ?>"/>

  • GetView: GetView($ViewName)This method takes the filename of a view within your plugin’s views/ folder and converts it into a path relative to the Document root. This format is suitable for $Sender->Render(), making overriding controller views extremely easy and pain free.

    For example: $Sender->Render($this->GetView('toggle.php'));

These convenience methods are the first of quite a few that we are planning to add in the future. If you have sane ideas for other methods we could add, don’t hesitate to suggest them on the Community Forums.

UserMeta Storage

Plugins often need to store extra information about users. A good examples of this is the Signatures plugin, which needs to store a signature and some settings for each user. Traditionally a plugin like this would need to create its own table and use queries to access the information within it. Not anymore. Enter the GDN_UserMeta table.

We created this table to allow plugin developers to store discrete chunks of information about users without needing to go through the hoops of creating their own table and structure calls, and especially to avoid having to write SQL. Each plugin gets its own namespace within the table (Plugin..*) and they can store as many key/value pairs as they like, each tied to a UserID. UserID 0 can be used to store settings for the plugin in general. We’ve written some code to make it easy to read and write this information. Extending Gdn_Plugin gives you access to four new methods:

  • SetUserMeta: SetUserMeta($UserID, $Key, $Value = NULL)This method attempts to set $Key = $Value for $UserID. $Key can be (or just contain) an SQL wildcard (%), thereby allowing multiple variations of a $Key to be set. $UserID can be an array or UserIDs, thereby allowing multiple users’ $Keys to be set to the same $Value.

    Before any queries are run, $Key is converted to a Fully Qualified Meta Key (Plugin..) (hereafter ‘FQMK’) to prevent collisions in the meta table when multiple plugins have similar key names. This is important, because when values are retrieved from the table, they are indexed by their FQMK.

    If $Value == NULL, the matching row(s) are deleted instead of updated.

    For example: $this->SetUserMeta($SigUserID, 'Sig', 'This is my signature');This code sets the value of the ‘Plugin.Signatures.Sig’ key for $SigUserID to This is my signature in the the database.

  • GetUserMeta: GetUserMeta($UserID, $Key, $Default = NULL)This method takes a $UserID or array of $UserIDs, and a $Key. It converts the $Key to a FQMK and then queries for the associated value(s). $Key can contain SQL wildcards (%), in which case multiple results can be returned.

    If $UserID is an array, the return value will be a multi dimensional array with the first axis containing UserIDs and the second containing FQMKs, associated with their values.

    If $UserID is a scalar, the return value will be a single dimensional array of $FQMK => $Value pairs.

    For example: $UserSig = $this->GetUserMeta(Gdn::Session()->UserID, 'Sig');This code retrieves the Key+Value pair for ‘Plugin.Signatures.Sig’ from the database for the currently logged in user.

  • MakeMetaKey: MakeMetaKey($RelativeUserKey)This convenience method takes a simply string and prepends ‘Plugin.’ to the front of it. If the string is already a FQMK, the Plugin.PluginName part is stripped off first.

    For example: $FullyQualifiedKey = $this->MakeMetaKey('Sig'); // 'Plugin.Signatures.Sig'

  • TrimMetaKey: MakeMetaKey($FullyQualifiedUserKey)This convenience method trims the Plugin.PluginName part off the front of a FQMK, thereby converting it to a relative key. If the provided argument is not in the format of a FQMK, the string is return unchanged.

    For example: $RelativeKey = $this->TrimMetaKey('Plugin.Signatures.Sig'); // 'Sig'

UserMeta storage should help plugin authors to easily and reliably access custom user information without having to go through the minefield of creating and managing their own database table or writing queries.

And that’s the end of Part 1 of Writing Plugins for Vanilla 2. Hopefully this has helped you to understand a little more about plugin development in Vanilla! In Part 2 I will be talking about some of the other things we’ve been working on for plugin developers, such as Slices, which let plugin authors create small asynchronously refreshable portions of the page quickly and easily.


Share Your Thoughts

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

Tim Gunter

Written by Tim Gunter

Have an Article for Vanilla's Blog?

Send us an email to [email protected] with your topic idea and we'll circle back with our publishing guidelines.

Subscribe to the Community Corner Newsletter and get expert insight and analysis on how to get the most out of your online community every Friday.
[contact-form-7 id="5700" title="Newsletter Form"]

Request a Demo

Schedule a product demo now.

Contact Us