Selvin Ortiz

Rendering Templates In Custom Locations

April 15, 2015 by

Cover Image for Rendering Templates In Custom Locations

When you write a plugin for Craft, you may need to render templates located in a custom directory to allow users to override templates you provide by default. In fact, this may be necessary if you’re trying to render a site template from the control panel or vice versa.

By default, Craft will look for template in specific locations and if your templates live outside of these locations, you’ll have to tell Craft where to find it.

Rendering #

To render templates in a custom directory, this is my usual workflow.

  1. Store the original templates path in a variable
  2. Set the templates path to your custom directory
  3. Call the render method you need to use
  4. Set the templates path to the original directory
  5. Output or return the rendered content

In Practice #

Here is a short snippet that illustrates the workflow outlined above.


$oldPath = craft()->path->getTemplatesPath();

craft()->path->setTemplatesPath('path/to/your/templates/');

$html = craft()->templates->render('template');

craft()->path->setTemplatesPath($oldPath);

return TemplateHelper::getRaw($html);

This is pretty much it for parsing templates in custom locations or locations determined at runtime.

However, if this template path swapping thing is not clear to you yet, there is another way.

Rendering From String #

To accomplish the task of rendering templates in custom locations without path swapping, you could use the old file_get_contents() on a file and then render its contents from string.

This is what that would look like…

$file = 'path/to/your/template.html'; // or .twig|.txt|.whatever

if (is_readable($file))
{
    $source   = file_get_contents($file);
    $rendered = craft()->templates->renderString($source);

    return TemplateHelper::getRaw($rendered);
}

Wrapping It In A Service #

If you do this often enough or your plugin makes extensive use of this technique, it might be worth abstracting it away into your service layer.

<?php
namespace Craft;

class MyPluginService extends BaseApplicationComponent
{
    const DEFAULT_TEMPLATES_PATH = 'path/to/your/templates/';

    /**
     * Renders a template in a custom location defined by $path
     *
     * @param string $file
     * @param array  $vars
     * @param string $path
     *
     * @return \Twig_Markup
     */
    public function renderCustomTemplate($file, array $vars = array(), $path = self::DEFAULT_TEMPLATES_PATH)
    {
        $oldPath = craft()->path->getTemplatesPath();

        craft()->path->setTemplatesPath($path);

        $html = craft()->templates->render($file, $vars);

        craft()->path->setTemplatesPath($oldPath);

        return TemplateHelper::getRaw($html);
    }

    /**
     * Renders the content of a template file using absolute path defined by $file
     *
     * @param string $file
     * @param array  $vars
     *
     * @throws Exception
     * @return \Twig_Markup
     */
    public function renderCustomTemplateString($file, array $vars = array())
    {
        if (is_readable($file))
        {
            $source   = file_get_contents($file);
            $rendered = craft()->templates->renderString($source, $vars);

            return TemplateHelper::getRaw($rendered);
        }

        throw new Exception(Craft::t('{f} is missing or cannot be read.', array('f' => $file)));
    }
}

I’ve created a new gist for the final snippet so that you can study further and contribute to, if you find anything that can be improved on.

Hope you find this helpful, questions or comments are always welcomed.

Categorized As