Navigate through nested yaml list with liquid - menu

I've seen a few questions about this topic but none could solve my problem. I want to have a multilingual jekyll site without using any plugin. I have a yaml file with this nested list
menu:
fr:
home:
name:"Acceuil"
url:"/"
team:
name:"Équipe"
url:"/equipe"
en:
home:
name:"Home"
url:"/home.html"
team:
name:"Team"
url:"/team"
I'd like to print a different menu depending on the page lang option in the yaml front matter. A minimal exemple would be:
---
lang: en
---
<ul>
{% for item in site.menu.[page.lang] %}
<li>{{ item[1].name }}</li>
{% endfor %}
</ul>
and this should print in raw html
Home
Team
But instead my code prints nothing, I just have two bullets with no text. I can't see what I'm doing the wrong way, could you guys help me ?
Edit:
Ok, my only problem was just that I didn't put space between the value indicator and the value. Now the problem is solved. Thanks !

Add a whitespace between colons and values in the menu file, according to the YAML specification:
YAML insists the “:” mapping value indicator be separated from the
value by white space.
Also remove the menu: key and save the menu in a file called _data/menu.yml.
fr:
home:
name: "Acceuil"
url: "/"
team:
name: "Équipe"
url: "/equipe"
en:
home:
name: "Home"
url: "/home.html"
team:
name: "Team"
url: "/team"
Then you can access that data with site.data.menu accessing directly to the lang key without a . between menu and page.lang:
<ul>
{% for item in site.data.menu[page.lang] %}
<li>{{ item[1].name }}</li>
{% endfor %}
</ul>
This generates:
<ul>
<li>Home</li>
<li>Team</li>
</ul>
I've used a similar approach in a multilingual site with nav.yaml and a langnav.html include.

Related

How can I create a multi-page blog post in Jekyll?

I am trying to re-create this Wordpress blog post on Jekyll. The post is made up of images with descriptions, with 5 or 6 such images per page.
I created the page with a Wordpress pagination plugin. Jekyll uses a paginate plugin to paginate blog menus, but it seems I cannot re-use that for a single blog post because:
the number of items per page must be hard-coded in _config.yml
I don't have the same number of elements on every page of my blog post anyway
I use a script to create this post, so I can use HTML, markdown, whatever. I could also make a separate file for each page--and hopefully, figure out how to direct Jekyll to find them without the date prefix.
I don't know Javascript or Ruby, but I can mostly find my way around. What I really need to know is which strategy to take so I can work toward that instead of spending all morning on something that won't work well.
So, how would you do it?
Here's my idea of what it could look like in Jekyll. This is a hack with some potential issues.
TL;DR
The blog post you have shared is using two different layouts for the start page and the subpages. The index has a different position for the menu and the intro. Also, the page content differs.
Good news: Jekyll has layouts, powerful collections (beside posts), as well as includes to reuse content. See the details with some notes below. I have also added short post about the solution to my own blog.
You need two layouts
_layouts\paginated-post.md
---
---
<p>tags here</p>
<h2>{{ page.title }}</h2>
<!-- page menu -->
<ul>
<li>{{ page.title }}</li>
{% for item in page.page_urls %}
<li>{{ item.title }} Palettes</li>
{% endfor %}
</ul>
{{ content }}
<h2>Pages</h2>
<ul>
<li>1</li>
{% for item in page.page_urls %}
{% assign page_number = forloop.index | plus: 1 %}
<li>{{ page_number }}</li>
{% endfor %}
</ul>
_layouts\paginated-post-index.md
---
---
<p>tags here</p>
<h2>{{ page.title }}</h2>
I created Artificial Intelligence to produce these palettes ...
<h2>Menu</h2>
<!-- page menu here -->
<ul>
<li>{{ page.title }}</li>
{% for item in page.page_urls %}
<li>{{ item.title }} Palettes</li>
{% endfor %}
</ul>
{{ content }}
<h2>Pages</h2>
<ul>
<li>1</li>
{% for item in page.page_urls %}
{% assign page_number = forloop.index | plus: 1 %}
<li>{{ page_number }}</li>
{% endfor %}
</ul>
Add a new collection
_config.yml
Note: I have chosen permalink path here, the defaults are optional if you set a layout in each collection item). Learn more about Jekyll collections in the docs.
collections:
palettes:
output: true
permalink: /:path/
defaults:
- scope:
path: ""
values:
layout: paginated-post
New collection folder (_palettes) with two files:
The index on each page defines the palettes index.
_palettes\index.md
---
layout: paginated-post-index
title: AI-Generated Palettes
index: palettes-index
page_urls:
- title: Wes Anderson
palette: Kind of Bird
url: /wes-anderson-kind-of-bird/
---
{% include palettes/wes.html %}
_palettes\wes-anderson-kind-of-bird.md
---
title: AI-Generated Palettes
subtitle: Wes Anderson – Kind of Bird
index: palettes-index
page_urls:
- title: Wes Anderson
palette: Kind of Bird
url: /wes-anderson-kind-of-bird/
---
{% include palettes/wes.html %}
Include file used above in _includes\palettes\wes.html
Note: the first line is the only line which will cause issues in other palette include files - maybe you will find your own solution or can just adjust the index here.
<h2>{{ page.page_urls[0].title }} </h2>
image here
Merin’s Fire: ff9506
Trojan Horse Brown: 7b571e
Minestrone: c4280d
Punch of Yellow: efd185
Root Brew: 2b0f0b
Green Ink: 12887f

