Unique page identifiers in Grav CMS - twig

I'm using the Grav CMS to create a modular web page; however, I'm having difficulty customizing the layout based on how the content is generated.
I've followed the documentation found Grav main site from which I've model my site after.
My folder structure is essentially:
pages
01.home
_section1
_section2
In each section folder I have my .md file. And each section is considered a sub-page of 'home'.
I've created the template file, modular.html.twig, in which I have the following code:
{% extends 'partials/base.html.twig' %}
{% block content %}
{% for child in page.children() %}
{{ child.content() }}
{% endfor %}
{% endblock %}
This code iterates through sub-pages to load the content onto the home page. In my template I'm simply printing the result of the content using {{ content }}
What I end up with is a page with vertically stacked content and repeating html,
as such.
What I want to do is uniquely define each sub-page (section) so that I can manipulate the content differently in my html, as such.
I've thought about creating separate template files for each section, but much of my content is nested.
For instance I have something akin to:
<div class="row">
<div class="section-1">
<h1>{{ content }}</h1> <!--Needs to be unique-->
</div>
<div class="section-2">
<h1>{{ content }}</h1> <!--Needs to be unique-->
</div>
</div>
Is it possible to accomplish what I'm trying to do with this framework? If so, how might I go about it?
Thank you

I think there are many ways to do this. For me, I use page's header to set CSS class of each section.
My section's md files could look like this (for example mysection.md)
---
title: Section 1
section_class: section-1
---
This is the content of section 1.
Here is my modular.html.twig:
{% extends 'partials/base.html.twig' %}
{% block content %}
<div class="row">
{% for child in page.children() %}
<div class="{{ child.header.section_class }}">
{{ child.content() }}
</div>
{% endfor %}
</div>
{% endblock %}
In my mysection.html.twig I print the section's content
<h1>{{ page.content }}</h1>
I hope this helps.

Related

Eleventy: Add pagination only to blog posts

In Eleventy, I have a simple layout file that I'd like to use for most pages on my website, including the blog collection. I'd like the layout to only add my pagination partial when in a blog post.
My attempt below doesn't add the pagination partial to any post. I know I need to modify the if statement, but I don't know how. Everything works fine if I don't include the if statement, but pages not in the blog collection get some of the code from partial, which I don't want.
Any suggestions?
---
layout: layouts/base.njk
---
<article>
<h1>{{ title }}</h1>
{{ content | safe }}
</article>
{% if post in collections.blog %}
{% include "partials/_pagination.njk" %}
{% endif %}
I got the answer from the Eleventy group on Discord:
---
layout: layouts/base.njk
---
<article>
<h1>{{ title }}</h1>
{{ content | safe }}
</article>
{% if "blog" in tags %}
{% include "partials/_pagination.njk" %}
{% endif %}

Symfony Twig block generation priority

