Im using gulp-twig: https://github.com/zimmen/gulp-twig
I have a twig file for my container component:
{# container.twig #} <div class="container"> {% for item in items %} <div class="container__item"> {{ item }} </div> {% endfor %} </div>
I also have a snippet file:
{# snippet.twig #} <div class="snippet"> <h2>{{ title }}</h2> </div>
Im demoing these in page.twig. I need to render the snippet as the {{ item }} within the container. So when viewing page.twig this should be the output:
<div class="container"> <div class="container__item"> <div class="snippet"> <h2>title</h2> </div> </div> <div class="container__item"> <div class="snippet"> <h2>title</h2> </div> </div> <div class="container__item"> <div class="snippet"> <h2>title</h2> </div> </div> </div>
Now here is where it gets tricky. container.twig and snippet.twig are being pulled into another application. As such {{ item }} within container.twig cant be changed to something like {{ itemRenderer(item) }}.
However page.twig is not being used anywhere else so I can edit it however I like. Is there a way in page.twig to render container.twig with snippet.twig as it's item, without modifying container.twig or snippet.twig?
This is my gulp task:
var gulp = require('gulp'), config = require('../config'), utilities = require('../build-utilities'), src = config.path.src, dest = config.path.dest, opts = config.pluginOptions, env = utils.getEnv(), plugins = require('gulp-load-plugins')(opts.load); var compile = function() { var notProdOrTest = env.deploy && !env.prod && !env.test, deployPath = env.deployPath, sources = (env.deploy) ? ((env.styleguide) ? src.twig.styleguide: src.twig.testing): src.twig.all; return gulp.src(sources, {base: 'src/'}) .pipe(plugins.twig({ data: { component: utils.getDirectories('src/component/'), deploy : env.deploy, test : env.test, prod : env.prod } })) .pipe(plugins.htmlmin(opts.htmlmin)) .pipe(plugins.tap(function(file){ file.path = file.path.replace('testing/', ''); })) .pipe((notProdOrTest) ? plugins.replace(/src="\//g, 'src="/' + deployPath.root + '/'): plugins.gutil.noop()) .pipe((notProdOrTest) ? plugins.replace(/href="\//g, 'href="/' + deployPath.root + '/'): plugins.gutil.noop()) .pipe((notProdOrTest) ? plugins.replace(/srcset="\//g, 'srcset="/' + deployPath.root + '/'): plugins.gutil.noop()) .pipe((notProdOrTest) ? plugins.replace(/url\('\//g, 'url(\'/' + deployPath.root + '/'): plugins.gutil.noop()) .pipe(gulp.dest((env.deploy) ? deployPath.markup: dest.markup)); }, watch = function() { gulp.watch(src.twig.watch, ['twig:compile']); }; module.exports = { compile: compile, watch : watch };
2 Answers
Answers 1
This could be done with macros:
{# macros.html.twig #} {% macro thisItem(item) %} <div class="this-snippet"> <h2>{{ item.title }}</h2> </div> {% endmacro %} {% macro thatItem(item) %} <div class="other-snippet"> <h2>{{ item.title }}</h2> </div> {% endmacro %} {% macro container(itemRenderer, items) %} <div class="container"> {% for item in items %} <div class="container__item"> {{ itemRenderer(item) }} </div> {% endfor %} </div> {% endmacro %}
And then in the template:
{# template.html.twig #} {% from "macros.html.twig" import thisItem as itemRenderer, container %} {% container(itemRenderer, items) %}
And in another template:
{# template2.html.twig #} {% from "macros.html.twig" import thatItem as itemRenderer, container %} {% container(itemRenderer, items) %}
The same thing can be achieved with regular includes, although both offer the same possibilities, I think the macro solution is cleaner.
{# snippet.html.twig #} <div class="this-snippet"> <h2>{{ item.title }}</h2> </div> {# container.html.twig #} <div class="container"> {% for item in items %} <div class="container__item"> {% include snippetTmpl with { 'item': item } only %} </div> {% endfor %} </div> {# page.html.twig #} {% include "container.html.twig" with { 'snippetTmpl': 'snippet.html.twig', 'items': items } only %}
Answers 2
I don't see how it could be possible without modifying container.html.twig
, since you are trying to render {{ item }}
, which is intended to be HTML, without the raw
filter, which is mandatory to mark the content of {{ item }}
as HTML-safe.
If you are the owner of the container.html.twig
file origin (not sure what you meant by
container.twig and snippet.twig are being pulled into another application
), maybe you could change {{ item }}
to {{ item|raw }}
. Then you would just need to be sure the items
parameter passed to container.html.twig
contains HTML generated by a renderView
of snippet.html.twig
. Then just be careful container.html.twig
is not used somewhere else with HTML-unsafe items
.
If you really don't have your hands on it, you may also try to render your template with a Twig environment that has autoescape
disabled.
Hope this helps!
EDIT: Since you must do this using gulp-twig, what about something like this:
var titles = ['First snippet', 'second snippet']; var i, items; for (i = 0; i < titles.length; i++) { gulp.src('/path/to/snippet.html.twig') .pipe(plugins.twig({ data: { title: titles[i] } })) .pipe(plugins.intercept(function(file){ items[i] = file.contents.toString(); return file; })); } gulp.src('/path/to/container.html.twig') .pipe(plugins.twig({ data: { items: items } })) .dest('/path/to/dest.html');
0 comments:
Post a Comment