I have a collection called opcodes and created a loop to generate a listing of all the members. In abbreviated form:
{% assign ops = site.opcodes | where: 'pst', 1 %}
{% for opcode in ops %}
<div id="op{{ opcode.n }}" class="opcode">
<span class="op-data">#{{ opcode.n }} ({{ opcode.n | dec_to_hex }})</span>
{{ opcode.content }}
{% endfor %}
The individual members are html files with some front matter. I'll be generating several listings and the members sometimes need to change slightly. It looks like by the time the loop runs, their content is already generated though. I tried affecting their front matter or site variables, but this is all too late, none of the liquid if statements work. The variables are either empty or at their original values.
Is there a way to make this work, somehow pass parameters to the members before their content gets rendered?
The obvious fix is to just copy the problematic files and edit them, since I'm already using a "where" clause to select them. The question is about any better ways.
EDIT: this is how the individual files look like:
---
title: bla
pst = 0
---
bla bla
{% if x == "big" %}
blu blu
{% else %}
ble ble
{% endif %}
x is what I'd like to set externally, from the first loop.
You can use front matter default configuration to set variable depending on containing folder.
─ _myCol
├── cat1
│ ├── item0.md
│ └── item1.md
└── cat2
├── item2.md
└── item3.md
If you want to set a variable myVar for all you items in myCol collection, you do :
# _config.yml
defaults:
- scope:
type: myCol
values:
myVar: "YOLO"
Now if you want to set a different value for myVar depending on containing folder, you add :
- scope:
path: _myCol/cat1
values:
myVar: "TOTO"
You can then use this variable in your collection's item layout, like this :
{% if page.myVar == "YOLO" %}
blu blu
{% else %}
ble ble
{% endif %}
I've looked at it again, but found no solution, so the answer appears to be: no, it is not possible to pass parameters to collection members before they get rendered.
Related
I need to work with folders and files in a directory on a minion not master. This is what I have tried but it's not working. Unfortunately, salt documentation is not very explicit in their examples.
{% set folderLocation = 'D:\\Myfolder' %}
{% for folder in folderLocation %}
{% if folder == "Something" %}
DeleteFolder:
file.absent:
- name = 'D:\\Myfolder\\folder'
{% endif %}
{% endfor %}
Basically, I want to get the content of Myfolder like how you use Get-Item/Get-ChildItem 'D:\\Myfolder' in powershell and then loop through it. How can I achieve this please in a salt state? I want to avoid using cmd.script or cmd.run. "Myfolder" is on the minion.
You can use the file.find module to get the contents of a given path.
For a simple operation like delete, that you have shown in the question, you can write it as (without having to iterate):
delete-myfolder-files:
module.run:
- file.find:
- path: "D:/MyFolder/"
- mindepth: 1
- delete: fd
The above state will delete all files and directories (represented by fd), in the given path, but excluding the base directory because of mindepth.
You could also save the results of the "find" operation into a variable, and use it.
{% set dir_contents = salt['file.find'](path="D:/MyFolder/", type="fd", mindepth=1) %}
{% for item in dir_contents %}
# Do something
{% endfor %}
Now the dir_contents variable will have an array of files and directories (specified by type). We can iterate over each "item" and do something else with it
I try to create a global variable in layout and call it in pages
E.g:
<!-- _layouts/post.html -->
{% assign filename = page.url | split: '/' | last | replace: '.html', '' %}
{{ content }}
in post page:
<!-- SomePage.html -->
<h1>Page Name: {{ filename }}</h1> //-> # Page Name: SomePage
The page name should be printed but I do not know how to do it
Any ideas?
I guess you are misusing Jekyll as it is not suppose to work like that. It should be used other way around. Templates are designed to show pages with variables, so that you follow many to one relation pages in templates.
The idea is to put repetitive part of your pages in your layout. So you should have your layout defined like this:
<!-- _layouts/post.html -->
{% assign filename = page.url | split: '/' | last | replace: '.html', '' %}
<h1>{{ filename }}</h1>
{{ content }}
Then you don't have to write that part in your every page, but it is handled automatically for you.
I'm trying to write a static site with Jekyll that has a few layers to it. What's the best way to generate links to all subpages within a section?
For example, if I have a site structure like this:
landing
- Topic A
- Content 1
- Content 2
- Content 3
- Topic B
- Content 1
- Content 2
- Content 3
What would be the best way to create links to each of the Content pages from its Topic page? And, is there a simple way to link to all the Topic pages from the landing?
These are not posts, just static pages. It would be really great if I could just do {% for topic.each %} ...etc. and print the links out.
I would not use posts for this purpose (as yaitloutou suggests). I would read the hierarchy from the directory structure (solution 1) or create two seperate collections (solution 2). You can let the collections from solution 2 share the same layout if you want that.
1. Using pages
Create a directory structure with index.md pages and loop over the Jekyll veriable called 'site.pages' to create the menu.
index.md
topic-a/index.md
content-1/index.md
content-2/index.md
content-3/index.md
topic-b/index.md
content-1/index.md
content-2/index.md
content-3/index.md
And loop over all pages like this:
<ul>
{% assign sitepages = site.pages | sort: 'order' %}
{% for sitepage in sitepages %}
<li {% if page.url == sitepage.url %} class="active"{% endif %}>
{{ sitepage.title }}
</li>
{% endfor %}
</ul>
If you want the nested structure, you can do something like this. Or if you want only the results for Topic A, you can do this:
<ul>
{% assign sitepages = site.pages | sort: 'order' %}
{% for sitepage in sitepages %}
{% if sitepage.url contains 'topic-a' %}
<li {% if page.url == sitepage.url %} class="active"{% endif %}>
{{ sitepage.title }}
</li>
{% endif %}
{% endfor %}
</ul>
2. Using collections (simplest solution and quickest build)
Create a collection Topic A and create another collection Topic B. Your config file should look like this:
collections:
topic-a:
output: true
permalink: /topic-a/:path/
topic-b:
output: true
permalink: /topic-b/:path/
Outputting the items of one topic goes like this:
{% assign atopics = site.topic-a | sort: 'order' %}
{% for atopic in atopics %}
<li {% if page.url == atopic.url %} class="active"{% endif %}>
{{ atopic.title }}
</li>
{% endfor %}
</ul>
You should create a _topic-a and a _topic-b directory with your content-1.md, content-2.md, etc. files.
Note that both solutions have YML variables called 'order', to determine the order of appearance of the items/pages. This looks like this:
---
title: mytitle
layout: mylayout
order: 50
---
mycontent
I'll propose here 2 ways, you can determine the "best" according to your specific needs/situation, and which one sound more adapted to them.
first of all, "posts" and "pages" are basically just collections of md/html files. with some variables associated to each one.
to generate files with this structure, you can:
1. Using _posts and page.categories
put all the sub-files in _posts (the 2017-01-01- is just a place holder)
_posts/
- 2017-01-01-content-a-1.md
- 2017-01-01-content-a-2.md
- 2017-01-01-content-a-3.md
- 2017-01-01-content-b-1.md
- 2017-01-01-content-b-2.md
- 2017-01-01-content-b-3.md
add appropriate categories to each file:
2.1. for posts caontent-a-* add category: topic-a (in this order) by adding this line in the yaml front matter at top of each of them:
---
layout: page # or any appropriate layout
category: topic-a
---
2.2. for posts caontent-b-* add category: topic-b
set a premalink to ignore the date, and create the desired structure, by adding the following line to _config.yml:
defaults:
-
scope:
path: "_posts" # to all the file in posts
values:
permalink: /landing/:categories/:title.html # set this as default permalink value
you still can specify a permalinks per post in its front matter, or just add the permalink line to each md folder front matter.
the above will generate the desired structure.
loop through all the
{% for entry in site.posts %}
{% if entry.category == type-a %}
<!-- do A stuff -->
{% elsif entry.category == type-b %}
<!-- do B stuff -->
{% endif %}
{% endfor %}
2. Using collections:
it's similar to the above, but instead of using the already existent _postscollection you'll start by creating a new collection (one advantage is that you'll not need to add a date )
any of the approaches above will generate this structure inside _site
landing/
type-a/
content-a-1/
index.html
content-a-2/
index.html
...
type-b/
...
I'm not entirely sure how to phrase my request, but, basically, I have a single collection with multiple categories, all the articles of this collection are shown on a single page. It's already sorted by category, however, I'm trying to find a way to sort these categories in a specific fashion. I've tried assigning the categories weight and using that to sort, but it did not work. I'm not sure what else to try?
You can find the code for all that I've done on GitHub...https://github.com/yndrelbosch/yndrelbosch.github.io
I'm trying to make this page: https://yndrelbosch.github.io/tutorials/ use a custom sorting for the categories on the page...
The code for that page is here: /pages/tutorials.html
the articles in the collection are here: /_tutorials/
Can anyone help me?
In pages/tutorials.html, your {% assign categories = site.tutorials | group_by:"category" | sort: "category-weight" %} will definitely not work.
As category-weight is not a key in site.tutorials documents, the sort filter will fail silently.
Saving some typing
We can avoid setting category in tutorials front matter by defining defaults variable depending on document path.
Let's change _tutorials organization :
_tutorials
├── advanced
│ ├── adding-next-previous-to-blog.md
│ └── ...
├── getting-started
│ ├── getting-started-with-jekyll.md
│ └── ...
└── setup
├── jekyll-on-windows-2.md
└── ...
Add some defaults in _config.yml :
defaults:
- ...
- { scope: { path: "_tutorials/advanced" }, values: { category: "Advanced" } }
- { scope: { path: "_tutorials/getting-started" }, values: { category: "Getting started" } }
- { scope: { path: "_tutorials/setup" }, values: { category: "Setup" } }
Create a reference for tutorials categories order
In _config.yml, add
# this is used to display tutorials in the right categories order
# be sure to match default category names defined in site.defaults
tutorials-categories:
- "Setup"
- "Getting started"
- "Advanced"
Note that moving categories order from pages/tutorials.html to _config.yml is made to centralize configuration. It helps to stay in synch between defaults settings and categories order.
Let's display our tutos in the right categories order
In pages/tutorials, we can do something like :
{% assign categories = site.tutorials | group_by:"category" %}
{% comment %} ++++++++++++++++++++++++++
We loop site.tutorials-categories to sort categories in a defined order
++++++++++++++++++++++++++ {% endcomment %}
{% for category in site.tutorials-categories %}
{% assign current-category = categories | where:"name", category | first %}
{% assign category-tutorials = current-category.items %}
<h2>{{ category }}</h2>
<ul>
{% for item in category-tutorials %}
<li>{{ item.title }}</li>
{% endfor %}
</ul>
{% endfor %}
How can I loop through every file in my _data folder in Jekyll?
Currently I have a list of files in a file called sidebarlist.yml like this:
- file1
- file2
- file3
In order to loop through all of these files, I use this code:
{% for sidebar in site.data.sidebarlist %}
{% for entry in site.data.sidebars[sidebar].entries %}
...
{% endfor %}
{% endfor %}
I would like to avoid using sidebarlist.yml and just iterate through all files within _data automatically. Can I do this?
Nesting loops allows you to loop through the contents of _data files.
When I did this I used a subdirectory, since I didn't want to loop through every data file, and I think that applies to many use cases. It also keeps my _data directory a little tidier.
My _data directory looks like this:
_data/
navigation.yml
news.yml
people/
advisors.yml
board.yml
staff.yml
Each of the files within people/ uses a structure like this:
- name: Anne Smith
role: Role A
url: mysite.com
- name: Joe Shmoe
role: Role B
url: mysite.org
And on the page where I'm looping through each of these data files:
{% for people_hash in site.data.people %}
{% assign people = people_hash[1] %}
{% for person in people %}
<li>{{ person.name }}, {{ person.role }}</li>
{% endfor %}
{% endfor %}
This results in:
<li>Anne Smith, Role A</li>
<li>Joe Shmoe, Role B</li>
It's very similar to what you've already done, but eliminates the need for that extra yaml file.
Note the use of people_hash[1] - this is what is targeting the appropriate values within the array.
If instead you do:
{% for people_hash in site.data.people %}
{% assign people = people_hash[1] %}
<pre>{{ people }}</pre>
{% endfor %}
You'll get the array of values that is returned, which should help you debug your template.
I have read your question title, and I will answer your last question:
You can't loop through files you keep in _data folder. According to Jekyll Variable doc and Jekyll Directory structure all the file in _data with supported extension .yml .yaml .csv .jsonby default will be loaded in site.data like #wasthishelpfull's answered and you access it via {{site.data.*filename.data*}} and loop though like this answer
If you wanna loop through files, create a folder (no underscore) serve it as static files, and use jquery.get() for the data in the file.
Or change _data to data in _config.yml by adding data_source: data and access at a url endpoint /data see this post for more
According to the documentation, jekyll will load YAML resources (.yml, .yaml, .json, and .csv files) directly into site.data. If your files use one of these formats, you can do:
{% for data in site.data %}
...
{% endfor %}
I assume you need to access jekyll site.data in a way of looping multi levels object:
{% assign my_data = site.data %}
{% assign my_level = "sidebarlist.sidebars.sidebar" | split: "." %}
{% for level in my_level %}
{% assign my_data = my_data[level[i]] %}
{% for data in my_data %}
{{ data }} : {{ my_data[data] }}
{% endfor %}
{% endfor %}