Skip to content

Melody Cookbook: Adding new features via YAML

mikert edited this page Mar 15, 2011 · 1 revision

Melody themes normally don't use any Perl whatsoever which can at first glance appear to be a hard limit on what they can do. One of the interesting features that Melody's YAML-based configuration and callback systems provide is the ability for plugin developers to creature features which theme designers can access using no code. For example, Melody's fork of the LinkBox plugin supports the ability to create link lists using YAML. The YAML tree looks like this:

template_sets:
    blogger_templates:
        label: BloggerTemplates
        linklists:
            blogroll:
                label: Blogroll
                links:
                    google:
                        label: Google
                        url: http://www.google.com
                        description: Big search engine.
                        order: 1
                    slashdot:
                        label: Slashdot
                        url: http://slashdot.org
                        description: Old as the hills tech news site.
                        order: 3
                    melody:
                        label: Open Melody Software Group
                        url: http://openmelody.org
                        description: The OMSG website
                        order: 2

Our fork of LinkBox attaches a callback to blog_template_set_change. When that callback is executed, one of the plugins that is contact is LinkBox. LinkBox gets passed some information about the blog, which allows it to look up the configuration information for the theme. This is done through a simple registry call:

sub ts_change {
    my ($cb, $param) = @_;
    my $blog = $param->{blog} or return;
    my $ts = $blog->template_set;
    return undef unless $ts;

    my $plugin = MT->component('LinkBox');
    my $reg = MT->registry('template_sets')->{$ts}->{linklists};

The theme used in the sample registers the obligatory template_sets top-level YAML identifier and directly underneath it registers its own YAML identifier (blogger_templates, name yours whatever you want). The linklists identifier is where LinkBox really starts looking. It drills down through that portion of the plugin's registry looking for link lists to create and then links to add to each list in the YAML file.

Now any theme designer who wants to create a blogroll widget need only do three things:

  1. Define a blogroll using the YAML sample provided here.
  2. Create a widget that uses the LinkBox template tags to render the blogroll.
  3. Tell their users to install LinkBox along with the theme if they don't have it already.

Full Callback Function

The following is the full callback function. It's reproduced below to serve as an extended reference for plugin developers looking for a full, code-based description of this approach.

## This is a callback handler for blog_template_set_change
## It looks for a predefined link list and makes it available
## when the template set has changed.
sub ts_change {
    my ($cb, $param) = @_;
    my $blog = $param->{blog} or return;
    my $ts = $blog->template_set;
    return undef unless $ts;

    my $plugin = MT->component('LinkBox');
    my $reg = MT->registry('template_sets')->{$ts}->{linklists};
    foreach (keys %$reg) {
        next if $_ eq 'plugin';
            unless ($reg->{$_}->{label}) {
                MT->log({
                    blog_id => $blog->id,
                    level => MT->model('log')->INFO(),
                    message => $plugin->translate('Link list with key [_1] missing label attribute. The config.yaml file for [_2] needs to be corrected.', $_, $ts)
                });
                next;
            }
        my $list = MT->model('linkbox_list')->load( { name => $reg->{$_}->{label}(), blog_id => $blog->id });
        if (!$list) {
            $list = MT->model('linkbox_list')->new();
            $list->name( $reg->{$_}->{label}() );
            $list->blog_id( $blog->id );
            $list->save() or die $list->errstr;

            my $links = $reg->{$_}->{links};
            if ($links) {
                foreach my $key (keys %$links) {
                    next if $key eq 'plugin';
                    my $link = $links->{$key};
                    unless ( $link->{url} ) {
                        MT->log({
                            blog_id => $blog->id,
                            level => MT->model('log')->INFO(),
                            message => $plugin->translate('A link with the key [_1] from link set [_2] was missing its url attribute. The config.yaml file for [_3] needs to be corrected.', $key, $list->name, $ts)
                        });
                        next;
                    }
                    unless ( $link->{label} ) {
                        MT->log({
                            blog_id => $blog->id,
                            level => MT->model('log')->INFO(),
                            message => $plugin->translate('A link with the key [_1] from link set [_2] was missing its label attribute. The config.yaml file for [_3] needs to be corrected.', $key, $list->name, $ts)
                        });
                        next;
                    }
                    my $l = MT->model('linkbox_link')->new();
                    $l->linkbox_list_id( $list->id );
                    $l->name( $link->{label}() );
                    $l->description( $link->{description} );
                    $l->link( $link->{url} );
                    $l->order( $link->{order} || 0 );
                    $l->save();
                }
            }
        }
    }
}
Clone this wiki locally