Index: branches/release-35/lib/MT/Blog.pm
===================================================================
--- branches/release-35/lib/MT/Blog.pm (revision 1945)
+++ branches/release-35/lib/MT/Blog.pm (revision 1949)
@@ -379,28 +379,36 @@
 sub include_path_parts {
     my $blog = shift;
-    my ($name) = @_;
-
-    my $filestem = MT::Util::dirify($name);
+    my ($param) = @_;
+
+    my $filestem = MT::Util::dirify($param->{name}) || 'template_'.$param->{id};
     my $filename = join q{.}, $filestem, $blog->file_extension;
-    return (MT->config('IncludesDir'), substr($filestem, 0, 3), $filename);
+    my $path = $param->{path} || '';
+    my @path;
+    if ($path =~ m!^/!) {
+        # absolute
+        @path = split /\//, $path;
+    } else {
+        # relative
+        push @path, MT->config('IncludesDir');
+        push @path, split /\//, $path;
+    }
+    return ($filename, @path);
 }
 
 sub include_path {
     my $blog = shift;
-    my ($name) = @_;
-
-    my @parts = $blog->include_path_parts($name);
-    my $filename = pop @parts;
-    my $path = File::Spec->catdir($blog->site_path, @parts);
-    my $file_path = File::Spec->catfile($path, $filename);
-    return wantarray ? ($path, $file_path) : $file_path;
+
+    my ($filename, @path) = $blog->include_path_parts(@_);
+    my $extra_path = File::Spec->catdir(@path);
+    my $full_path = File::Spec->catdir($blog->site_path, $extra_path);
+    my $file_path = File::Spec->catfile($full_path, $filename);
+    return wantarray ? ($file_path, $full_path, $filename) : $file_path;
 }
 
 sub include_url {
     my $blog = shift;
-    my ($name) = @_;
-
-    my @parts = $blog->include_path_parts();
-    my $url = join q{/}, $blog->site_url, @parts;
+
+    my ($filename, @path) = $blog->include_path_parts(@_);
+    my $url = join q{/}, $blog->site_url, @path, $filename;
     return $url;
 }
