Decoupling Shortcodes from Pages

@bep,
I was looking at Shortcodes last night with the intention of seeing if I could add the ability to render arbitrary content with Shortcodes. For example, I could create a template function similar to markdownify that rendered shortcodes. However, the Shortcodes are coupled with the Page. As far as I can tell, other than context within the Shortcode, the Page is only used for error messages in the Go code.

What is the feasibility of decoupling Shortcodes from Pages?

As you have spotted, it is easy to remove the Page dependency from the shortcode … but, I’m not sure you really want to go down that route.

There have been discussion (I think there is an open GH issue… ?) about what you’re talking about; and this would in my head be another template function. If it can reuse some functionality used in shortocdes, great, but then extract some common methods or similar.

That said, I think this is easier to discuss if you provide examples of what you try to do / some use cases.

This post went much longer than I intended. I’m not apologizing; just warning you. :wink:

The rationale for this feature is to provide options for scenarios similar to what @Murray_Thompson described a few days ago in the DRY thread.

In my situation at work, we’re trying to see if and how Hugo can accomplish what we need in order to replace our complex and expensive CMS-powered site. I’ll give you an example that’s similar at least in layout. Look at VMware’s vCloud Suite site. The content and layout problems you would need to solve in order to create the pages in that area (see the links below the title for the sub-pages) are the same problems we’re trying to solve.

So in this example, assume a content type of “vcloud-suite” with a project structure such as this:

content/
  vcloud-suite/
    features.md
    resources.md
    compare.md
    pricing.md
    gettingstarted.md 
layout/
  vcloud-suite/
    section.html
    single.html

Let’s ignore the section.html template and just focus on the single.html template. Take the VMware Getting Started page for example. What strategies would you employ to design the single.html template just for that page, let alone the others? Doesn’t the main content of each page belong with it’s matching content file (ie. gettingstarted.md)? On the Getting Started page, what would you say the “main content” is and how would you put that into Markdown? Or into the content file? If the “main content” is everything from the title to the Site Recover Manager section at the bottom, how would attack that? Part of the goal is to have fairly clean, concise, and coherent layout templates.

So, back to this feature request. Since the page.Content is really not modular or divisible, we were considering putting some content into the front matter as @Murray_Thompson describes. We can use markdownify or safeHTML to embed that content into the front matter, but we can’t use shortcodes in the front matter. We’re not sure that we would need to, but the same limitation applies to the data and get[JSON|CSV] features. So basically, we want to be able to use shortcodes in any content in the same way we can use Markdown anywhere with the markdownify template function.

From a practical standpoint, I’m still not sure if we will end up using Hugo on such a complex site, and even if we do end up using Hugo, I don’t know exactly how we would go about it. But as it stands right now, the only place that we can use shortcodes is in the page.Content. I just get the sense that we would need to pull content from other places to do complex layouts, and we’d like to have the ability to use shortcodes in these other data sources.

We’re still theorizing how far we can push Hugo and how to use all of the features…and maybe what features we would like to see implemented. Any advise would be appreciated.

PS: We’ve also had the idea of using shortcodes to divide some page.Content:

layouts/shortcodes/section.html:

<section{{ with .Get "class"}} class="{{.}}"{{ end }}>{{ .Inner }}</section>

content/test.md:

{{% section %}}
Awesome content block
{{% /section %}}

{{% section class="super-special-content" %}}
Another awesome content block...
{{% /section %}}

But at that point, we’re basically inserting layout into the content. Boo!

You are right, this was long! I have skimmed it … and the alternatives all look kind of hacky.

There is a GitHub issue about getting sections in pages. I was a little bit chilly about it, thinking that this has to be implemented in the Markdown engine … But since we support lots of different engines, that will never happen for all of them.

Since then I’ve been thinking, and there are two alternatives that will be fairly easy to implement and will keep the Hugo-speed:

1. Named sections:

  1. Pick a syntax that will survive markdown rendering to mark the start and end of the named sections.

  2. After Markdown rendering: Extract the slice boundaries (and maybe remove the section markers). Put this in the map PageSections or something.This should be both fast ande memory allocation “free”.

  3. Use it in templates: {{ index .PageSections "sidebar-content" }}

2. Multiple Content:

  1. Make up a syntax to mark a new content page.
  2. They will share front-matter, but will be rendered individually and put in a list.
  3. The .Content willl become a method that get the first page in this list.
  4. Contents (or the plural of content …) will be a rangeable list of content pages: index .Contents 1. If we add a key to the page divider, we can even make this a map: index .Contents "sidebar-content"

The second alternative will have some limitations in the Table of contents department, both of them may have some issues I haven’t thought about … But it is doable.

2 Likes