Twig escaping HTML and rendering as raw - html

I hope someone can assist me on this issue.
I am pulling details from a database to display on a twig template (using Symfony2) but the way in which it is saved in the db makes it difficult to interpret the HTML.
Basically, the HTML tags are already translated as entities in the table, e.g.:
<p>Bach Flower Crab Apple Remedy:&nbsp;the "cleansing" Remedy can be used both internally and externally&nbsp;</p><p><strong>
And so on. I have researched the rendering options in twig and tried the following (based on me rendering a loop of product descriptions):
{% set strategy = 'html' %}
{% autoescape 'html' %}
{{ product.description|escape('html')|raw }}
{% endautoescape %}
and also just:
{{ product.description|raw }}
The first method just echoes the existing content (as entities) and the second method just renders the HTML tags to the page as follows:
<p>Bach Flower Crab Apple Remedy: the "cleansing" Remedy can be used both internally and externally.</p><p><strong>...
So, as you can see, I cannot find a way to actually interpret the HTML tags in order to display the description as it should be.
Is there a way to do this? I can't do it in the PHP as all it's doing is sending an object to the template which is looped through:
public function showAction(Request $request, $store_id=0)
{
$max = 1000;
$repository = $this->getDoctrine()->getRepository('AppBundle:Product');
$products = $repository->getProductsByStoreId($store_id,$max);
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$products,
$request->query->get('page', 1),
20
);
$return['products'] = $pagination;
$return['categories'] = $this->getCategories();
return $this->render('AppBundle:tables:productstable.html.twig', $return);
}

Your core issue is that you do not have HTML in your database to begin with. At best Twig could be outputting some HTML entities, which will render visibly as "<p>...", and at "worst" Twig will escape the text to render it accurately as it actually is, which is "<p>...". Expecting Twig to output actual HTML which will render a paragraph is unrealistic, since that's not what your original data contains at all.
You'll have to HTML-decode that text in PHP first, and then output it in Twig with ..|raw. raw means that Twig will output it as is without further escaping it. Since it's nonsense to get the data from the database to then html_entity_decode it, you need to fix your data input here! Don't HTML encode data which is going into the database, it serves no purpose.

I think you have to write custom escaper plugin to decode html entities and use it like this:
{{ product.description|myawesomehtmlentitiesdecoder|raw }}
http://twig.sensiolabs.org/doc/filters/escape.html#custom-escapers for reference.
But generally, it's better to store HTML in database and then apply needed security filters on output.

Related

Pulling API data into Django Template that has <a></a> tags embedded, is there a way of wrapping the text in an HTML tag?

I'm reading a very large API, one of the fields I need, have "a" tags embedded in the item in the dictionary and when I pull it into my template and display it, it shows the "a" tags as text.
exp:
"Bitcoin uses the SHA-256 hashing... ...such as Litecoin, Peercoin, Primecoin*"
I would like to wrap this in HTML so when it displays on the page it has the actual links rather than the 'a' tags and the URL.
What I'm looking to get:
"Bitcoin uses the SHA-256 hashing... ...such as Litecoin, Peercoin, Primecoin*"
I figured it out, I used the Humanize function with the |safe tag.
Pretty simple answer.
In the settings.py add 'django.contrib.humanize' to the INSTALLED_APPS:
**INSTALLED_APPS = [
'django.contrib.humanize', ]**
In the HTML Template add
{% load humanize %}
For the data you want to format use |safe
{{ location.of.data|safe }}
This will read the text as HTML.

reusing handlebars & panini partials with different data

I've a number of 'building blocks' I've created of my own to use when templating a site and I'm wondering how I could use Panini to re-use partials on the same page, with different data.
Say for example I have a partial which basically adds a h1 tag followed by a single p tag but I want to be able to re-use that same partial on the same page with different data each time.
This is the content of the partial file for example;
<h1> {{ h1Header }}</h1>
<p> {{ pParagraph }} </p>
The Frontmatter data in the Index file;
---
h1Header: Hello!
pParagraph: This is some text.
---
And this to call the partial into action;
{{> partial }}
Unless I'm doing something fundamentally wrong the way I'm using it at the moment would mean I'd have to create several different partials for each possible outcome.
I was wondering if there was some way of sending arguments etc. If someone can point me in the right direction with even the simplest of examples just to get a feel of what I can do and what to look into I'd be grateful.
You can pass data to your partials passing a context or parameters to your partial. You can pass different data every-time you render the partial, according to the manual.
Having a partial called test:
<h1>{{foo}}</h1>
You can render it with specific data:
{{> test foo="bar"}}
{{> test foo="foobar"}}
Which results in
<h1>foo</h1>
<h1>foobar</h1>

