4

I want to render a Twig template in an API endpoint. Specifically I need HTML for the JSON Feed field "content_html".

My attempts until now (inside the transformer function):

$view = Craft::$app->getView();
$template = $view->resolveTemplate('_blog-entry');

// first attempt:
$html = $view->render($template, ['entry' => $blogpost]);

// second attempt:
$controller = Craft::$app->createController('templates/render')[0];

$html = $controller->render($template, ['entry' => $blogpost])

But in both ways it says "Template not found" even if the path after the "resolveTemplate" is correct.

Has anybody an idea how to do it? Thanks!

4

You didn’t tell where that Twig file is located, but I assume your issue has to do with being in the wrong “Template Mode”.

Here’s how you can switch mode:

Craft::$app->view->setTemplateMode()

Documentation: https://docs.craftcms.com/v3/extend/updating-plugins.html#rendering-plugin-templates-on-front-end-requests

  • 1
    Thank you very much! I tried to render a template from my own "templates" folder, not for the Craft CP. So the solution was: $view->setTemplateMode($view::TEMPLATE_MODE_SITE); $view->renderTemplate('_blog-entry', ['entry' => $blogpost]) – zauni Dec 8 '17 at 15:50
4

You're using $view->resolveTemplate('_blog-entry') which is returning the absolute path to the template as a string, and then passing that to $view->render which is expecting a relative path, not an absolute one. Internally I expect it's trying to run resolveTemplate on its argument, and it isn't sophisticated enough to recognize that a path is already absolute.

From your comment on the other answer it looks like you solved this, though didn't highlight it as the solution: just pass the relative template path straight to render; no need to use resolveTemplate first.

So corrected full code might be:

$view = Craft::$app->getView();
$html = $view->render('_blog-entry', ['entry' => $blogpost]);

I don't believe switching the template mode, as suggested in the other answer, is actually required, at least not under all circumstances.

1

I wrote a transformer class that does exactly this:

namespace your\awesome\namespace;

use Craft;
use craft\elements\Entry;
use League\Fractal\TransformerAbstract;
use craft\web\View;

/**
 * Class TwigTransformer
 * Renders a TWIG entry for each item
 */

class TwigTransformer extends TransformerAbstract
{
    private $twigTemplateFilePath;

    public function __construct($twigTemplateFilePath)
    {
        $this->twigTemplateFilePath = $twigTemplateFilePath;
    }

    public function transform(Entry $entry)
    {
        $oldMode = Craft::$app->view->getTemplateMode();
        Craft::$app->view->setTemplateMode(View::TEMPLATE_MODE_SITE);
        $html = Craft::$app->view->renderTemplate( $this->twigTemplateFilePath, ['entry' => $entry]);
        Craft::$app->view->setTemplateMode($oldMode);

        return [
            'id' => $entry->id,
            'html' => $html
        ];
    }
}

You could use the class likes this:

'transformer' => new TwigTransformer('includes/_overview-entry.twig'),

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.