I have a little problem in twig to render symfony forms,
so, first I will explain the context of it.
In Twig, blocks are defined in a certain order on a template:
{# base.layout.html.twig #}
{% block firstBlock %}
{% endblock firstBlock %}
{% block secondBlock %}
{% endblock secondBlock %}
And when we extends this template we can write this:
{# child.layout.html.twig #}
{% embed "base.layout.html.twig" %}
{% block secondBlock %}
{{ form_widget(form.submit_button) }}
{% endblock secondBlock %}
{% block firstBlock %}
{{ form_widget(form.some_field) }}
{{ form_rest(form) }}
{% endblock firstBlock %}
So the problem is with the form() functions in twig which renders Symfony forms.
I am trying to generate a submit button at the very end of a modal window
but the problem is that form_rest() renders all parts of the form not already rendered.
There is a little fix to avoid form_rest to render form.submit_button, it's to set form.submit_button as an already rendered field with:
{% do form.submit_button .setRendered %}
But with this form.submit_button is never rendered
Of course the finality of all this is to don't remove the form_rest instruction.
So I search something to unset rendered value of form.submit_button after the form_rest instruction or even better a way to choose the order of blocks generation of a template.
Like this:
{% block secondBlock with(1) %}
{{ form_widget(form.submit_button) }}
{% endblock secondBlock %}
{% block firstBlock with(2) %}
{{ form_widget(form.some_field) }}
{{ form_rest(form) }}
{% endblock firstBlock %}
Thank you for your help !
If it is just for a submit button, you can remove it from your form type and write it in html, it is'nt a problem, and it will work.
The problem is that you render first the rest (including the button), and after you try to render the button but it is already rendered...
Of course, your html button must be inside < form > tags.
If you want to keep your submit button from your form type,
1 solution is to move it using some javascript ...
2 solution is to mark it as rendered (as you have done), and write the exact html of your submit button in the place you want.
[edit]
You can also render every field of your form in the first block, render your submit button in the second block, and put form_rest after all these (as all the fields have been rendered, it will not have something to render,
this is a solution also)
If that's just a matter of a submit button that has no logic and no mapping at all, the easiest way is to render your submit button in HTML directly and removing it from your form.
<input type="submit" value="Submit"> {# ¯\_(ツ)_/¯ #}
Another solution is to put your modal in a modal_layout.html.twig, and then use the embed tag that is exactly made for this kind of issues.
modal_layout.html.twig
<div class="modal">
<div class="form">
{% block form_part %}{% endblock %}
</div>
<div class="submit pull-right">
{% block submit_part %}{% endblock %}
</div>
</div>
your_page.html.twig
{% embed 'modal_layout.html.twig' %}
{% block submit_part %}
{{ form_row(form.submit_button) }}
{% endblock %}
{% block form_part %}
{{ form(form) }} {# won't render submit again #}
{% endblock %}
{% endembed %}
But IMO the second solution, even if it appears cleaner, does not worth it for a stupid submit button.
Cheers

where is block/about-us coming from in bolt _aside.twig

I was just reading through content fetching in bolt HERE , which gave me a fair idea of how setcontent works. Now i came across the following code in _aside.twig template in the default bolt theme:
<div class="panel">
{# The next section attempts to fill the panel in the sidebar with the contents of the
'about-us'-block, if it exists. First, attempt to fetch the block with slug 'about-us' #}
{% setcontent block = "block/about-us" %}
{# check if we have a title. If so, we know we have content to display. Otherwise, we will
output a default text, telling the user to create the 'blocks' in the backend. #}
{% if block.title is defined %}
<h5>{{ block.title }}</h5>
{{ block.content }}
{% if link(block.contentlink) or block.editlink() %}
<p>
{{ link(block.contentlink, __('general.phrase.read-more')) }} /
{{ __('general.phrase.edit') }}
</p>
{% endif %}
{% else %}
<h5>{{ __('general.phrase.missing-about-page') }}</h5>
<p>{{ __('general.phrase.missing-about-page-block') }}</p>
{% endif %}
</div>
My question is about the below line of code:
{% setcontent block = "block/about-us" %}
Where is "block/about-us" coming from ??
it refers to a record with the slug about-us on the blocks ContentType. It's set up as a resource ContentType. You can read more about resource ContentTypes here:
https://docs.bolt.cm/3.1/howto/resource-contenttype

Cancelling parent template if variable is null in Twig

I'm new to Twig and I'm trying to figure out how to achieve the following.
I have an object with a set of properties that I want to render with different Twig templates depending on which type of property it is (text, images, date, etc).
I want to render them as follows:
<div class="row">
<div class="title">Title of property</div>
<div class="propertycontent">
//Specific property content depending on property type
</div>
</div>
My problem is that I can't figure out to skip the complete output if the property is not defined. I want to be able to use parent templates to take care of the "wrapping" of the rendered property content. Is it possible to use parent templates that returns nothing if the property value is undefined? Is there another good solution that does not rely on include "begin"/"end" for wrapping each template?
Thanks in advance.
Solution: Call parent with value(might be null) and title
Parent (propery_wrapper.twig):
{% if value %}
<div class="row">
<div class="title">{{title}}</div>
<div class="propertyContent">
{% block content %}{% endblock %}
</div>
</div>
{% endif %}
child (for height property):
{% extends 'property_wrapper.twig' %}
{% block content %}
{{ value.value|number_format(2, ',') }} m
{% endblock %}

Jekyll paginate blog as subdirectory

I'm using Jekyll for a static site and I'm trying to generate the blog as a subdirectory/subfolder:
http://example.com/blog
In the directory structure before running jekyll, this is blog/index.html.
I tried adding pagination by adding "paginate: 5" to _config.yml, but the generated url's were of the form:
http://example.com/page2/
i.e. no "/blog". This is fixed by:
paginate_path: /blog/page/:num
in _config.yml.
But the resulting generated pages at:
http://example.com/blog/page/2/
don't use blog/index.html as their layout. They use the root index.html. What's the point in even having the paginate_path option, then?
How do I get my blog at example.com/blog, with pagination, using Jekyll?
Use the destination key in your _config.yml file to set the base path where you want the output to be published to. For example,
paginate: 5
destination: _site/blog
Note that assuming your site is setup to server its root (e.g. "http://example.com/") from "_site" jekyll won't produce and "index.html" page at that location. Everything that jekyll builds will be under the "blog" directory, but that sounds like what you are after.
I found a fix via this page Basically it involves a bit of a hack to figure out if you are on the nth page of the blog and then includes a file that pulls in you blog section.
Create a file in _includes/custom/ called pagination. In that have your pagination code
<!-- This loops through the paginated posts -->
{% for post in paginator.posts %}
<h1>{{ post.title }}</h1>
<p class="author">
<span class="date">{{ post.date }}</span>
</p>
<div class="content">
{{ post.content }}
</div>
{% endfor %}
<!-- Pagination links -->
<div class="pagination">
{% if paginator.previous_page %}
Previous
{% else %}
<span class="previous">Previous</span>
{% endif %}
<span class="page_number ">Page: {{ paginator.page }} of {{ paginator.total_pages }}</span>
{% if paginator.next_page %}
Next
{% else %}
<span class="next ">Next</span>
{% endif %}
</div>
Now in your _layout/index.html add
{% if paginator.page != 1 %}
{% include custom/pagination %}
{% else %}
The original content of index
{% endif %}

Resources