diff --git a/src/Cortex/Router/MatchingResult.php b/src/Cortex/Router/MatchingResult.php
index e23759d..0417897 100644
--- a/src/Cortex/Router/MatchingResult.php
+++ b/src/Cortex/Router/MatchingResult.php
@@ -86,13 +86,15 @@ public function matched()
     }
 
     /**
-     * @return string
+     * @return string|bool|callable
      */
     public function template()
     {
         $template = $this->data['template'];
 
-        return (is_string($template) || $template === false) ? $template : '';
+        return (is_string($template) || $template === false || is_callable($template))
+            ? $template
+            : '';
     }
 
     /**
diff --git a/src/Cortex/Router/ResultHandler.php b/src/Cortex/Router/ResultHandler.php
index f1f32d3..6680b1c 100644
--- a/src/Cortex/Router/ResultHandler.php
+++ b/src/Cortex/Router/ResultHandler.php
@@ -28,7 +28,7 @@ public function handle(MatchingResult $result, \WP $wp, $doParseRequest)
         $result = apply_filters('cortex.match.done', $result, $wp, $doParseRequest);
         $handlerResult = $doParseRequest;
 
-        if (! $result instanceof MatchingResult) {
+        if (!$result instanceof MatchingResult) {
             return $result;
         }
 
@@ -40,23 +40,28 @@ public function handle(MatchingResult $result, \WP $wp, $doParseRequest)
             $before = $this->buildCallback($result->beforeHandler());
             $after = $this->buildCallback($result->afterHandler());
             $template = $result->template();
-            (is_string($template)) or $template = '';
             $vars = $result->vars();
             $matches = $result->matches();
 
+            if (is_callable($template)) {
+                $template = $template($vars, $wp, $matches);
+            }
+
+            (is_string($template) || $template === 'false') or $template = '';
+
             do_action('cortex.matched', $result, $wp);
 
             is_callable($before) and $before($vars, $wp, $template, $matches);
             is_callable($handler) and $handlerResult = $handler($vars, $wp, $template, $matches);
             is_callable($after) and $after($vars, $wp, $template, $matches);
-            $template and $this->setTemplate($template);
+            $this->setTemplate($template);
 
             do_action('cortex.matched-after', $result, $wp, $handlerResult);
 
             is_bool($handlerResult) and $doParseRequest = $handlerResult;
             $doParseRequest = apply_filters('cortex.do-parse-request', $doParseRequest);
 
-            if (! $doParseRequest) {
+            if (!$doParseRequest) {
                 remove_filter('template_redirect', 'redirect_canonical');
 
                 return false;
@@ -79,7 +84,7 @@ private function buildCallback($handler)
             $built = $handler;
         }
 
-        if (! $built && $handler instanceof ControllerInterface) {
+        if (!$built && $handler instanceof ControllerInterface) {
             $built = function (array $vars, \WP $wp, $template) use ($handler) {
                 return $handler->run($vars, $wp, $template);
             };
@@ -93,14 +98,14 @@ private function buildCallback($handler)
      */
     private function setTemplate($template)
     {
-        if (is_string($template)) {
+        if (is_string($template) && $template) {
             $ext = apply_filters('cortex.default-template-extension', 'php');
-            pathinfo($template, PATHINFO_EXTENSION) or $template .= '.'.ltrim($ext, '.');
+            pathinfo($template, PATHINFO_EXTENSION) or $template .= '.' . ltrim($ext, '.');
             $template = is_file($template) ? $template : locate_template([$template], false);
-            $template or $template = null;
+            $template or $template = '';
         }
-        
-        if (is_null($template)) {
+
+        if ($template === '' || !(is_string($template) || $template === false)) {
             return;
         }
 
@@ -124,7 +129,7 @@ private function setTemplate($template)
         ];
 
         $returnTemplate = function () use ($template) {
-            current_filter('template_include') and remove_all_filters('template_include');
+            current_filter() === 'template_include' and remove_all_filters('template_include');
 
             return $template;
         };