-
Notifications
You must be signed in to change notification settings - Fork 36
DevGuide TemplateTags
Welcome to a complete reference on one of the most common ways in which developers seek to customize and extend Melody: the creation of new template tags. If you are still unfamiliar with the basics of creating a Melody plugin, we suggest you start there, and then come back here to learn more.
Before we dive into creating our own tags, let's make sure we understand the basics of what a tag is.
A template is a file that is processed by Melody to produce a text file suitable for web publishing, such an HTML file (which is most common), a PHP file, a JavaScript file, a CSS file, etc.
Designers utilize template tags within a template to easily parameterize the output of the template itself.
In many respects, Melody's templating language, the collection of all of Melody's template tags, is a programming language unto itself. It is as functional as PHP and JavaScript, but has more in common with HTML as it utilizes a more semantic, tag or markup oriented approach to templating.
Let's compare Melody's templating language side-by-side with PHP:
PHP
<html>
<head>
<title><?php echo $BLOG_NAME; ?></title>
</head>
<body>...</body>
</html>
Melody Template Tag Syntax
<html>
<head>
<title><mt:BlogName></title>
</head>
<body>...</body>
</html>
As you can see they are virtually identical. We will leave the debate of language aesthetics to the uber-geeky.
Now that we grok what a template tag is, let's get on our way to creating our own. First, Melody supports two different types of tags. They are:
- function
- block
Function tags are atomic and simply output text in place of the tag itself.
Examples
-
<mt:BlogURL>
- display the blog's URL -
<mt:EntryTitle>
- display an entry's title -
<mt:EntryPermalink>
- display the full URL to an entry's permalink -
<mt:Link id="javascript">
- display the URL to the template with the id of "javascript"
Block tags can contain other tags or text. They enclose text by an opening and closing tag like so:
<mt:Entries lastn="5">
Your HTML here.
</mt:Entries>
Examples
-
<mt:Entries>
- loop over a set of entries -
<mt:Comments>
- loop over a set of comments -
<mt:IfRegistrationEnabled>
- conditionally display the contents of the tag if registration is enabled on this blog
All template tags are first declared in the plugin's config.yaml
file. In the following example we are going to define four different template tags to illustrate each of the following:
- How to declare a function tag
- How to declare a tag that loops
- How to declare a conditional tag that will show and hide content based upon a variable
- How to enable template tags to take arguments or input
Here are the tags we will define in this example:
-
<mt:SaySomething>
- will output the word "Something" -
<mt:LoopTenTimes></mt:LoopTenTimes>
- will output the contents contained by the tag 10 times -
<mt:SayWhatever>
- will output the word you input -
<mt:IfOdd></mt:IfOdd>
- will output the contents contained by the tag only if the iteration through the loop is odd
First up: your config.yaml
file. The following sample shows how to register each of the four tags this example will illustrate:
name: Example Plugin for Melody
id: Example
description: This plugin is an example plugin for Melody.
version: 1.0
tags:
function:
SaySomething: $Example::Example::Plugin::SaySomething
SayWhatever: $Example::Example::Plugin::SayWhatever
block:
LoopTenTimes: $Example::Example::Plugin::LoopTenTimes
IfOdd?: $Example::Example::Plugin::IfOdd
Conditional tags are a special kind of block tag. They work by enclosing content by an opening and closing tag, like any other block tag. However their handler (their perl code) is much simpler. A conditional tag handler need only return true or false. If the handler returns true, then the contents of the tag will be displayed. If the handler returns false then the contents of the tag will be ignored.
Conditional tags are differentiated from a normal block tag by appending a question mark '?' to the tag's name. When you do this, be sure to encapsulate the template tag in apostrophe's or Perl might complain about a YAML syntax error.
Once the tags have been declared in your config.yaml
it is time to write the code that will govern their behavior.
-
Create a plugin module called
Plugin.pm
in the following directory:/path/to/mt/plugins/Example/lib/Example/
-
Edit
Plugin.pm
and cut and paste the following into it using a text editor (don't worry, we will deconstruct how all of this works soon enough):package Example::Plugin; use strict; sub SaySomething { my ($ctx, $args) = @_; return "Something"; } sub SayWhatever { my ($ctx, $args) = @_; # What the person passed in through the argument 'say' my $input = $args->{'say'}; return $input; } sub LoopTenTimes { my ($ctx, $args, $cond) = @_; my $out = ""; for (my $i = 1; $i <= 10; $i++) { $ctx->stash("current_loop_number",$i); defined(my $txt = $ctx->slurp($args,$cond)) or return; $out .= "$i - $txt"; } return $out; } sub IfOdd { my ($ctx, $args, $cond) = @_; my $num = $ctx->stash('current_loop_number'); if ($num % 2 == 0) { return 0; } else { return 1; } } 1; # Every module must return true
Once this plugin has been created, the following template code can be used:
<mt:LoopTenTimes>
<mt:IfOdd>
<mt:SaySomething>
<mt:Else>
<mt:SayWhatever say="I am even!">
</mt:IfOdd>
</mt:LoopTenTimes>
When processed through Melody, the above template code will output the following text:
1 - Something
2 - I am even!
3 - Something
4 - I am even!
5 - Something
6 - I am even!
7 - Something
8 - I am even!
9 - Something
10 - I am even!
Ok. We blazed through that, and we didn't even explain the perl code at all. In the next section we will deconstruct what some of those tag handlers were doing in an effort to shed some light on Melody's inner workings.
When a template is being published, a "context" is maintained while the page is processed and subsequently published. Template tags can store variables and information in the context to be used by other tags. This is the best way to maintain state during the process of publishing a page.
To store or retrieve a variable, use the "stash" method.
Storing values in the stash
sub handler {
my ($ctx, $args, $cond) = @_;
$ctx->stash("some stash key", "some value");
}
Retrieving values from the stash
sub handler {
my ($ctx, $args, $cond) = @_;
my $value = $ctx->stash("some stash key");
# do something
}
How does this relate to our previous example. Let's take a look:
1 sub LoopTenTimes {
2 my ($ctx, $args, $cond) = @_;
3 my $out = "";
4 for (my $i = 1; $i <= 10; $i++) {
5 $ctx->stash("current_loop_number",$i);
6 defined(my $txt = $ctx->slurp($args,$cond)) or return;
7 $out .= "$i - $txt";
8 }
9 return $out;
10 }
You should notice two things. The first might be a call to the enigmatic slurp()
method. The slurp
method performs the simple function of returning the results from evaluating the contents or template code contained by the block tag. In the code sample above, this method is used to prepend to the evaluated template code the loop count each time the loop is iterated over.
Secondly, you may notice that within the for loop we are placing an element onto the stash. The name of this item is current_loop_number
. Each time through the loop it is updated to store the number of times the loop has been processed up until that point in time.
Once it is stashed, we can reference it later and in another tag.
sub IfOdd {
my ($ctx, $args, $cond) = @_;
my $num = $ctx->stash('current_loop_number');
if ($num % 2 == 0) {
return 0;
} else {
return 1;
}
}
You will notice that the IfOdd
handler then retrieves this element off of the stash and if the number retrieved is an odd number the handler returns true, or 1, else it returns false or 0. In this way, the template context's stash is a way for developers to maintain the state of the template and template tag(s) being processed.
At any point in any of your template tag handlers you may encounter a condition under which the best course of action is to terminate the publishing process and return an error. In these situations one can utilize the template context to return an error, complete with an error message that will be displayed to the user. For example:
sub handler {
my ($ctx, $args, $cond) = @_;
# do something
if (<error condition>) {
return $ctx->error("Something went horribly wrong.");
}
return $html;
}
The behavior of template tags can be modified programatically through the use of template tag arguments. These arguments can be used to customize the output of a template tag according to the developer/designer's design. For example:
<MTEntries lastn="2" sort="created_on"></MTEntries>
In the example above, both "lastn" and "sort" are template tag arguments. Accessing the values passed to these template tags is done via the following code sample:
sub handler {
my ($ctx, $args, $cond) = @_;
my $lastn = $args->{lastn};
my $sort = $args->{sort};
# do something
}
Questions, comments, can't find something? Let us know at our community outpost on Get Satisfaction.
- Author: Byrne Reese
- Edited by: Violet Bliss Dietz