Open faulesocke opened 6 years ago
I have no strong feeling about that. I don't really see the usecase though so I'd like to see more people wanting that
Probably the most common use case is for the page title as seen in the stackoverflow thread. Of course one can easily work around this, but I thought it would be nice, if I (and others) don't have to.
Probably the most common use case is for the page title as seen in the stackoverflow thread.
Yes, that's a very common use-case. I also had to scratch my head around it when making a Hugo theme. I just don't understand the logic of not being able to reuse a block elsewhere in the template ^^" (is there an actual reason?)
I just don't understand the logic of not being able to reuse a block elsewhere in the template ^^" (is there an actual reason?)
In the first template of the stackoverflow, thetitle
block is defined twice. When using the title
block in a child template, which one should the template engine inherits from? The template engine has no way of knowing which one so that's the reason you go through self
in Jinja2
that's the reason you go through self in Jinja2
Thanks for the explanation! Am i wrong to think this could also be addressed differently by using a separate function for overriding the block? (such as define in Hugo)
Define in Hugo is just block in Tera. What you need is a way to render the content of a block, not redefine it. I'm not sure if the golang template engine has a way to do that
On Mon, 6 Aug 2018, 20:06 cmal, notifications@github.com wrote:
that's the reason you go through self in Jinja2
Thanks for the explanation! Am i wrong to think this could also be addressed differently by using a separate function for overriding the block? (such as define in Hugo https://gohugo.io/templates/base/#override-the-base-template)
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/Keats/tera/issues/265#issuecomment-410798820, or mute the thread https://github.com/notifications/unsubscribe-auth/AApho5BDIp3dYBPNtrAon9lRlokjgj7fks5uOIWVgaJpZM4SYYlx .
What you need is a way to render the content of a block, not redefine it.
Yes, I meant that we need different keywords for defining and using a block. Sorry if i wasn't clear. I understand that it would make sense in order to avoid a breaking change to have define a {% useblock BLOCK %}
feature. Would that be hard to implement?
I think the title example from stackoverflow is a clear example of why people would want this. Are variables the appropriate way to deal with such issues? (I'm not sure about the flow of data of a template to/from other templates it extends)
I would definitely propose the useblock
syntax since this ambiguity is one of the most disgusting things in jinja2.
Woops didn't see @paulcmal message
I think useblock
makes sense and shouldn't be too hard to implement
What's wrong with the {{ self.block_name() }}
syntax?
Here's an example where title
, description
, site
and url
are used >1 time on a regular page that doesn't want to look like garbage on social media:
<!DOCTYPE html>
<html lang="en">
<head>
<title>{% block title %}{% endblock title %}</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="{% block description %}{% endblock description %}" />
<meta name="author" content="{% block author %}{% endblock author %}" />
<meta name="keywords" content="{% block keywords %}{% endblock keywords %}" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta property="og:site_name" content="{% block site %}{% endblock site %}" />
<meta property="og:title" content="{% block title %}{% endblock title %}" />
<meta property="og:url" content="{% block url %}{% endblock url %}" />
<meta property="og:description" content="{% block description %}{% endblock description %}" />
<meta property="og:image" content="{% block og_image_src %}{% endblock og_image_src %}" />
<meta property="og:image:alt" content="{% block og_image_alt %}{% endblock og_image_alt %}" />
<meta property="og:type" content="{% block type %}{% endblock type %}" />
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:site" content="{% block site %}{% endblock site %}" />
<meta property="twitter:title" content="{% block title %}{% endblock title %}" />
<meta property="twitter:description" content="{% block description %}{% endblock description %}" />
<meta property="twitter:image" content="{% block twitter_image_src %}{% endblock twitter_image_src %}" />
<meta property="twitter:creator" content="{% block twitter_author %}{% endblock twitter_author %}" />
<link rel="canonical" href="{% block url %}{% endblock url %}" />
{% block extra_head %}
{% endblock extra_head %}
</head>
<body>
{% block content %}{% endblock content %}
</body>
</html>
Naturally, this breaks on the "can't have multiple whatevers".
Do y'all have a suggested workaround for this?
You can set
the variables once depending on the variables present and render them.
Eg
{% if page %}
{% set title = page.title %}
{% else %}
...
{% endif %}
...
<meta property="og:title" content="{{title}}" />
Thanks for the quick reply, @Keats! I'll give this a roll later today
@Keats Is what you suggested possible in a template that is being extended from another template? For example, what is above is my base.html
, and here is post.html
:
{% extends "base.html" %}
{% block author %}{{author}}{% endblock author %}
{% block description %}{{description}}{% endblock description %}
{% block keywords %}{{keywords}}{% endblock description %}
{% block site %}{{site}}{% endblock site %}
{% block title %}{{title}}{% endblock title %}
{% block twitter_author %}{{twitter_author}}{% endblock description %}
{% block type %}article{% endblock type %}
{% block url %}{{url}}{% endblock url %}
{% block content %}
<!-- some stuff here -->
{{content_html | safe}}
{% endblock content %}
and I'm trying to get base.html
to use these values of title
, description
and url
in a few places in base.html
Yep, it should work
I can't seem to get that concept to work when I'm rendering post.html
with data, providing it to a block, and trying to use it a few times in base.html
.
I'm not rendering base.html
, but I am extending it and trying to send it variables.
I do think it is this same issue of "Allow block to be used multiple times". How else can you render template2, which extends template1, and have template1 use an inserted variable from template2 more than 1 time?
Thank you for your time, and I can stop bothering you if this is annoying!
The way the template engine works, it will start rendering the base template (base.html
) in all cases going through blocks. So if you define anything in the base.html
, whether you're rendering template2 or template1 doesn't matter since the context will be what you care about.
If you have an example repo I can have a look
It looks like rpearce was trying to set something in post.html which extends from base.html which would then need to be used in base.html.
If you're using Zola you run into this situation.
If I do something like this:
index.html:
<title>{% block title %}{{ config.title }}{% endblock title %}</title>
page.html (which extends from index.html):
{% block title %} {{ page.title }} | {{ config.title }} {% endblock title %}
It works for setting the title block contents from page.html.
If instead I use a variable:
index.html:
{% set title_example = config.title %}
<title>{{ title_example }}</title>
page.html:
{% set title_example = page.title ~ ' | ' ~ config.title %}
There are no errors, but the value of title_example
used in page.html is not used.
In this example page.title
is not available in index.html.
An alternative approach is:
page.html:
{% set title_example = config.title %}
{% if page and page.title %}
{% set title_example = page.title ~ ' | ' ~ config.title %}
{% endif %}
<title>{{ title_example }}</title>
<!-- other stuff here -->
<meta name=”twitter:title” content=”{{ title_example }}” />
This approach requires hardcoding specific cases where the title is used into index.html instead of having them be the responsibility of the child templates so it isn't great either.
What's wrong with the {{ self.block_name() }} syntax?
I find it hard to understand what self
is there. Can I also render imported macros that way? Or render variable set in that template.
@LunNova did you figure out this?
Nothing better than the example at the bottom there :/
Thanks @LunNova , I finally handle all these cases on base.html
{%- block social_meta -%}
{%- if page.title -%}
{%- set_global title = page.title -%}
{%- elif term.name -%}
{%- set titled_type_name = taxonomy.name | title -%}
{%- set_global title = titled_type_name ~ " | " ~ term.name -%}
{%- elif taxonomy.name -%}
{%- set_global title = taxonomy.name | title -%}
{%- elif section.title -%}
{%- set_global title = section.title -%}
{%- endif -%}
{%- if title -%}
{%- set_global full_title = title ~ " - " ~ config.title -%}
{%- elif is_index == true -%}
{%- set_global title = config.title -%}
{%- set_global full_title = config.title -%}
{%- endif -%}
{%- if page.description -%}
{%- set_global description = page.description -%}
{%- elif page.summary -%}
{%- set_global description = page.summary | spaceless | striptags -%}
{%- elif page.content -%}
{%- set_global description = page.content | spaceless | striptags | truncate(length=200) -%}
{%- elif is_index -%}
{%- set_global description = config.description -%}
{%- elif section.content -%}
{%- set_global description = section.content | spaceless | striptags | truncate(length=200) -%}
{%- else -%}
{%- set_global description = config.description -%}
{%- endif -%}
{%- if page.extra.image -%}
{%- set_global image = page.extra.image -%}
{%- elif is_index and config.extra.image -%}
{%- set_global image = config.extra.image -%}
{%- elif page.assets -%}
{%- for asset in page.assets | sort -%}
{%- if asset is matching("[.](jpg|png|jpeg)$") -%}
{%- set_global image=get_url(path=asset) -%}
{%- break -%}
{%- endif -%}
{%- endfor -%}
{%- endif -%}
<title>{{full_title}}</title>
<meta property="og:title" content="{{title}}"/>
<meta itemprop="headline" content="{{title}}"/>
<meta property="og:description" content="{{description}}"/>
<meta name="description" content="{{description}}"/>
<meta property="og:url" content="{{current_url | safe}}"/>
{%- if image -%}
<meta name="og:type" content="summary_large_image"/>
<meta property="twitter:card" content="summary_large_image"/>
<meta property="og:image" content="{{ image }}"/>
<meta property="og:image:alt" content="{{ title }}"/>
{%- else -%}
<meta name="og:type" content="summary"/>
{%- endif -%}
{%- endblock social_meta -%}
Instead of trying to do this, which isn't allowed:
<!-- base.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<!-- We can't use the same `title` block twice -->
<title>{% block title %}{% endblock title %}</title>
<meta property="og:title" content="{% block title %}{% endblock title %}" />
</head>
<body>
{% block content %}{% endblock content %}
</body>
</html>
<!-- page.html -->
{% extends "base.html" %}
{% block title %}{{ page.title }}{% endblock title %}
{% block content %}{{ content_html | safe }}{% endblock content %}
We can instead do this:
<!-- base.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<!-- This imports the variables that are set in the block in page.html
and they're accessible anywhere below this block/endblock line -->
{% block head_variables %}{% endblock head_variables %}
<title>{{ title }}</title>
<meta property="og:title" content="{{ title }}" />
</head>
<body>
{% block content %}{% endblock content %}
</body>
</html>
<!-- page.html -->
{% extends "base.html" %}
{% block head_variables %}
{% set title = page.title %}
<!-- You can set more variables here as you wish -->
{% endblock head_variables %}
{% block content %}{{ content_html | safe }}{% endblock content %}
It should be possible to use a block multiple times in the template. This is possible in jinja2, because a block can be accessed through the special
self
variable as described for example here:https://stackoverflow.com/questions/20929241/how-to-repeat-a-block-in-a-jinja2-template