Zola: Allow shortcodes in shortcode bodies

Created on 5 Nov 2018  路  10Comments  路  Source: getzola/zola

If a short-code with a body is used in the body of a short-code it's {% end %} is matched with the outer short-code. This prevents the use of nested short-codes with bodies.

Use Case

I'm trying to write [reveal.js] presentations in Gutenberg currently and I have defined simple shortcodes for vertical slides, fragments, and notes:

<aside class="notes">
{{ body | safe | trim | markdown }}
</aside>
<section{%- if id %} id="{{id}}" {%- endif -%}
        {%- if attributes -%}
          {%- for attr in attributes %}{#
            #} {{attr.attribute}}="{{attr.value}}"
          {%- endfor -%}
        {%- endif -%}>
{{ body | safe | markdown(inline=true) }}
</section>
<span class="fragment">
    {{ body | safe | trim | markdown }}
</span>

This makes it easier to write slides like so:

+++
title = "Installation instructions"
+++

{% vertical_slide() %}
Main content

{% notes() %}
- notes on main content
{% end %}
{% end %}


{% vertical_slide() %}
Basement slide with extra content

{% notes() %}
- notes on basement content
{% end %}
{% end %}

Workaround

Of course I can just throw in html to work around this, but I find short-codes are more pleasant to work with, especially when I have more complicated things going on like figures with complex markup that I've created with short-codes showing up in vertical slides.

For example:

{% vertical_slide() %}
**Linux** (Ubuntu/Debian)

`sudo apt-get install git`

<figure class="toggle-figure">
    <span class="toggle-figure__button"></span>
    <img class="toggle-figure__figure" alt="`sudo apt-get install git`" src="img/gif/linux-install-git.gif"/>
</figure>

<aside class="notes">
- Linux typically comes with `git` installed
- `git` was created specifically to manage the Linux project
</aside>
{% end %}

However, this isn't ideal since the list inside the aside _is not rendered as markdown_.

enhancement good first issue help wanted

Most helpful comment

@Keats I will be more than willing to implement this once I am done with my current project.

All 10 comments

Having shortcodes inside shortcodes is very unlikely to happen imo, it doesn't feel great and would probably be a bit messy since there are already issues with the shortcodes <> markdown interactions in some cases (https://github.com/Keats/gutenberg/issues/479)

If you have time you could write the code and I will have a look ('m not promising to merge it just to be clear).

Is there anyone wanting to implement that? It looks like most of the work is actually parser-related, in components/rendering/shortcode.rs and the content.pest file in the same folder.

@Keats I will be more than willing to implement this once I am done with my current project.

Hi y'all,

Thanks for all of your efforts with Zola -- I really enjoy building sites with it! I just thought I'd chime in to say that I, too, would absolutely love to see nested shortcodes.

Obviously, I don't have the same perspective as you, @Keats, but for me personally, I think this feature would make the interaction with markdown much more natural -- right now, I'm writing a lot of repetitive HTML on my site, and I think that (a) nested shortcodes would actually simplify the page code greatly and (b) actually _improve_ the interaction with markdown because inserting HTML breaks parsing, too.

I would also be thrilled to help with this (@creikey, would love to join forces or support you in any way!), but not being familiar with rust nor pest (humble web dev here 馃槈), I'm not sure how to get started. My very naive impression is that shortcode_with_body and text_in_body_sc in components/rendering/src/content.pest would need to be adapted to allow for nested shortcodes (so text_in_body_sc would be able to include shortcode_with_body as well as inline_shortcode), and render_shortcode in components/rendering/src/shortcode.rs would need to run recursively. Would that be a starting point?

Thanks a bunch, and again, please don't hesitate to let me know if I can help with this! (maybe I could try to make a test case #479?)

-Felix

Thanks for the kind words!

Regarding the work to be done, I am not 100% sure as I haven't a look at that in ages. I think you nailed the parser changes but it's likely to be more complex when rendering them than just running recursively. I think https://github.com/getzola/zola/blob/fa0cf05fe0ab911a7e59c27cc7ab80fbcc9eff2c/components/rendering/src/shortcode.rs#L173 will need to be extracted to another function and https://github.com/getzola/zola/blob/fa0cf05fe0ab911a7e59c27cc7ab80fbcc9eff2c/components/rendering/src/shortcode.rs#L185 will need to call it instead of taking everything as a string.
It doesn't look too hard but you never know...

Hej, thanks a lot for your super-quick and kind response ... and no worries, this is the absolute least I can do!

I'm really enjoying working with Zola, and it's been an immense help with a new website I've been setting up -- I'd love to explore abstracting away some common elements that take up a lot of space in the code, and see whether that would make sense for Zola in general.

As noted above, I'm new to Pest and Rust, so I can't make any promises, but I'll play around with the pest online editor over the coming days to see whether I can get the parser running, and then maybe I'll have a go at the rendering code.

@creikey Please let me know if you'd like to take over, I wouldn't want to steal this from you if you've already made plans.

@FelixHenninger I am very busy with Naval Battle and Godot Engine as of now, unlikely I'll start working on this in the near future.

This would make pages with columns much simpler

This is something that I too have been looking for in static site generators without success (I'm currently using Hugo). My use case is documentation, e.g.:

{{% note %}}
Read more about {{ doc "nginx#anchor" }} and see these {{ file "snippet.conf" "custom settings" }}.
{{% end %}}
  • The note code could expand to a <div>, itself containing header and body <div>s.
  • The doc code might search for nginx.md in the document tree, fetch its frontmatter title, embed the anchor in the href, but obscure it in the link text.
  • The file code might look in a custom data directory, produce a <span> with a file icon and become red (or throw an error at build time) if the file isn't found.

There are a lot of possibilities that allow one to write concise documentation. Having to use inline HTML or do manual validation is terrible for productivity, and any changes to recurring elements would have be reapplied in every document, instead of a single template file.

@Th3Whit3Wolf I have exactly the same use case! We currently have a workaround (shown below) by creating a .md file for each column and using the paginator, but it would be nice to be able to create rows and columns from within the same markdown file.

{% block content %}
  <!-- Main Content -->
  <div class="container">
    <div class="row">
      {% for page in paginator.pages %}
      {% if page.extra.col %}
      <div class="col-md-{{page.extra.col}} col-sm-12 mx-auto">
      {% else %}
      <div class="col-md-4 col-sm-12 mx-auto">
      {% endif %}
        <h2>{{ page.title }}</h2>
        {{ page.content | safe }}
      </div>
      {% endfor%}
    </div>
    {% endblock content %}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

svenstaro picture svenstaro  路  5Comments

seanomlor picture seanomlor  路  4Comments

Keats picture Keats  路  7Comments

snsvrno picture snsvrno  路  4Comments

NuLL3rr0r picture NuLL3rr0r  路  6Comments