Grav - Retrieving specific items from page in template

I have the following page structure in Grav:
# Title
## Subtitle
### Subsubtitle
The page structure is always the same and it has just those three items.
How can I retrieve each item (Title/Subtitle/Subsubtitle) separately in Twig template?
The twig template will then do things like:
<p> You typed {{ page.whatever_retrieves_the_title_# }} as title, then {{ page.whatever_retrieves_the_subtitle_## }} as subtitle and finally {{ page.whatever_retrieves_the_subsubtitle_### }} as subsubtitle</p>
What if instead of the above structure I have:
- Title
- Subtitle
- Subsubtitle
The objective is that the user adds just that structure of three items and the twig template use each item to display a more complex layout.
This is Markdown, right?
# Title
## Subtitle
### Subsubtitle
You can get the HTML version of the page's Markdown in Twig with {{ page.content }}, as described in Grav's documentation. So you should get something like this:
<h1>Title</h1>
<h2>Subtitle</h2>
<h3>Subsubtitle</h3>
You can use the split and raw filters to extract the contents of those tags. I'm also using the default filter so that there won't be an error if the extraction of the tag contents fails:
Title is:
{{ page.content|split('<h1>')[1]|default|raw|split('</h1>')[0] }}
Subtitle is:
{{ page.content|split('<h2>')[1]|default|raw|split('</h2>')[0] }}
Subsubtitle is:
{{ page.content|split('<h3>')[1]|default|raw|split('</h3>')[0] }}
Or because Grav seems to provide a regex_replace filter, you could also use it:
Title is:
{{ page.content|regex_replace('~.*<h1>(.*)</h1>.*~s', '$1') }}
Subtitle is:
{{ page.content|regex_replace('~.*<h2>(.*)</h2>.*~s', '$1') }}
Subsubtitle is:
{{ page.content|regex_replace('~.*<h3>(.*)</h3>.*~s', '$1') }}
If instead you have this:
- Title
- Subtitle
- Subsubtitle
You can again use the split, default and raw filters:
Title is:
{{ page.content|split('<li>')[1]|default|raw|split('</li>')[0] }}
Subtitle is:
{{ page.content|split('<li>')[2]|default|raw|split('</li>')[0] }}
Subsubtitle is:
{{ page.content|split('<li>')[3]|default|raw|split('</li>')[0] }}
Not very beautiful. :-) If the titles can contain HTML (e.g. ## Hello **world**! → <h2>Hello <strong>world</strong>!</h2>) or special characters, you probably need to append |raw to the already long magic spells.
Others provided good solution with markdown manipulation. However, you could use grav features and provide your own blueprints, and have your user fills some fields.
Let's say this is for a page that uses the template blog_article.html.twig, you can therefore create a file named blog_article.yaml inside user/themes/yourtheme/blueprints and fill it with the following blueprint:
title: Blog_Article
'#extends':
type: default
context: blueprints://pages
form:
fields:
tabs:
fields:
content:
fields:
header.mytitle:
type: text
label: My Label
header.mysubtitle:
type: text
label: Type Subtitle
header.mysubsubtitle
type: text
label: Type subsubtitle
Now, if you try to edit your page from admin, you will see three new fields added to the page, under the page medias.
You can then display these fields in your template with the following twig:
{{ page.header.mytitle }}
{{ page.header.mysubtitle }}
{{ page.header.mysubsubtitle }}
Hope it helps

OpenCart 3.x - including a new template file

I need to add a new OpenCart template file into another template file.
Essentially I've created a new head file in /theme/customtheme/template/common/ called "header_home.twig".
Then in home.twig, I've changed {{ header }} to say {{ header_home }}, but it's not displaying anything.
Basically, all I did was copy header.twig and rename it to header_home.twig, and put in "xxxxx" to see if it was calling the new file, which it's not. Instead, it's not displaying anything.
Here's what my home.twig now looks like:
{{ header_home }}
<div id="common-home" class="container">
<div class="row">{{ column_left }}
{% if column_left and column_right %}
{% set class = 'col-sm-6' %}
{% elseif column_left or column_right %}
{% set class = 'col-sm-9' %}
{% else %}
{% set class = 'col-sm-12' %}
{% endif %}
<div id="content" class="{{ class }}">{{ content_top }}{{ content_bottom }}</div>
{{ column_right }}</div>
</div>
{{ footer }}
I assume I'm somehow missing a step when it comes to adding a new template file? If someone could help me with adding in a new twig file, that would be fantastic.
You can either:
Change the name of Twig rendering template on the OpenCart level in the controller/common/header as #bogalakon pointed out (preferably to do this via ocmod so that your future OpenCart updates will not overwrite your hack).
or include another template on the Twig level
I.e.:
{{ header }} {# Original rendered to HTML OpenCart header - you can move it to your header_home.twig or just drop it #}
{% include customtheme/template/common/header_home.twig %}
<div id="common-home" class="container">
...
Twig is very powerful template language. And you can do much more than just a simple include! It's nice that OpenCart officially accepted it. But for now it's just Twig 1.24.2. Please refer to the Twig documentation.
I haven't learn OpenCart 3.x, but I guess you need to change
return $this->load->view('common/header', $data);
to
return $this->load->view('common/header_home', $data);
in catalog/controller/common/header.php.
In order to connect another template via the {{header_home}} construct, you need to create the header_home.php in the folder /controller/common/directory, create the header_home.twig file in the theme /*theme_name*/template/common/ folder and in the controller , which is responsible for the formation of the page, for example in the directory /controller/common/home.php
add a line:
'$ data [' header_home '] = $ this-> load-> controller (' common / header_home '); '
before:
'$ this-> response-> setOutput ($ this-> load-> view (' common / home ', $ data)); '
To add your own custom twig file and include it inside another existing one you need to do three things:
Create the actual custom twig file.
In your case it will be:
catalog/view/theme/customtheme/template/common/header_home.twig
Create a controller for that twig file. In your case you can just copy:
/catalog/controller/common/header.php and rename that to header_home.php. Edit this controller and change the class name to ControllerCommonHeaderHome usually on line 2.
Lastly, since you are going to include header_home inside home.twig, edit /catalog/controller/common/home.php and add the line $data['header'] = $this->load->controller('common/header_home'); after $data['header'] = $this->load->controller('common/header');
That's it. After you've done the steps above, you can now include {{ header_home }} inside home.twig. If you are editing the files directly, I find that sometimes I need to login to the admin of the website, go to design>theme editor, open up the files I added or changed, hit reset, and save. Refresh your website and you should see the changes.
The answer of #bogalakon is right but if you update your OpenCart core files you will lose your changes so, I suggest you to copy the header.php controller file and rename it to header_home.php and then edit the file and replace the line
return $this->load->view('common/header', $data);
with:
return $this->load->view('common/header_home', $data);
There are several ways to give a different value.
For example:
Consider the controller
$data['header'] = $this-> load-> controller ('common / header');
A variable {{header}} is available in the template
You can place a new template in another file (header_home.twig), and then you can immediately download a new template for use:
$data['**header**'] = $this-> load-> controller ('common / ***header_home***');
If you want use {{header}} in the template.
Or,
$data['**header_home**'] = $this-> load-> controller ('common / header_home');
For use {{header_home}} in the template.

Twig direct include doesn't work, only "with"ing specific keys does

I'm using Pattern Lab with twig templates and having an issue with using objects directly in the with statement in includes.
This is my teaser-content-blocks organism:
{% set content_blocks = [
{
teaser_photo: {
url: 'https://img.buzzfeed.com/buzzfeed-static/static/enhanced/terminal01/2011/3/29/17/enhanced-buzz-14894-1301433714-5.jpg',
alt: 'Man sleeping on a cake',
title: 'Man sleeping on a cake',
height: '200px',
width: '400px',
},
}
] %}
<div class="teaser-content-blocks">
{% for content_block in content_blocks %}
{% include '#molecules/teaser-content-block.twig' with content_block only %}
{% endfor %}
</div>
This is the teaser-photo atom:
<div class="teaser-photo">
<img
src="{{ url }}"
alt="{{ alt }}"
title="{{ title }}"
/>
</div>
And this is what I'm attempting to do with the teaser-content-block molecule:
<div class="teaser-content-block">
<div class="left">
{% include '#atoms/teaser-photo.twig' with teaser_photo only %}
</div>
<div class="right">
{% include '#atoms/title.twig' with { title: 'Sleep on a cake', element: 'h3' } only %}
{% include '#atoms/teaser-body.twig' with { body: "When we say 'sweet dreams', this isn't quite what we mean! Check this mad lad not understanding the general concept of pillows! This utter banterboy has completely confused what he is meant to use as a confectionary-based celebration of one's birth and a soft item of bedding designed to cushion the head during sleep or light rest. Mental!" } only %}
</div>
</div>
It seems, however, that the with teaser_photo only statement causes twig to break and not compile, with an error of Catchable fatal error: Argument 1 passed to Twig_Template::display() must be of the type array, null given.
If I change that include statement to the following:
{% include '#atoms/teaser-photo.twig' with { url: teaser_photo.url, alt: teaser_photo.alt, title: teaser_photo.title } only %}
... it works fine, but this is way too verbose for my liking. I'd rather just pass the object down as it is. It just seems to not want to pick it up in the correct manner, even though theoretically it should work the same.
I'm not a twig expert so I may be missing something really obvious.
Any help much appreciated as always!
Discovered the issue. Pattern Lab of course tries to render every available pattern, so it was trying to render teaser-content-block.twig which is trying to reference the variable teaser_photo, which of course doesn't exist in this scope. So the cure was to replace that line with one that uses a default, like so:
{% include '#atoms/teaser-photo.twig' with teaser_photo|default({}) only %}
... or at least something that does a similar thing. Thanks to #DarkBee too for taking the time to have a look.

Symfony3: Enable aptoma twig-markdown extension

How can I enable the aptoma twig-markdown extension? I have installed it using composer but when I use {% markdown %} in my twig file, I get an error message saying:
Unexpected "markdown" tag (expecting closing tag for the "block" tag
defined near line 8).
I had a look in the symfony documentation but was not able to find the solution.
Edit:
I tried to add the following code to services.yml but got another error:
twig.markdown:
class: Aptoma\Twig\Extension\MarkdownExtension
arguments: []
tags:
- { name: twig.extension }
Type error: Argument 1 passed to
Aptoma\Twig\Extension\MarkdownExtension::__construct() must be an
instance of Aptoma\Twig\Extension\MarkdownEngineInterface, none given
[...]
Upon request my .twig-file:
{% extends 'XYZBundle::layout.html.twig' %}
{% block title %}
{{ parent() }} – Eintrag anzeigen
{% endblock %}
{% block platform_body %}
<ul>
<li>
Back to the list
</li>
<li>
Edit
</li>
</ul>
<h1>{{ work.title }}</h1>
<div class="work-content">
{% markdown %}
{{ work.content }}
{% endmarkdown %}
</div>
{% endblock %}
According to the docs you need to install the markdown engine of your choice like:
composer require michelf/php-markdown
You need to create a service for the twig extension and the markdown engine, add the engine to the extension and register it as twig extension, f.e like this in your services.yml or config.yml:
services:
markdown.engine:
class: Aptoma\Twig\Extension\MarkdownEngine\MichelfMarkdownEngine
twig.markdown:
class: Aptoma\Twig\Extension\MarkdownExtension
arguments: ['#markdown.engine']
tags:
- { name: twig.extension }
Symfony will then automatically register it as twig extension through the usage of 'tags' or tagged services.
According to the new autowire system, you only have to declare the mardown engine implementing the Aptoma markdown engine interface.
Aptoma\Twig\Extension\MarkdownEngineInterface:
class: the markdown engine of your choice!
twig.extension.markdown:
class: Aptoma\Twig\Extension\MarkdownExtension
tags:
- { name: twig.extension }
If you do not change Aptoma\Twig\Extension\MarkdownEngineInterfaceby something like markdown.engine you do not need to declare arguments in your twig extension service declaration.
If you want to use the recommended markdown engine, install it via:
composer require michelf/php-markdown
Then, declare it:
Aptoma\Twig\Extension\MarkdownEngineInterface:
class: Aptoma\Twig\Extension\MarkdownEngine\MichelfMarkdownEngine
twig.extension.markdown:
class: Aptoma\Twig\Extension\MarkdownExtension
tags:
- { name: twig.extension }
You can see in vendor\aptoma subdirectories the available engine.
But you can use yours. It only have to implement MarkdownEngineInterface.

Resources