@@ -408,5 +416,4 @@
 sub include_statement {
     my $blog = shift;
-    my ($name) = @_;
 
     my $system = $blog->include_system or return;
@@ -416,11 +423,12 @@
         $statement = q{<!--#include virtual="%s" -->};
 
+        my ($filename, @path) = $blog->include_path_parts(@_);
         my $site_url = $blog->site_url;
         $site_url =~ s{ \A \w+ :// [^/]+ }{}xms;
         $site_url =~ s{ / \z }{}xms;
-        $include = join q{/}, $site_url, $blog->include_path_parts($name);
+        $include = join q{/}, $site_url, @path, $filename;
     }
     else {
-        $include = $blog->include_path($name);
+        $include = $blog->include_path(@_);
         $statement = $system eq 'php'   ? q{<?php include("%s") ?>}
                    : $system eq 'jsp'   ? q{<%@ include file="%s" %>}
Index: branches/release-35/lib/MT/CMS/Template.pm
===================================================================
--- branches/release-35/lib/MT/CMS/Template.pm (revision 1913)
+++ branches/release-35/lib/MT/CMS/Template.pm (revision 1949)
@@ -474,4 +474,5 @@
         if ($blog) {
             $param->{include_with_ssi}      = 0;
+            $param->{cache_path}            = '';
             $param->{cache_enabled}         = 0;
             $param->{cache_expire_type}     = 0;
@@ -483,4 +484,6 @@
             $param->{include_with_ssi} = $obj->include_with_ssi
               if defined $obj->include_with_ssi;
+            $param->{cache_path}       = $obj->cache_path
+              if defined $obj->cache_path;
             $param->{cache_enabled} = $obj->use_cache
               if defined $obj->use_cache;
@@ -1237,4 +1240,5 @@
     # module caching
     $obj->include_with_ssi( $app->param('include_with_ssi') ? 1 : 0 );
+    $obj->cache_path( $app->param('cache_path'));
     $obj->use_cache( $app->param('cache_enabled')           ? 1 : 0 );
     my $cache_expire_type = $app->param('cache_expire_type');
Index: branches/release-35/lib/MT/Template/ContextHandlers.pm
===================================================================
--- branches/release-35/lib/MT/Template/ContextHandlers.pm (revision 1926)
+++ branches/release-35/lib/MT/Template/ContextHandlers.pm (revision 1949)
@@ -2328,4 +2328,5 @@
     my $blog = $ctx->stash('blog') || MT->model('blog')->load($blog_id);
 
+    my %include_recipe;
     my $use_ssi = $blog && $blog->include_system
         && ($arg->{ssi} || $tmpl->include_with_ssi) ? 1 : 0;
@@ -2334,5 +2335,16 @@
         # easiest way to determine this is from the variable
         # space setting.
-        $use_ssi = 0 if $ctx->var('system_template');
+        if ($ctx->var('system_template')) {
+            $use_ssi = 0;
+        } else {
+            my $extra_path = $arg->{cache_key} ? $arg->{cache_key}
+                : $tmpl->cache_path ? $tmpl->cache_path
+                    : '';
+           %include_recipe = (
+                name => $tmpl_name,
+                id   => $tmpl->id,
+                path => $extra_path,
+            );
+        }
     }
 
@@ -2342,10 +2354,10 @@
       && $blog->include_cache
       && ( ( $arg->{cache} && $arg->{cache} > 0 )
-        || $arg->{key}
+        || $arg->{cache_key}
         || ( exists $arg->{ttl} )
         || $tmpl->use_cache ) ? 1 : 0;
     my $cache_key =
-        $arg->{key}
-      ? $arg->{key}
+        $arg->{cache_key}
+      ? $arg->{cache_key}
       : 'blog::' . $blog_id . '::template_' . $type . '::' . $tmpl_name;
     my $ttl =
@@ -2362,6 +2374,6 @@
                 if ($use_ssi) {
                     # base cache expiration on physical file timestamp
-                    my $include_name = $arg->{key} || $tmpl_name;
-                    my $mtime = (stat($blog->include_path($include_name)))[9];
+                    my $include_file = $blog->include_path(\%include_recipe);
+                    my $mtime = (stat($include_file))[9];
                     if ($mtime && (MT::Util::ts2epoch(undef, $latest) > $mtime ) ) {
                         $ttl = 1; # bound to force an update
@@ -2388,10 +2400,9 @@
             return $cache_value if !$use_ssi;
 
-            my $include_name = $arg->{key} || $tmpl_name;
             # The template may still be cached from before we were using SSI
             # for this template, so check that it's also on disk.
-            my ($path, $file_path) = $blog->include_path($include_name);
-            if ($blog->file_mgr->exists($file_path)) {
-                return $blog->include_statement($include_name);
+            my $include_file = $blog->include_path(\%include_recipe);
+            if ($blog->file_mgr->exists($include_file)) {
+                return $blog->include_statement(\%include_recipe);
             }
         }
@@ -2424,7 +2435,7 @@
 
     if ($use_ssi) {
-        my $include_name = $arg->{key} || $tmpl_name;
+        my ($include_file, $path, $filename) =
+            $blog->include_path(\%include_recipe);
         my $fmgr = $blog->file_mgr;
-        my ($path, $file_path) = $blog->include_path($include_name);
         if (!$fmgr->exists($path)) {
             if (!$fmgr->mkpath($path)) {
@@ -2433,15 +2444,16 @@
             }
         }
-        defined($fmgr->put_data($ret, $file_path))
+        defined($fmgr->put_data($ret, $include_file))
             or return $ctx->error(MT->translate("Writing to '[_1]' failed: [_2]",
-                $file_path, $fmgr->errstr));
+                $include_file, $fmgr->errstr));
 
         MT->upload_file_to_sync(
-            url  => $blog->include_url($include_name),
-            file => $file_path,
+            url  => $blog->include_url(\%include_recipe),
+            file => $include_file,
             blog => $blog,
         );
 
-        return $blog->include_statement($include_name);
+        my $stat = $blog->include_statement(\%include_recipe);
+        return $stat;
     }
 
Index: branches/release-35/lib/MT/Template.pm
===================================================================
--- branches/release-35/lib/MT/Template.pm (revision 1937)
+++ branches/release-35/lib/MT/Template.pm (revision 1949)
@@ -44,4 +44,5 @@
         'cache_expire_interval' => 'integer meta',
         'cache_expire_event' => 'string meta',
+        'cache_path' => 'string meta',
     },
     indexes => {
