Is it possible to share HubL macros across modules and templates? - hubl

In the HubSpot CMS, you can create a macro like so:
{% macro render_section(classes, background_style) %}
<div class="mosaic-section {{classes}}" {{background_style}}>
{{ caller() }}
</div>
{% endmacro %}
Is it possible to share this macro across different modules and templates? Or do you have to repeat the macro everywhere you need to use it?

Yes, you can share macros across modules but only the modules that are in the same scope as an imported HTML partial/snippet that contains the macros you've created.
According to the HubL docs for using the {% import %} tag (found here), macros can be imported from user created HTML partials/snippets. For example, if you were to create the following HTML partial called macros.html:
{% macro render_section(classes, background_style='', data='') %}
<div class="mosaic-section {{classes}}" {{background_style}} {{data}}>
{{ caller() }}
</div>
{% endmacro %}
You would then import macros.html into a template, for example, called homepage.html with the following HubL/HTML code:
<!doctype html>
<head>
{# standard HubL header code goes here %}
</head>
<body class="site-page two-column {{ builtin_body_classes }}" style="">
{% import 'path/to/macros.html as module_macros %}
<!--- more HubL/HTML code .... -->
{{ standard_footer_includes }}
</body>
</html>
And as result, all modules added to the homepage.html coded template are now in the same scope as the imported macros and as such said modules can now utilize the macros.
If you'd like to import a single macro from a HTML partial that contains multiple macros you can use the {% from %} tag (found here) and perform the following:
{% from 'path/to/macros.html' import render_section %}
Now the macro render_section() is available to all proceeding modules in the coded template.
NOTE:
Unfortunately, I have yet to find a way to use/import macros "globally" into a drag-and-drop template -- at least without having to use an embed HubL module which can add weird spacing issues in the generated HTML markup that you may need to resolve using CSS.
Hope this answer was sufficient and helps resolve the problem you've posed.

Related

zendesk - semantic template array accessor

Is there a way for me to access a particular element of an array using Zendesk semantic templating. https://connect.zendesk.com/hc/en-us/articles/115010914668-Using-the-email-editor#topic_h2z_hn5_r1b
Normally you would go through each element of the array
{% for image in 'images' | EventProperty %}
<img src="{{ image.src }}">
{% endfor %}
But for my current use case I only need the first element. I wanna do something similar to the following:
<img src="{{ images[0].src }}">
The syntax looks like Liquid Markup, and I know they use Liquid in other areas of the product. Have you tried the Liquid Filter 'first'?
{% assign my_array = "apples, oranges, peaches, plums" | split: ", " %}
{{ my_array.first }}

Encore webpack or assets generating wrong path to image in symfony 4

I am trying to learn to use encore webpack.
Well, following this guideEncore + webpack + bootstrap sass and this guide Symfony 4+ enconre + Bootstrap 4 I got symfony to use the scss and js assets I use.
But the problem is when I insert an image in my scss code (for a bg) the relative url I see in the browser is wrongly generated.
Webpack is generating the image here:
public\build\images\2.f26e9a05.jpg
But the url in the browser ends up like this:
/public/build/build/images/2.f26e9a05.jpg
(if I delete the second "build/" the image loads like it should)
this is my folder estructure:
assets:
css:
app.scss
js:
app.js
public:
images:
2.jpg
app.scss:
#import '~bootstrap/scss/bootstrap';
...
.parallax {
background-image: url("images/2.jpg");
}
Webpack.config.js:
var Encore = require('#symfony/webpack-encore');
Encore
// the project directory where compiled assets will be stored
.setOutputPath('public/build/')
// the public path used by the web server to access the previous directory
.setPublicPath('build')
// the public path you will use in Symfony's asset() function - e.g. asset('build/some_file.js')
.setManifestKeyPrefix('build/')
.cleanupOutputBeforeBuild()
.enableSourceMaps(!Encore.isProduction())
// the following line enables hashed filenames (e.g. app.abc123.css)
//.enableVersioning(Encore.isProduction())
// uncomment to define the assets of the project
.addEntry('app', './assets/js/app.js')
//.addStyleEntry('css/app', './assets/css/app.scss')
// uncomment if you use TypeScript
//.enableTypeScriptLoader()
// uncomment if you use Sass/SCSS files
.enableSassLoader()
// uncomment for legacy applications that require $/jQuery as a global variable
.autoProvidejQuery()
;
module.exports = Encore.getWebpackConfig();
index.html.twig:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}100Monos{% endblock %}</title>
{% block stylesheets %}
<link rel="stylesheet" href="{{ asset('build/app.css') }}">
{% endblock %}
</head>
<body>
<div class="container">
{% block body %}
<div id="Nosotros" class="pantalla d-flex align-items-center parallax">
<div class="contenido">
<h1>100Monos</h1>
<h3>Nuestra Web es mala porque pasamos todo el tiempo haciendo la suya</h3>
<img src="{{ asset('images/1.jpg') }}">
</div>
</div>
{% endblock %}
{% block javascripts %}
<script src="{{ asset('build/app.js') }}"></script>
{% endblock %}
</div>
</body>
</html>
I am responding to this rather old question, because I assume some things have changed in the meantime concerning yarn watch and the setting of the public path:
If I do a:
.setPublicPath('./')
yarn watch feels offended, and shows a:
WARNING The value passed to setPublicPath() should *usually* start with "/" or be a full URL (http://...). If you're not sure, then you should probably change your public path and make this message disappear..
So I think the way this is meant to be is more like this:
Encore
// directory where compiled assets will be stored
.setOutputPath('public/build/')
// public path used by the web server to access the output path
.setPublicPath('/public/build')
// only needed for CDN's or sub-directory deploy
.setManifestKeyPrefix('public/build/')
So the public path should still be absolute while the "manifest prefix" takes care of the set up as a subdirectory.
Information on this can be found here:
webpack-encore-readme
webpack-encore-issue-13
Just added this for correctness, as I stumbled over it and others might as well...
I resolved it at the end, after testing many things. There was 2 problem I kept repeating.
First, the path was generated in a not relative way, solve it changing webpack with this:
.setPublicPath('./')
But then the scss didn't load, what happen? Well, the prefix was the problem, because when you put the prefix in the asset function it takes the prefix and change it for the public path... so I changed the prefix for
.setManifestKeyPrefix('webpack/')
(something random really)

include file without swig parsing it as a template

I would like to include a file in a swig template without swig parsing it as a swig template. Something like raw tag for files.
Using swig-highlight I would like to get this working.
{% highlight 'html' %}
{% import 'some-template-file.html' %}
{% endhighlight %}
Problem is 'some-template-file.html' is a Jekyll template and throws errors in swig.
You can try using the raw tag. This ignores any inside swig syntax and should, presumably, ignore any other syntax as well.
// inside (e.g.) index.html
{% import 'some-template-file.html' %}`
// inside some-template-file.html
{% raw %} {{ testVar }} {% endraw %}
// results in "{{ testVar }}"

Extending erlydtl

How is it possible to extend "erlydtl"?
I really like django templates, and the way the template language can be extended. For example, I like the extensions such as "sekizai".
It is possible to have custom tag modules for erlydtl. But how do I add support for more complex tags such as provided by sekizai?
In django, using sekizai I can do following (taken from sekizai documentation).
{% render_block "css" %}
And add following to add to the above block
{% addtoblock "css" %}
<link href="/media/css/stylesheet.css" media="screen" rel="stylesheet" type="text/css" />
{% endaddtoblock %}
And this will add the contents at the place where {% render_block %} is called.
You need to write your own module and define functions that are called and provide the data for your template tags.
Example:
File perc_filter.erl:
-module(perc_filter).
-export([percentage/2]).
percentage(Input, Whole) when is_integer(Input), is_integer(Whole) ->
[Result] = io_lib:format("~.2f", [Input / Whole * 100]),
Result.
In template:
{{ x|percentage:1000 }}

Django templates problem — {% if object|length > 4 %} raises TemplateDoesNotExist: 500.html

I have the following in my template.
{% block content %}
{% for album in albumsList %}
{% if fotosList %}
<div class="photoalbum-wrapper">
<h3>{{ album.title }}</h3>
<ul class="photoalbum">
{% for foto in fotosList %}<li>item</li>{% endfor %}
</ul>
{% if fotosList|length > 4 %}
больше <span>▼</span>
{% endif %}
</div>
{% endif %}
{% endfor %}
{% endblock %}
And it raises TemplateDoesNotExist: 500.html.
If i write simple {{ fotoList|length }} it works okay.
This is a very old question. Since then, newer versions of Django support operators in if-statement out of the box, so the following code will work just fine:
{% if fotosList|length > 4 %}
{% endif %}
Use fotosList.count instead of fotosList|length. you will get desired result.
FYI if tags with the operators ==, !=, <, >, <=, >= are supported now in the development version of Django.
{% if fotosList|length > 4 %} is not a valid tag; you can't use greater than/less than operators in the Django if tag. (You can use operators in the latest development release, but I'm assuming you're not using the latest version from Django's SVN repository.)
The reason you get the TemplateDoesNotExist error is because Django is throwing a 500 Internal Server Error (due to the invalid tag), but you haven't supplied a 500.html error template, as noted here.

Resources