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 %}
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 have a template folder containing a file.j2 , e.g
{% set summary %}
{% if summary %}
{{ summary }}
% endif %}
{% endset %}
I would like to use this summary variable in my yaml file but I can't seem to be able to find the information on how to reference the j2 file in the yaml file
Can I do this?
template: file.j2
summary: '{{ summary }}'
Any suggestions are greatly appreciated!
I am trying to include a template file dynamically, but the variable does not appear to expand in the include declaration. How is this best done?
{% for file in files %}
{% include "{{ file }}.txt" %}
{% endfor %}
The error I am getting is:
jinja2.exceptions.TemplateNotFound: {{ file }}.txt
The below works for me.
I would like to clarify having a "." in jinja2 might create an issue so it would be better to pass the entire filename with extension to jinja2.
The usage of double quotes would not render the variable value so it would remain as it is like {{ file }}
The below works:
from jinja2 import Environment, FileSystemLoader
data = '''
{% for file in files.split(",") %}
{% include file %}
{% endfor %}
'''
template = Environment(loader=FileSystemLoader("templates/")).from_string(data)
msg = template.render(files="1.txt")
print(msg)
Output:
1.txt
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 am very new to writing websites and jekyll so I apologize if my terminology is unclear or wrong.
I have a bunch of saved files (foo1, foo2, etc) in a subdirectory called 'savedfiles' of my root jekyll folder. Suppose I am editing index.md which is in a sub folder called 'subfolder" and want to link to each of these. One way I can do this is to use
{{ site.url }}/savedfiles/foo1
{{ site.url }}/savedfiles/foo2
etc
Is there a way of saving the file path in a variable say pathfoo so that I could write
{{ pathfoo }}/foo1
etc
And sort of related to this can I get the file path of the subfolder that index.md is in? I know that
{{ page.path }}
will give me {{ site.url }}/subfolder/index.md but I want {{ site.url }}/subfolder. Is this possible?
Saving a path in a variable
{% capture path %}{{ site.url }}{{ site.baseurl}}/savedfiles/{% endcapture %}
you can now use this variable like this :
Link to foo
Getting file path from a file
It is a little bit tricky. But here is a way :
{% assign pathParts = page.path | split: "/" %}
{% assign length = pathParts.size | minus: 2 %}
{% assign path = "" %}
{% for c in (0..length) %}
{% capture path %}{{ path }}/{{pathParts[c]}}{% endcapture %}
{% endfor %}
You now have a path variable like /folder/subfolder. This could be simplest with pop or shift filters, but they are not working as expected and will change in Jekyll 3.0.