Reuse blocks of content on different pages


I recently discovered Grav and I am very happy that I finally found a clean and intuitive flat-file CMS. Thanks to the development team for creating this project!

In the roadmap of Grav 2 I can see that there is a plan of introducing Content Blocks and Widgets, but until we have them, I would like to know what is currently the best practice to reuse parts of content on different pages.

For example, I have a sidebar in which I would like to create some boxes which list links to external websites. In order to separate content and presentation, I created a page (pages/side_menus/ which lists all the links in the YAML FrontMatter section.

    - title: Social Networks
      active: true
        - title: Facebook
          url: #
        - title: Twitter
          url: #
        - title: Youtube
          url: #
    - title: Related Websites
      active: true
        - title: website1
          url: #
        - title: website2
          url: #
        - title: website3
          url: #

Then I created a twig tamplate called “sidebar.html.twig” in the ‘partials’ folder, with the following code:

{% set page = pages.find('/side_menus') %}
{% for menu in page.header.menus %}
    {% if %}
    <h1>{{ menu.title }}</h1>
        {% for link in menu.links %}
        <li><a href="{{ link.url }}">{{ link.title }}</a></li>
        {% endfor %}
    {% endif %}
{% endfor %}

I could have written the links with markdowns in the content area of the .md file, but I find it more structured in a YAML hierarchy and easier to manipulate from the template file. It also allows me to activate/deactivate a menu easily.

This works, but I have several concerns:

  • I first wondered where I should put the links. I did not want to write them directly in the template files which in my opinion should not contain any content. Then I thought about creating a plugin, but it seems overkill for a simple list of links… I finally decided to put them in the ‘pages’ folder, although technically they are rather a block to include in pages than a page in itself. Is there a better place to put them?
  • From the admin interface, it is strange to go to “pages” in order to edit these links. Additionally it is not possible to see on which pages those side menu will appear.
  • I find it strange to create a .md file without content (using only YAML inside the header). Isn’t it possible to just create a .yaml file?

In my understanding modular pages allow to create different areas within a page. This may look similar to what I want to do but I am more searching about a way to reuse blocks of HTML & content on different pages of the website.

I would be very happy to hear ideas and advice to achieve this in a better way.



1 Like

Great question. Content reuse at all granularities is a pillar of CMSs IMO (I’ve done courses on CMS selection, been on selection panels, and written formal evaluations against business requirements in the past). Looking forward to seeing what content blocks bring myself.

I’m not going to do justice to your considered concerns just right now. But I did contemplate this in depth when I ported the Minimaxing theme with demo content a little while back. I used modulars as a hack in a similar way to you, so you might want to take a look for further inspiration. Specifically:

I haven’t spend too much time considering Admin UI implications as yet, since none of my clients use it (but they and I both want them to). Empty markdown sections are a little ugly, yes, but that doesn’t keep me awake at night. Conscious design or not, it’s likely a trade-off of some sort.

So yeah, any reusable content that has no obvious relation with specific pages, I put in its own folder. You might also be interested in my thoughts about shoehorning this structure for a content API one day.

1 Like

Thank you for your reply. Your theme is a good example. It is reassuring to see that someone found a similar solution to what I did…

I also thought about gathering components inside a single folder, but when I first did it, they did not appear on the page. I just found out that I have to remove “visible: false” in the frontmaker (). According to the documentation this option should only affect the navigation, so I am not sure why it was preventing the block from showing…

Thank you also for sharing your thoughts (JSON data/catalogue API). I didn’t quite understand the JSON objects idea though…

I hope Grav 2 will allow creation of blocks in a separate folder that is not ‘pages’, and that we will have a different page on the admin panel to manage them. I think it is important to clearly distinguish pages & block as they are quite different in nature.

I’m myself quite new to Grav, so my advice is probably not worth much. I bookmarked this thread to learn about the answers. And I’m glad I did. Many thanks to @hughbris for sharing those ideas and pointers! I will myself come back to that in a later project.

@mathmax: In your particular case I would argue that the sidebar configuration is part of the theme configuration, so I would consider making it accessible there with blueprints. I haven’t done something like this myself yet, though.

I would still love to learn more about the other options, though. :slight_smile:

@Utis: Except maybe the “active” option in the hierarchy posted on my first post, the menus, titles and urls are all content, not configuration. So I am not sure how blueprints would be useful here… Could you explain more your idea?

Well, the way I understood you, they are part of a sidebar that is displayed on many pages. Maybe it’s an edge case and you could argue that it’s content. My feeling, however, is that it’s something that’s comes with a theme, as part of it’s page structure and is no more content than, say, a footer with links.

I haven’t really done this myself yet. But I mean adding something to your theme’s blueprint like this:

  validation: loose
      type: section
      title: Sidebar
      underline: true

          type: toggle
          label: Active
          highlight: 1
          default: 1
            type: bool

          type: list
          style: vertical
          label: Links
              type: text
              label: Title
              type: text
              label: URL

And then, when you click in the admin panel on “Themes” ==> you have a form to edit those links.

1 Like

@Utis: It’s a good idea to use a blueprint to allow adding/removing items from the admin panel. I haven’t yet played with blueprints either, and I am not really sure what would be the advantages to store the data at the theme level vs at the page level. My feeling is that, in this case, it is better to create a page blueprint rather than editing the configuration of the theme. You took the example of the footer, but I would also consider it as content. If you look at grav-skeleton-open-publishing-space-site, you will see that they created a “footer” page:

Now if I create side_menus.yaml, I can target my side_menu component and reproduce the same hierarchy as posted on my first post (note that I need to add prefix the field names for your file to work). The blueprint helps editing from the admin panel, but doesn’t change the way I structured my files.

Later, I may want to move the “active” options to a separate blueprint to be able to enable menus only on certain pages, while still having the links stored in a single place.

Thinking about this some more, I think I eventually agree: It’s maybe a better compromise to put the data in pages and maybe create a blueprint to edit them in forms.

But for me, in this case, it’s more a question of exposing a predictable interface to the end user. (In the end it’s always about interface, inside it’s just numbers at memory adresses.) IMHO, the concept of “themes” in the CMS world sits in an uneasy place anyways and is neither here nor there: Themes define not only appearance and viewer interaction, but also content structure and logic; and a site likely breaks when switching to another theme. Components are conceptually probably right in between “theme” and “page” (content). Personally, the fact that a component disappears when switching to another theme makes me inclined to put them more on the theme side.

That being said, in practise, for end users, making the data configurable in the theme’s config panel is probably far too hidden and difficult to find. Maybe if it’s just a single component, I’d still consider doing it. But if there’s several of them, creating pages in a components folder might indeed be better, especially if these provide forms. It’s not ideal, though, I can see end users looking at the pages panel, wondering whether and when they created these “pages”.

Ideally, components would have their own section in the admin panel right between “Pages” and “Themes”. With their data being stored in `user/components‘. Maybe that can be achieved with a plugin?

(Don’t know what you meant with “prefix the field names”; it worked for me.)

Yes, exactly. I agree that components are kind of “in between” theme and pages. Pages should be stable when switching from one theme to another, whereas components (or blocks) may change. I also think they should appear in a different section on the admin panel. For now, the best i could do is to gather them inside a ‘blocks’ folder which separates them a bit from normal pages although they still appear under ‘pages’ in the admin panel. I expect Grav2 to improve this… I believe that components are, like bricks, the basics of a well designed project.

Btw, i like how Magento handles components. Basically, you can define default components, override them per theme, and reference them through layout files (XML in the case of Magento). Layout files are part of a theme, but are not exactly templates: their role is just to bind sets of pages to various components, describing where they should be positioned on the pages.

By prefix, i mean adding ‘header.menus.[…]’ to the field names of the blueprints. Sorry i am on my mobile, so i can’t test it again now. Without prefix, you can fill the form in the admin panel, but you shouldn’t be able to save the data. Please give it a try.

1 Like