import template with context doesn't seem to be working

I've recently been trying to get to grips with nunjucks, I've used handlebars before so the learning curve hasn't been that bad. However there is one thing I can't seem to get working:
I've got a JSON file which has the following data in it:
"contentIntro" : {
"componentClass" : "c-global-header",
"title" : "Welcome Firstname Surname,",
"subtitle" : "New applications:",
"bodyCopy" : "You can create, edit and save the draft application as many times as you need before submitting it for assessment.",
"ctaType" : "text",
"ctaText" : "View the list",
"ctaURL" : "#"
}
This exists in a JSON file which includes other page elements but it's only the contentIntro context I'm interested in.
If I include a partial like this:
{% include "components/c-headed-text.nunjucks" %}
then I can access the JSON data using dot notation within that partial (eg {{ contentIntro.title }}), however this isn't very flexible and it precludes me having more than one of the same partial type on the page.
Ideally what I'd want to do is import the partial like this:
{% import "components/c-headed-text.nunjucks" as contentIntro %}
and then in the template I can just access the JSON data using {{ title }} as it will already know the context from the import.
Annoyingly though it doesn't work and I can't see why. The Jinja2 documentation seems to suggest it would but I can't get it to work using Nunjucks, is this even possible?
Edit: I should also add that the templates are being prerendered in gulp so the end result is just flat HTML.
Ok I've found a way around it. it's not as clean as I'd like but it does the job.
I just a normal include statement:
{% include "components/c-headed-text.nunjucks" %}
but above it a set a variable as follows:
{% set context = contentIntro %}
Then inside the partial I can just use {{ context.title }} and it works like a charm!

URL encoding on Django Template

I have this anchor link:
{{title}}
Sometimes, this title has some content with + (add operator) like:
"Django + Python"
But when it is directly placed on anchor links, the url delivered will be:
http://127.0.0.1:8080/question/tag/1/1/?list_id=Django + Python
Which will eventually cause problem on the retrieval as the url decoder thought the list_id GET = DjangoPython.
So, does anyone knows how to avoid this issue? Note that I do not want to change anchor links to input buttons.
Instead of
{{ title }}
do
{{title|urlencode}}
Instead of hardcoding the URL and building the querystring in the template by concatenating the title context item, consider simplifying it a bit by using django.core.urlresolvers.reverse() and specifying a named URL from the relevant urls.py file. Makes for a clean design when you don't have to worry about URLs changing! Imagine the headache of all the scattered HREFs you'd have to change, versus simply assigning a context variable from the view set to the result of the reverse call. The querystring can be added nicely in the view too, without having to worry about some of the often strange template parsing rules. Note that the urllib.urlencode function acts completely differently to the template filter of the same name; don't get confused! It can be used as follows:
# If the entry in URLConf has named capture groups such as ?<pk>,
# pass a dict as kwargs parameter instead.
url = reverse('your-named-url', args=(1, 1)) # e.g '/question/tag/1/1/'
# Encodes as form data to 'list_id=Django+%2B+Python'
querystring = urllib.urlencode({'list_id': 'Django + Python'})
context['question_url'] = '{}?{}'.format(url, querystring)
Then, in the template it can be as simple as href="{{ question_url }}". It might seem like more work, but it can pay off very quickly and it's a much better separation of concerns. Normally I'd use the {% url "your-named-url" %} template tag, but it doesn't currently handle querystrings nicely -- as in, not in the same manner as it deals with URL args and kwargs defined in URLConf.

passing variable to django custom template tag

Im using django-profiles. In my profile_detail template I know that I will receive a profile variable.
I want to make a custom tag that gets the content per user via user id. Like this:
{% get_user_content book.review profile.user.id as review_list %}
However, when my parser runs It seems like profile.user.id was not transformed to an id number and throws an exception.
I can verify that my custom tag works by changing profile.user.id to say 1 for admin.
{% get_user_content book.review 1 as review_list %}
Has anyone deals with it before? What did you do?
Template tags never translate arguments. You need to do the lookup in the context yourself.