Jun 29, 2005

Dynamic Tag Archiving with Tagwire and MT-XSearch

Instead of static tag/category archives supported by Tags Plugin, Tagwire provides Dynamic Tag Archiving by using Tim Appnel's MT-XSearch. Dynamic Tag Archiving is slower than static one but preferable to support more flexible archiving. For example, Tagwire supports listing entries having two or more tags.

In this article, I will explain how Tagwire plugin cooperates with Tim Appnel's MT-XSearch and realize Dynamic Tag Archiving.

How to setup

Now assume that you've already installed Tagwire plugin.

  1. Install MT-XSearch:
    First, download mt-plus-1.01.zip from Download mt-plus | Appnel Internet Solutions. And unpack it and copy/upload the following files into your Movable Type directory.
    • mt-xsearch.cgi (this file should be executable)
    • plugins/mt-xsearch.pl
    • extlib/MT/XSearch.pm
  2. Modify mt-xsearch.cgi and plugins/mt-xsearch.pl a little. These are for multilingual support and bug fix, and they may be included in the future releases of MT-Plus/MT-XSearch.
    --- mt-xsearch.cgi.bak Fri Aug 27 12:06:24 2004
    +++ mt-xsearch.cgi Sat Jun 11 02:58:33 2005
    @@ -41,7 +41,8 @@
         $ctx->stash('CGI',$q);
         my $out = $tmpl->build($ctx)
             or die "Building search template failed: ".$tmpl->errstr;
    -    print $q->header.$out;
    +    my $charset = $mt->{cfg}->PublishCharset;
    +    print $q->header(-charset=>$charset).$out;
     };
     if ($@) {
         print "Content-Type: text/html\n\n";
    
    --- plugins/mt-xsearch.pl.bak Sat May 14 06:01:19 2005
    +++ plugins/mt-xsearch.pl Sat Jun 11 00:31:39 2005
    @@ -63,7 +63,7 @@
         my $pages = $limit ? ($count-($count % $limit)) / $limit : 1;
         $pages += ($limit && $count % $limit) ? 1 : 0;
         my $offset = $xsearch->args->{offset} || 0;
    -    my $current = $offset / $limit + 1;
    +    my $current = $limit ? ($offset / $limit + 1) : 1;
         $ctx->stash('MT::XSearch::current_page',$current);
         $ctx->stash('MT::XSearch::pages',$pages);
         my $builder = $ctx->stash('builder');
    
  3. Create a template module named "XSearch Tagwire" (other name is not permitted):
    <html>
    <body>
    <form method="get" action="<$MTCGIPath$>mt-xsearch.cgi">
    <input type="hidden" name="blog_id" value="<$MTBlogID$>" />
    <input type="hidden" name="search_key" value="Tagwire" />
    <label for="search" accesskey="4">Search this site:</label>
    <input id="search" name="search" size="20" value="<$MTSearchString decode_url="1" encode_html="1"$>" />
    <input type="submit" value="Search" />
    </form>
     
    <MTSearchResults>
    <MTSearchHeader>
    Results found: <$MTSearchResultCount$> 
    <ol>
    </MTSearchHeader>
    <li><a href="<$MTEntryLink$>"><$MTEntryTitle$></a></li>
    <MTSearchFooter>
    </ol>
    <p>Searched on: <em><$MTSearchString decode_url="1"$></em></p>
    </MTSearchFooter>
    </MTSearchResults>
    <MTNoSearch><p>No search performed.</p></MTNoSearch>
    <MTNoSearchResults><p>Nothing found.</p></MTNoSearchResults>
     
    </body>
    </html>
    
    This template can be customized as you like.

Usage

Tag Search Form:

To create tag search form, simply add the following code to your index/archive templates:

<form method="get" action="<$MTCGIPath$>mt-xsearch.cgi">
<input type="hidden" name="blog_id" value="<$MTBlogID$>" />
<input type="hidden" name="search_key" value="Tagwire" />
<label for="search" accesskey="4">Search this site:</label>
<input id="search" name="search" size="20" value="<$MTSearchString decode_url="1" encode_html="1"$>" />
<input type="submit" value="Search" />
</form>

Tag Archive Links:

To generate directly tag archive links instead of forms, you can write as like follows:

<MTEntryTags glue=", ">
<a href="<$MTCGIPath$>mt-xsearch.cgi?blog_id=<$MTBlogID$>&search_key=Tagwire&search=<$MTTag encode_url="1"$>"><$MTTag$></a>
</MTEntryTags>

Smarter Tag Archive Links:

To realize smarter representation of the tag archive URL such as "http://my.host.tld/tag/Tag", add the following to your .htaccess:

RewriteEngine on
RewriteRule ^tag/(.*) /mt/mt-xsearch.cgi?blog_id=1&search_key=Tagwire&search=$1 [QSA,L]

Once the above setting complete, you need only to write as follows:

<MTEntryTags glue=", ">
<a href="<$MTBlogURL$>tag/<$MTTag encode_url="1"$>"><$MTTag$></a>
</MTEntryTags>

Options

The following options can be added as hidden input fields of the Tag Search Form or as query strings of the Tag Archive Links:

blog_id (REQUIRED)
A blog ID.
search_key (REQUIRED)
Must be set to "Tagwire" for tag search.
search (REQUIRED)
An URL-encoded search string. You can specify one or more tags separated by the delimiter character. When you specify two or more tags, MT-XSearch generates the list of entries with all these tags. And the default delimiter is a whitespace, which should be represented as "%20" or "+" in a URL-encoded string. So if you specify "movable+type" as the search string and omit the delimiter option, MT-XSearch generates the list of entries having both of "movable" and "type" tags.
delimiter
Sets the delimiter character for the search string. For example, if you set "movable,type" as the search string and "," as the delimiter, MT-XSearch generates the list of entries having both of "movable" and "type" tags.
case_sensitive [0 | 1]
Chooses whether the plugin treats tags as the case-sensitive manner or not. The default is case_sensitive="1".
sort_order [ascend | descend]
Chooses the sorting order. The default sort_order is "descend".

Advanced Issue: CGI::Cache enabled MT-XSearch

The above mentioned method is not so a fast solution. Because, everytime you access tag archives, it invokes CGI process and retrieves the tag information from the DB engine and then generates the result page.

But, generally saying, the tag information is not so often added or modified. In short, by caching pages and suppressing page transfers, we make it possible to reduce the overhead of dynamic tag archives effectively.

Based on this observation, I introduce a speedup method for Tagwire/MT-XSearch, with enabling CGI::Cache module. CGI::Cache enabled MT-XSearch can cache the result pages for a fixed period (e.g, 1 hour) and return the pages to the clients with the Last-Modified HTTP Header (the cached time may be preferable).

To realize CGI::Cache enabled MT-XSearch, install CGI::Cache module from CPAN, and modify mt-xsearch.cgi as follows:

--- mt-xsearch.cgi.bak Fri Aug 27 12:06:24 2004
+++ mt-xsearch.cgi Sat Jun 11 03:44:32 2005
@@ -17,6 +17,7 @@
 }
 
 use CGI;
