Skip to content

English plugin dev 3 1

semuel edited this page Jul 10, 2012 · 9 revisions

Plugin Configuration

Sometimes plugins need additional information to act. Here is how to make a configuration panel in the Setting→Plugin screen

Why a plugin needs configuration?

Some plugins need basic data to function. This include API keys and secrets, or account ids on web services.

Others use this information to tweaking their behavior, or on which item to act on.

i.e. MultiBlog plugin setting screen

Today’s plugin will:

Will have a configuration screen

We will use MyPlugin03 as the basis of this chapter, and create a configurable tag <MTHellowWorld2>.
We will actually make two configuration screen, one system-wide, and the other blog-wide.

For configuring the plugin, you should be able to go to Settings→Plugins, (either in the System overview mode or inside a blog) click on the plugin, (conveniently named “Sample Plugin 1.00”) and then choose Settings.
In that panel, you will see a single text box, with the writing below it “Please input the word, ‘Hello, xxx!’”
Enter some word, and click “Save”.

Expected (very expected) screen:

Our function Tag (<MTHelloWorld2>)

This tag will output “Hello xx!”, depending on the settings.

  • Should have ability to set the name system-level
  • Should have ability to set the name blog-level
  • If neither blog-level nor system-level is set, use the default: “World”.
  • When rendering the tag, the function should use:
    • Blog level settings, if set
    • Otherwise, system level settings, is set
    • Otherwise, the default, “World”

Plugin Development

config.yaml

id: MyPlugin08
key: MyPlugin08
name: <__trans phrase="Sample Plugin plugin config">
version: 1.0
description: <__trans phrase="_PLUGIN_DESCRIPTION">
author_name: <__trans phrase="_PLUGIN_AUTHOR">
author_link: http://www.example.com/about/
doc_link: http://www.example.com/docs/
l10n_class: MyPlugin08::L10N

blog_config_template: word_setting_blog.tmpl
system_config_template: word_setting_system.tmpl
settings:
    word_setting_blog:
        default:
        scope: blog
    word_setting_system:
        default:
        scope: system

tags:
    function:
        HelloWorld2: $MyPlugin08::MyPlugin08::Tags::_hdlr_hello_world_2
  • “blog_config_template” and “system_config_template” entries are notifying MT that this plugin have blog-level and system-level configuration screens.
  • The “Settings” entry tells MT which values this plugin needs. Here we define two type of settings: one system-level, and one blog-level so every blog can have its own settings. both of them have a blank default

word_setting_blog.tmpl

The settings panel template, to be used in the blog-wide plugin configuration. This file should be located in “MyPlugin08/tmpl/word_setting_blog.tmpl”, and is used to set “word_setting_blog”.

<mtapp:setting id="word_setting_blog" label="<__trans phrase='_MyPlugin08_Word'>"
    hint="<__trans phrase="Please input the word, 'Hello, xxx!'">" show_hint=1>
    <input type="text" name="word_setting_blog" id="word_setting_blog"
        value="<mt:Var name="word_setting_blog">" />
</mtapp:setting>

The template will output the following HTML code in the plugin configuration screen.
(of course, we tidied it a bit)

<!-- Plugin Config -->

<div id="plugin17-config" class="config">
    <form method="post" action="/cgi-bin/mt/mt.cgi" id="plugin-17-form">
        <input type="hidden" name="__mode" value="save_plugin_config" />
        <input type="hidden" name="blog_id" value="2" />
        <input type="hidden" name="return_args" value="__mode=cfg_plugins&amp;_type=blog&amp;blog_id=2&amp;id=2" />
        <input type="hidden" name="plugin_sig" value="MyPlugin08" />
        <input type="hidden" name="magic_token" value="(cut)" />

        <fieldset>
            <div id="word_setting_blog-field" class="field field-left-label ">
                <div class="field-header">
                     <label id="word_setting_blog-label" for="word_setting_blog">Word</label>
                </div>
                <div class="field-content ">
                    <input type="text" name="word_setting_blog" id="word_setting_blog" value="" />
                    <div class="hint">Please input the word, 'Hello, xxx!'</div>
                </div>
            </div>
        </fieldset>

        <div class="actions-bar settings-actions-bar last-child">
            <button mt:mode="save_plugin_config" type="submit"
                class="save action primary-button first-child last-child">Save Changes</button>
        </div>
    </form>
</div>

word_setting_system.tmpl

