Working on an addition to the Movable Type developer guide which I wanted to post here first for feedback:
Plugin Settings
Often plugins need a way to allow their users to customize and configure their behavior in some way. For example, an Amazon plugin may want collect your Amazon Associates ID to embed within a link it generates. Or perhaps a theme or template set wants to make it easy for users to change the color scheme, or header image. Regardless of what options you need to surface to your users, Movable Type offers a relatively simple system for doing so.
This system works by editing your plugin's config.yaml and registering a set of plugin settings, and the templates that will be used for rendering the user interface and form for editing those settings.
The following guide will take you through this process, and then show you some alternatives that make this process even easier.
Registering Plugin Settings
Step one is registering each of the individual settings you will need to make available to your users. In this first step we are not defining the UI for these settings, just that the settings exist, their default values, their scope and what names will be used for storing and retrieving the values they hold.
Here is a small excerpt from a plugin that defines a single setting with a look up key of my_setting:
Sample config.yaml
name: Example Plugin for Movable Type
id: Example
description: This plugin is an example plugin for Movable Type.
settings:
my_setting:
default: "Byrne"
scope: blog
Registry Properties
default - the default value for this plugin setting when no value has been explicitly provided by the user.
scope - the scope for which this setting applies. A value of "system" will indicate to Movable Type to store only one value for this setting across the entire installation, whereas a value of "blog" will instruct Movable Type to store a value for this setting for each blog in the system.
Registering a Plugin Settings Template
Once you have declared what settings will be collected, the next thing you need to do is create the UI for editing them. First you will need to register the config template that will be used for the system level or blog level (or both) settings interfaces. There are two registry properties you can use:
system_config_templateblog_config_template
Each of these properties takes a single value as input, the name of the template file used to render your settings. The template file you will create will need to be placed in your plugins tmpl directory.
Here is a sample config.yaml that shows these registry properties in action:
name: Example Plugin for Movable Type
id: Example
description: This plugin is an example plugin for Movable Type.
system\_config\_template: system_config.tmpl
blog_config_template: blog_config.tmpl
settings:
my\_setting:
default: "Byrne"
scope: blog
Implementing a Settings Template
With your settings template or templates registered, time to actually implement one. Let's begin by creating a template called blog_config.tmpl and placing it in your plugins tmpl directory.
The first template we will create will expose a single text field with the label "My Setting." Here is the template code you would use:
<mtapp:setting
id="my_setting"
label="My Setting"
hint="Enter any value you want here."
show_hint="1">
<input type="text" name="my_setting" id="my_setting"
value="<mt:var name="my_setting">" />
</mtapp:setting>
A couple things to note:
The template above only defines the input elements themselves, the
<form>tag that wraps your input element will be generated for you automatically by Movable Type.Movable Type automatically populates your template with variables that hold the current value of each of your plugin configuration settings. You can use any normal Movable Type template to access these values.
Finally, the single most important detail in making all of this work is utilizing a name for your form elements that are synchronized with the setting you defined for them in your config.yaml. Let's look at one more example. First your config.yaml:
settings:
my\_favorite\_color:
default: "Blue"
scope: blog
And now the form element that will allow a user to provide a value for this setting:
<mtapp:setting
id="my_setting"
label="My Setting"
hint="Enter any value you want here."
show_hint="1">
<select name="my\_favorite\_color">
<option>Red</option>
<option>Yellow</option>
<option>Green</option>
<option>Blue</option>
</select>
</mtapp:setting>
You can include as many form elements that you want. To help you with the styling of these form elements, Movable Type provides the helper `Fetching Plugin Data
By now you should have successfully created a plugin that exposes a simple user interface that makes it possible for you to collect from your users configuration data for your plugin and for that information to be faithfully stored by Movable Type. The following section will instruct you on how to access that information once it has been stored. **Fetching a System-Level Setting** If you need to retrieve the value stored for a setting that is consider a system wide setting, then the following code should do the trick:my $plugin = MT->component("MyPlugin");
my $my_setting = $plugin->get_config_hash('my_setting','system');
Fetching a Blog-Level Setting
Retrieving a blog-specific setting is very similar, and requires only one additional piece of information: the ID of the blog for which this setting applies:
my $plugin = MT->component("MyPlugin");
my $scope = "blog:" . $blog_id;
my $my_setting = $plugin->get_config_value('my_setting',$scope);
And finally, you can fetch all of the values associated with your plugin's preferences at once by using the get_config_hash method like so:
my $plugin = MT->component("MyPlugin");
my $scope = "blog:" . $blog_id;
my $config = $plugin->get_config_hash($scope);
my $my_setting = $config->{'my_setting'};
Using Configuration Assistant
Even with Movable Type's capable API for letting developers define their own custom user interfaces for collecting plugin preferences from their user's, there exists a far easier method by way of a plugin prototype called "Config Assistant." Config Assistant is useful because it reduces all of the work associated with collecting and accessing plugin configuration data to editing a config file.
To illustrate let's take a second look at the example explained in gory detail previously that surfaced a single text field called "My Setting." To accomplish that task you needed to:
- Register the setting in your
config.yaml. - Register a template for rendering your settings form.
- Create a template to display your setting form elements.
That entire process can be reduced to the following config.yaml file:
name: Example Plugin for Movable Type
id: Example
description: This plugin is an example plugin for Movable Type.
settings:
my_setting:
default: Byrne
scope: blog
blog_config_template: '<mt:PluginConfigForm id="Example">'
plugin_config:
Example:
fieldset_1:
my_setting:
type: text
label: "My Setting"
hint: "Enter anything here."
tag: 'MySetting'
After all that, this is what Config Assistant will output for your plugin's settings UI:
Config Assistant Registry Settings
Config Assistant is driven 100% by configuration data you place in your plugin's config.yaml. In addition to defining a new data structure for use within your config.yaml, Config Assistant makes use of the following registry keys as well:
settings- you still need to register the values that will be stored in the database.blog_config_templateandsystem_config_template- you also need to provide templates to properly display the form defined by theplugin_configregistry data structure.
The new registry data structure parsed exclusively by Config Assistant is associated with the registry key plugin_config. This element has a single child element, corresponding to the plugin's id for which you are defining configuration options. It is this element which will contain each of your plugin's configuration options and input elements, grouped by fieldset. Let's look at an example that stubs out one possible plugin_config data structure:
plugin_config:
MyPluginID:
ServerInfo:
server_host: *snip*
server_port: *snip*
PluginOptions:
use_https: *snip*
http_auth_username: *snip*
http_auth_password: *snip*
The sample above defines two field sets:
- ServerInfo
- PluginOptions
Each of these field sets will be encapsulated by the HTML element from which they get their name:
<fieldset id="ServerInfo">
<!-- form elements go here -->
</fieldset>
<fieldset id="PluginOptions">
<!-- form elements go here -->
</fieldset>
Field sets like this provide the benefit of visually grouping related configuration options together. They have no bearing on the functionality of your plugin.
Within each of these field sets, Config Assistant will render their associated form input elements, or "fields."
Each field then supports the following registry properties:
type - the type of the field. Supported values are: text, textarea, select, checkbox.
label - the label to display to the left of the input element
hint - the hint text to display below the input element
tag - the template tag that will access the value held by the corresponding input element
values - valid only for fields of type "select" - this contains a comma delimitted list of values to present in the pull down menu
rows - valid only for fields of type "textarea" - this corresponds to the number of rows of text displayed for the text area input element
Finally, in order for Config Assistant to properly surface the form under your plugin's settings area, you will need to define a blog configuration template using the blog_config_template registry property like so:
blog_config_template: '<mt:PluginConfigForm id="MyPluginID">'
Auto-Generated Template Tags
Each plugin configuration field can define a template tag by which a designer or developer can access its value. If a tag name terminates in a question mark then the system will interpret the tag as a block element. Here are two example configs:
feedburner_id:
type: text
label: "Feedburner ID"
hint: "This is the name of your Feedburner feed."
tag: 'FeedburnerID'
use_feedburner:
type: checkbox
label: "Use Feedburner?"
tag: 'IfFeedburner?'
And here are corresponding template tags that make use of these configuration options:
<mt:IfFeedburner>
My feedburner id is <mt:FeedburnerID>.
<mt:Else>
Feedburner is disabled!
</mt:IfFeedburner>

Looking good.
I've just been having a go at this for a custom tag, and it is a great-looking procedure.
It isn't clear, however, how you get the configuration settings from the context parameter in a tag subroutine. Could you add something for that?
I've got my tag plugin up and running following this recipe: http://www.movabletype.org/documentation/developer/template-tag-handler.html. It gets its config from 'config_settings' in the config.yaml.
Your procedure configures settings in 'settings' rather than 'config_settings'. It isn't obvious - without deeper knowledge - what to change to get both to work.
Is there a way to reference 'settings' from the ctx parameter passed to the tag subroutine, or does it need to work with...
my $plugin = MT->component("MyPlugin");
# etc.
...instead?
Try $ctx->stash('blog_id') where $ctx is a MT::Template::Context object in your tag code to get the current blog id number.
Beware, there's a typo in this:
my $my_setting = $plugin->get_config_hash('my_setting','system');
Should be: get_config_value. [Use get_config_hash to get the hash.]
For what it's worth, I've got my tag working thus:
sub tag { my ($ctx, $args) = @_; #my $cfg = $ctx->{config}; my $plugin = MT->component("MyPlugin"); my $cfg = $plugin->get_config_hash('system'); my $system_setting = $cfg->{'my_system_setting'}; my $scope = "blog:" . $ctx->stash('blog_id'); $cfg = $plugin->get_config_hash($scope); my $blog_setting = $cfg->{'my_blog_setting'}; return ''; }It does however look a lot more bloated than simply using $ctx->{config}.
I promise I'll stop bombarding you with comments now! :-)
As asked elsewhere, how do I access config variables in tmpl files for the plugin?
Using tags breaks the page and using mt:var just outputs blank.