Pebble Templating Engine

repository·master·Indexed 22 days ago

https://github.com/pebbletemplates/pebble

A Java-based templating engine inspired by Twig, featuring template inheritance, internationalization, and built-in autoescaping for security. It provides a compilation pipeline consisting of a Lexer, Parser, and Node Tree, and offers integrated support for Spring Boot via dedicated starters.

Tokens
27.6K
Snippets
127
Records
171
Agent score
78%

What's inside Pebble

  1. Configure the default Template Loader in Pebble 4.1.x

    master

    Starting with Pebble version 4.1.0, if you do not provide a custom Loader, Pebble defaults to using only a ClasspathLoader.

    Previously, Pebble used a DelegatingLoader (which combined ClasspathLoader and FileLoader) by default. If your application relies on loading templates from the file system rather than the classpath, you must now explicitly provide a FileLoader or a custom implementation to the PebbleEngine.

    // Example: Explicitly providing a FileLoader if you need file-system access
    // (Note: Exact API usage depends on your specific Pebble version/implementation)
    PebbleEngine engine = new PebbleEngine.Builder()
        .loader(new FileLoader(new File("/path/to/templates")))
        .build();
  2. Handle escaping and XSS protection

    master

    Pebble enables autoescaping of all data by default to prevent XSS vulnerabilities. It assumes an HTML context.

    • Manual Escaping: If autoescaping is disabled, use the {{ value | escape }} filter.
    • Context-specific Escaping: You can specify an escaping strategy (e.g., for JavaScript) using the strategy argument: {{ value | escape(strategy="js") }}.
    {# Manual escaping in a JS context #}
    <script>var username="{{ danger | escape(strategy="js") }}"</script>
  3. Implement template inheritance with blocks

    master

    Template inheritance allows child templates to override specific sections of a parent template using {% block %} tags.

    1. In the parent template, define sections using {% block name %}...{% endblock %}.
    2. In the child template, use {% extends "parent.html" %} as the very first tag.
    3. Override sections in the child using {% block name %}...{% endblock %}.

    If a child does not override a block, the parent's content is used. You can also use dynamic expressions in the extends tag.

    {# Parent Template (parent.html) #}
    <html>
    <head>
        <title>{% block title %}Default Title{% endblock %}</title>
    </head>
    <body>
        {% block content %}{% endblock %}
    </body>
    </html>
    
    {# Child Template #}
    {% extends "parent.html" %}
    
    {% block title %}Home{% endblock %}
    
    {% block content %}
        <h1>Welcome Home</h1>
    {% endblock %}
    
    {# Dynamic inheritance example #}
    {% extends ajax ? 'ajax.html' : 'base.html' %}
  4. Control flow with for loops and if statements

    master

    Pebble uses {% ... %} tags for control structures like loops and conditionals.

    {# For loop with an optional else block #}
    {% for article in articles %}
        <h3>{{ article.title }}</h3>
        <p>{{ article.content }}</p>
    {% else %}
        <p> There are no articles. </p>
    {% endfor %}
    
    {# If/Elseif/Else conditional #}
    {% if category == "news" %}
        {{ news }}
    {% elseif category == "sports" %}
        {{ sports }}
    {% else %}
        <p>Please select a category</p>
    {% endif %}
  5. Use loop special variables in `for` loops

    master

    Inside a for loop, Pebble provides a loop object containing metadata about the current iteration state:

    • loop.index: A zero-based index that increments with every iteration.
    • loop.length: The total size of the object being iterated over.
    • loop.first: Returns True if the current iteration is the first one.
    • loop.last: Returns True if the current iteration is the last one.
    • loop.revindex: The number of iterations remaining from the end of the loop.
    {% for user in users %}
    	{{ loop.index }} - {{ user.id }}
    {% endfor %}
  6. Use the `extends` tag for template inheritance

    master

    The extends tag allows a child template to inherit the structure of a parent template.

    Rules for usage:

    1. The {% extends "parent_name" %} tag must be the very first tag in the child template.
    2. A child template can extend only one parent template.
    3. Parent templates define content areas using {% block name %}...{% endblock %} tags.
    4. Child templates override these areas by defining a block with the same name: {% block name %}...{% endblock %}.
    5. If a child template does not override a block, the content from the parent template is used by default.

    You can create deep inheritance chains (a child extending a child) to build a hierarchy of templates and minimize code duplication.

    /* Parent Template (base.html) */
    <html>
    	<head>
    		<title>{% block title %} {% endblock %}</title>
    	</head>
    	<body>
    		<div id="content">
    			{% block content %} Default content {% endblock %}
    		</div>
    	</body>
    </html>
    
    /* Child Template (home.html) */
    {% extends "base" %}
    
    {% block title %} Home {% endblock %}
    
    {% block content %} Home page content. {% endblock %}
  7. How autoescaping works in Pebble

    master

    To prevent XSS vulnerabilities, Pebble enables autoescaping by default. This means any expression inside print delimiters {{ ... }} will have its output automatically escaped.

    Exceptions to autoescaping:

    • String Literals: Expressions containing only a string literal (e.g., {{ '<br>' }}) are treated as safe and not escaped.
    • Safe Output: If the last operation in an expression is a filter or function that returns a SafeString (such as date, escape, or raw), the autoescaper will ignore it.

    Important: For the raw filter to work as intended, it must be the final operation in the expression chain. If you apply another filter after raw, the output will be re-escaped.

    {# Automatically escaped #}
    {% set danger = "<br>" %}
    {{ danger }}
    
    {# Not escaped because 'raw' is the last operation #}
    {{ danger | raw }}
    
    {# Re-escaped because 'uppercase' is the last operation #}
    {{ danger | raw | uppercase }}