The settings panel template, to be used in the system-wide plugin configuration. This file should be located in “MyPlugin08/tmpl/word_setting_blog.tmpl”, and is used to set “word_setting_system”.

<mtapp:setting id="word_setting_system" label="<__trans phrase='_MyPlugin08_Word'>"
    hint="<__trans phrase="Please input the word, 'Hello, xxx!'">" show_hint=1>
    <input type="text" name="word_setting_system" id="word_setting_system"
        value="<mt:Var name="word_setting_system">" />
</mtapp:setting>

The template will output the following HTML code in the plugin configuration screen.
(of course, we tidied it a bit)

<!-- Plugin Config -->

<div id="plugin17-config" class="config ui-tabs-panel ui-widget-content ui-corner-bottom last-child">
    <form class="first-child last-child" method="post" action="/cgi-bin/mt/mt.cgi" id="plugin-17-form">
        <input class="first-child hidden" name="__mode" value="save_plugin_config" type="hidden">
        <input class="hidden" name="return_args" value="__mode=cfg_plugins&amp;_type=blog&amp;blog_id=0&amp;id=2">
        <input class="hidden" name="plugin_sig" value="MyPlugin08" type="hidden">
        <input class="hidden" name="magic_token" value="(cut)" type="hidden">

    <fieldset>
        <div id="word_setting_system-field" class="field field-left-label  first-child last-child">
            <div class="field-header first-child">
                <label class="first-child last-child" id="word_setting_system-label" for="word_setting_system">Word</label>
            </div>
            <div class="field-content  last-child">
                <input class="first-child text" name="word_setting_system" id="word_setting_system" value="" type="text">
                <div class="hint last-child">Please input the word, 'Hello, xxx!'</div>
            </div>
        </div>
    </fieldset>

    <div class="actions-bar settings-actions-bar last-child">
        <button mt:mode="save_plugin_config" type="submit"
            class="save action primary-button first-child last-child">Save Changes</button>
    </div>
</form>
</div>

Now your configuration screens are functional and ready

Plugin Development (<MTHelloWorld2>, Perl)

This Tags.pm is very similar to MyPlugin03, so we will explain only the difference

package MyPlugin08::Tags;
use strict;

sub _hdlr_hello_world_2 {
    my ($ctx, $args) = @_;
    my $blog_id = 'blog:' . $ctx->stash('blog_id');
    my $plugin = MT->component('MyPlugin08');

    my $word_blog = $plugin->get_config_value('word_setting_blog', $blog_id);
    my $word_sys = $plugin->get_config_value('word_setting_system', 'system');

    my $word_default = MT->translate('world');

    my $word = $word_blog ? $word_blog :
                 ( $word_sys ? $word_sys : $word_default );

    return MT->translate( 'Hello, [_1]!', $word );
}

1;
  • We take out of the stash the blog_id, as we need to get blog-level configuration. from it, we built a scope string for the blog, i.e. "blog:12"
  • For getting plugin configuration, we need plugin object. This is by calling MT->component('MyPlugin08')
  • Then we retrieve the configuration, using the plugin’s get_config_value function, that receive the config key, (word_setting_blog and word_setting_system in our case) and the scope-string of this config.
  • Setting $word_default to be used as default, is the translation of the word “world”
    • In templates, we use the <__trans> tag, but in Perl code we use the MT->translate() command
  • Using the ternary operator, we check the blog settings, system settings and default in the correct order
  • Outputting “Hello $word!”

Plugin Development (<MTHelloWorld2>, PHP)

The PHP version have a very similar structure as the Perl version, but uglier because it is PHP, and sometimes needs intermediate steps.

function.mthelloworld2.php

<?php
    function smarty_function_mthelloworld2($args, &$ctx) {
        $mt = MT::get_instance();
        $blog_id = 'blog:' . $ctx->stash('blog_id');

        $cfg = $mt->db()->fetch_plugin_data('MyPlugin08', 'configuration:' . $blog_id);
        $word_blog = $cfg['word_setting_blog'];

        $cfg = $mt->db()->fetch_plugin_data('MyPlugin08', 'configuration');
        $word_sys = $cfg['word_setting_system'];

        $word_default = $mt->translate('world');

        $word = $word_blog ? $word_blog :
                  ( $word_sys ? $word_sys : $word_default );

        return $mt->translate( 'Hello, [_1]!', $word );
    }
