diff --git a/lib/SimpleSAML/XHTML/Template.php b/lib/SimpleSAML/XHTML/Template.php
index 7a4e3d6169e730a4788a42a6d77610ab58cd730a..38a8066c3083d6d5377d31062b02ec8d772313c6 100644
--- a/lib/SimpleSAML/XHTML/Template.php
+++ b/lib/SimpleSAML/XHTML/Template.php
@@ -70,6 +70,17 @@ class SimpleSAML_XHTML_Template
      */
     private $module;
 
+    /**
+     * A template controller, if any.
+     *
+     * Used to intercept certain parts of the template handling, while keeping away unwanted/unexpected hooks. Set
+     * the 'theme.controller' configuration option to a class that implements the
+     * SimpleSAML\XHTML\TemplateControllerInterface interface to use it.
+     *
+     * @var SimpleSAML\XHTML\TemplateControllerInterface
+     */
+    private $controller;
+
 
     /**
      * Whether we are using a non-default theme or not.
@@ -107,6 +118,15 @@ class SimpleSAML_XHTML_Template
         // initialize internationalization system
         $this->translator = new SimpleSAML\Locale\Translate($configuration, $defaultDictionary);
         $this->localization = new \SimpleSAML\Locale\Localization($configuration);
+
+        // check if we need to attach a theme controller
+        $controller = $this->configuration->getString('theme.controller', false);
+        if ($controller && class_exists($controller) &&
+            class_implements($controller, '\SimpleSAML\XHTML\TemplateControllerInterface')
+        ) {
+            $this->controller = new $controller();
+        }
+
         $this->twig = $this->setupTwig();
     }
 
@@ -221,6 +241,10 @@ class SimpleSAML_XHTML_Template
         $twig->addGlobal('queryParams', $queryParams);
         $twig->addGlobal('templateId', str_replace('.twig', '', $this->normalizeTemplateName($this->template)));
 
+        if ($this->controller) {
+            $this->controller->setUpTwig($twig);
+        }
+
         return $twig;
     }
 
@@ -369,6 +393,9 @@ class SimpleSAML_XHTML_Template
     {
         if ($this->twig !== false) {
             $this->twigDefaultContext();
+            if ($this->controller) {
+                $this->controller->display($this->data);
+            }
             echo $this->twig->render($this->twig_template, $this->data);
         } else {
             $filename = $this->findTemplatePath($this->template);
diff --git a/lib/SimpleSAML/XHTML/TemplateControllerInterface.php b/lib/SimpleSAML/XHTML/TemplateControllerInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..bd54907c48a9e5d4152062e36a19add335ad83ee
--- /dev/null
+++ b/lib/SimpleSAML/XHTML/TemplateControllerInterface.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace SimpleSAML\XHTML;
+
+/**
+ * Interface that allows modules to run several hooks for templates.
+ *
+ * @package SimpleSAMLphp
+ */
+interface TemplateControllerInterface {
+
+    /**
+     * Implement to modify the twig environment after its initialization (e.g. add filters or extensions).
+     *
+     * @param \Twig_Environment $twig The current twig environment.
+     *
+     * @return void
+     */
+    public function setUpTwig(\Twig_Environment &$twig);
+
+
+    /**
+     * Implement to add, delete or modify the data passed to the template.
+     *
+     * This method will be called right before displaying the template.
+     *
+     * @param array $data The current data used by the template.
+     *
+     * @return void
+     */
+    public function display(&$data);
+}