+use CGI::Cache;
 use MT;
 use MT::ConfigMgr;
 use MT::Template;
@@ -27,10 +28,13 @@
     my $mt = MT->new( Config => $MT_DIR . 'mt.cfg', Directory => $MT_DIR )
         or die MT->errstr;
     my $q = new CGI;
+    CGI::Cache::setup({ cache_options => { cache_root => './cache', default_expires_in => 3600 } });
     my $blog_id = $q->param('blog_id') or
         die "Missing parameter blog_id";
     my $key = $q->param('search_key') or
         die "Missing parameter key";
+    CGI::Cache::set_key($q->Vars);
+    CGI::Cache::start() or exit;
     my $search = MT::XSearch->execute($q);
     my $tmpl = MT::Template->load( { 
                         name=>'XSearch '.$key, 
@@ -41,7 +45,14 @@
     $ctx->stash('CGI',$q);
     my $out = $tmpl->build($ctx)
         or die "Building search template failed: ".$tmpl->errstr;
-    print $q->header.$out;
+    my $charset = $mt->{cfg}->PublishCharset;
+    my @m = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
+    my @w = qw(Sun Mon Tue Wed Thu Fri Sat);
+    my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime(time);
+    my $now = sprintf("%3s, %02d %3s %04d %02d:%02d:%02d GMT",
+        $w[$wday], $mday, $m[$mon], $year+1900, $hour, $min, $sec);
+    print $q->header(-charset=>$charset,-Last_Modified=>$now).$out;
+    CGI::Cache::stop();
 };
 if ($@) {
     print "Content-Type: text/html\n\n";

Underlines mean the cache directory and the cache lifetime by seconds. In the above example, the directory is "./cache" and the lifetime is 3600 secs(1 hour).

About Me

My Photo

つくばで働く研究者

Total Pageviews

Amazon

Copyright 2012 Ogawa::Buzz | Powered by Blogger
Design by Web2feel | Blogger Template by NewBloggerThemes.com