?>
  • Getting MT instance by calling MT::get_instance()
  • Taking the blog_id from the stash, and building blog scope string
  • We use $mt->db()->fetch_plugin_data to fetch the whole configuration data for this plugin and for this scope, twice. (once for every scope, blog-level and system level)
    • the we extract the variable that is of interest to us from the fetched configuration data
  • Setting $word_default to the translated “word”
    • In templates we use the <__trans> tag to translate strings, and in PHP we use the $mt->translate() command
  • Using the ternary operator, we check the blog settings, system settings and default in the correct order
  • Outputting “Hello $word!”

init.MyPlugin08.php

The PHP system have a L10N system similar to the Perl side, we just need to init it first. the “init..php” files are loaded on PHP startup, and can be used to abuse the system. and load our L10N files.

<?php
$lang = substr(strtolower($this->config('DefaultLanguage')), 0, 2);
if (!@include_once("lib/l10n_$lang.php")) {
    include_once("lib/l10n_en.php");
}
?>

The language file to be loaded is set using the first two characters from the DefaultLanguage configuration. If no such file exists, we simply load the English version “l10n_en.php”

これらのコードはプラグインのハンドラ関数に直接書けばよいのですが、複雑なプラグインで関数が増えてくると毎回書かなくてはならないので、初期化時に読み込むようにします。

l10n_en.php

This PHP plugin does not require English lexicon. so $Lexicon_en is empty

<?php
global $Lexicon_en;
$Lexicon_en = array(
);
?>

l10n_ja.php

The Japanese lexicon, stored in $Lexicon_ja

<?php
global $Lexicon_ja;
$Lexicon_ja = array(
    'world' => '世界',
    'Hello, [_1]!' => 'こんにちは、[_1]!',
);
?>

Directory Structure

$MT_DIR/
|__ plugins/
   |__ MyPlugin08/
      |__ config.yaml
      |__ lib/
      |  |_ MyPlugin08/
      |     |__ L10N.pm
      |     |_ L10N/
      |     |  |_ en_us.pm
      |     |  |_ ja.pm
      |     |_ Tags.pm
      |__ php/
      |  |_function.mthelloworld2.php
      |  |_init.MyPlugin08.php
      |  |_lib/
      |        |_ l10n_en.php
      |        |_ l10n_ja.php
      |__ t/
      |  |_00-compile.t
      |  |_01-tags.t
      |__ tmpl/
         |_word_setting_blog.tmpl
         |_word_setting_system.tmpl

Test driving <MTHelloWorld2>

Add tags to a template in your blog:

Add the tag immediately below the “alpha-inner” div element

                    <div id="alpha">
                        <div id="alpha-inner">
                        <p><mt:HelloWorld2></p>

Checking various configuration combinations

Settings combination map:

System Settings Blog Settings Output
Hello, world!
system Hello, system!
blog Hello, blog!
system blog Hello, blog!

Notice that blog settings are overriding the system-level settings. Of course, it is also possible to make the plugin prefer the system-level settings, but this is very rare and special notice in this case is in order.

Developing Dynamic Setting tab

The method that was presented above is pretty simple: Plain template, with MT populates the values and saving changes.
But what if you need to dynamically change it? populate dynamic values?

We don’t have to use a plain file for the setting – we can have a callback. in the config.yaml put:

blog_config_template: 
    code: $Plugin::module::handler

And that callback will be called with the following parameters:

my ($plugin, $params, $scope) = @_;

The return value of the function will be used as a template for the settings tab, and the $params hashref will be used as variables for the template. You can either return the template text, or a MT::Template object.

For loading a template from the plugin tmpl directory, use: return $plugin->load_tmpl("filename.tmpl");

After the settings are saved, the following callback is called: (starting MT 5.12)

callbacks:
    save_config_filter.PluginID: $Plugin::Module::handler

With parameters:

    my ( $cb, $plugin, $data ) = @_;

This is a filter callback – meaning that you need to either return 1 to accept the settings, or $plugin->error('...') to reject them.

Summery

Of course, it is possible to config your plugin using environment variable, and bypass the whole configurtion screen stuff. However, once you have users and each have his own special configuration, using configuration screens is better.

Also, it will make life easier to you, and it is just a few minutes of work to setup these screens. so you really should be a masochist not to use them. Or a BOFH. or something.

Plugin Download

MyPlugin08.zip(8.11KB)

Navigation

Prev:Plugin Debugging << Index >> Next:Callbacks and Hooks

Clone this wiki locally