Reuse file path in Jekyll - jekyll

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.

Related

Use variable inside Liquid tag call instead of string

I have already checked this solution and it doesn't seem to work for my problem. I have issue passing post.image variable name to tag responsive_image. If I pass string like that {% responsive_image path: assets/img/ar-7.jpg %} it works without any issue but I didn't found a way how to pass variable to that. Any ideas?
1) I thought this would work, unfortunately string post.image is passed instead of variable. Commented code is working example that I need to change to responsive image.
{% if post.image %}
{% responsive_image path: post.image %}
<!-- <img class="has-ratio" src="{{post.image}}" /> -->
{% endif %}
Invalid image path specified: "post.image"
Liquid Exception: unable to open image `/Users/.../Documents/Apps/Jekyll/wtc-mbp/post.image': No such file or directory # error/blob.c/OpenBlob/2881 in .html
2) Solution from this answer, doesn't work
{% if post.image %}
{% assign path = post.image %}
{% responsive_image path %}
{% endif %}
Invalid image path specified: nil
Liquid Exception: no decode delegate for this image format `' # error/constitute.c/ReadImage/566 in .html
3) Another idea also doesn't work
{% if post.image %}
{% assign path = post.image %}
{% responsive_image path: path %}
{% endif %}
Invalid image path specified: "path"
Liquid Exception: unable to open image `/Users/.../Documents/Apps/Jekyll/wtc-mbp/path': No such file or directory # error/blob.c/OpenBlob/2881 in .html
To use Liquid variables, you need to opt for the responsive_image_block tag instead:
{% responsive_image_block %}
path: {{ post.image }}
{% endresponsive_image_block %}

Output link to "parent page"?

I have a collection _colletion. In there is a file _collection/path/topic.md and a folder _collection/path/topic/ that includes lots of .md files with content. The permalinks for these files are /path/topic and /path/topic/file-x - so a parent page with a folder with the same name with multiple random pages in it.
Now I want to output a link to /path/topic in all these .md files with the title of topic.md as link text:
---
title: This is the page title defined in topic.md
---
should become
This is the page title defined in topic.md
How do I do that most easily?
Can I somehow access the folder name topic of the .md files and use this to read topic.md and output it's title and also generate a link to it?
My current manual "solution" (or workaround):
Add a parent entry to the frontmatter of all pages in /topic/ that contains the title and relative URL for the topic.md:
parent: ['Topic Title', '../topic']
In the template of the pages:
{% if page.parent %}
<p>« {{ page.parent[0] }}</p>
{% endif %}
Works, but of course duplicates this information n times and has to be maintained manually.
How about this (option 1)?
{% assign pageurl_array = page.url | split: "/" %}
{% assign path = pageurl_array[0] %}
{% assign topic = pageurl_array[1] %}
<p>« <a href="{{ path }}/{{ topic }}/{{ topic }}.html">
{{ topic | capitalize | replace: "-", " " }}
</a></p>
If you do not mind crazy build times, do this (option 2):
{% assign pageurl_array = page.url | split: "/" %}
{% assign path = pageurl_array[0] %}
{% assign topic = pageurl_array[1] %}
{% capture parent_url %}{{ path }}/{{ topic }}/{{ topic }}.html{% endcapture %}
<p>« <a href="{{ parent_url }}">
{% for i in site.pages %}
{% if i.url == parent_url %}
{{ i.title }}
{% endif %}
{% endfor %}
</a></p>
I would go for the first option (much faster) and use this javascript to get the capitals and special characters right:
$('a').each( function() {
var str = $(this).html();
str = str.replace('Topic from url', 'Topic from URL');
$(this).html(str);
});
I admit that the javascript solution is far from pretty, but it solves the build time problem pretty well.
Note that Jekyll is pretty slow. I would advice you to dig into Hugo if you require faster build times.
During discussion in the comments on my question and the other answers I noticed that what I wanted to build was actually a very common thing: A breadcrumb navigation! Just a very "small" one, with only one level.
With this newfound knowledge I could google "breadcrumb" plugins for Jekyll:
This solution uses the path of the page to extract the "crumbs":
https://www.mikestowe.com/blog/2017/08/adding-breadcrumbs-in-jekyll.php
It uses the folder name for the link text.
Another similar implementation:
https://stackoverflow.com/a/9633517/252627
Another one:
https://stackoverflow.com/a/37448941/252627
So no title link text in all of these.
This solution actually reads the page title, but can also read breadcrumb frontmatter from the pages, and uses these as link text:
https://github.com/comsysto/jekyll-breadcrumb-for-github-pages/
https://comsysto.com/blog-post/automatic-breadcrumb-for-jekyll-on-github-pages
https://gist.github.com/csgruenebe/8f7beef9858c1b8625d6
This one might be a valid solution.
There are also real plugins (that unfortunately don't work with Github Pages):
https://github.com/git-no/jekyll-breadcrumbs
My solution, based on JoostS code:
{% assign url = page.url | remove:'.html' | split: "/" %}
{% assign path = url | pop %}
{% if path.size == 1 %}
<a class="back" href="/home/">home</a>
{% else %}
<a class="back" href="/{% for dir in path offset: 1 %}{{ dir | append: "/" }}{% endfor %}">{{ path | last }}</a>
{% endif %}```

How to loop through all files in Jekyll's _data folder?

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 %}

Dynamically add and filter images in Jekyll for github pages?

I am trying out Jekyll to help someone who's not all that technical maintain their own static site. I would like to be able to have a images directory in the app's root /images containing images following a naming convention:
post_one_1.jpg, post_one_2.jpg, post_two_1.jpg, post_two_2.jpg ... etc.
I would then like for the user to create a post (post_one) and dynamically grab all of the images pertaining to that post from the images directory.
This plugin (https://gist.github.com/jgatjens/8925165) does almost exactly what I need, but isn't compatible with github pages.
Is there a solution in which I can hand the site off to a user and they would only need to add images to the image directory following the naming convention and then create a post and have access to the images?
Given you have a post file _posts/2015-05-28-post_one.md
From inside this post you have :
page.id = /2015/05/29/post_one
page.dir = /2015/05/29
In order to extract post_one whe do :
{% assign imgNameStart = page.id | remove: page.dir | remove: "/" %}
We now generate the base path we search for :
{% assign imgBasePath = imgNameStart | prepend: "/images/" %}
in this case it will be imgBasePath = "/images/post_one"
Loop over all our static files (files that are not pages or posts).
{% for img in site.static_files %}
And print images that have /images/post_one in their path like /images/post_one-01.jpg or /images/post_one-wathever-you-want.jpg
{% if img.path contains imgBasePath %}
<img src="{{ site.baseurl }}{{ img.path }}">
{% endif %}
{% endfor %}
All together :
{% assign imgNameStart = page.id | remove: page.dir | remove: "/" %}
{% assign imgBasePath = imgNameStart | prepend: "/images/" %}
{% for img in site.static_files %}
{% if img.path contains imgBasePath %}
<img src="{{ site.baseurl }}{{ img.path }}">
{% endif %}
{% endfor %}
Beware of code indentation if your post is a markdown file, four space indentation can be transformed to code snippet.

Check for existence of file using Jekyll

How can I use Jekyll to test for the existence of a file?
To clarify, I want to run an {% if %} statement to check if an image file exists with the same name as the page I am on.
On my page in the YAML front matter:
----
reference-design: true
----
In my layout:
{% if page.reference-design %}
{% assign filename = page.path | remove_first: '.html' %}
<!-- How can I check if file actually exists? -->
<img src="images/reference_designs/{{ filename }}.png">
{% endif %}
As of Jekyll 2, all site files are available via site.static_files. You can use this to check if a file exists. For example:
{% for static_file in site.static_files %}
{% if static_file.path == '/favicon.ico' %}
{% assign favicon = true %}
{% endif %}
{% endfor %}
I had a similar problem to solve, but specifically looking for videos that matched the a specific directory / filename based on the markdown file.
Using file.size allowed me to test if the file (actually) exists.
{% for video in site.video-demos %}
{% assign path = page.id | replace: page.slug , "" | prepend: '/assets/media/video' | append: video.directory | append: page.slug | append: ".mp4" %}
{% assign file_exists = site.static_files | where: "path", path %}
{% if file_exists.size != 0 %}
{% include video-player.html filename = path title = video.title %}
{% endif %}
{% endfor %}
It loops through an array from my config to get part of the directory structure:
video-demos:
- title: iOS Voiceover Safari
directory: ios/
- title: Android Talkback Chrome
directory: android/
- title: Windows Jaws Chrome
directory: jaws/
- title: Windows NVDA Chrome
directory: nvda/
- title: MacOS Voiceover Safari
directory: macos/
This plugin worked for me: https://github.com/Wolfr/jekyll_file_exists
After you install it, you can use it like:
{% if page.reference-design %}
{% assign filename = page.path | remove_first: '.html' %}
{% capture img_exists %}{% file_exists {{ filename }}.png %}{% endcapture %}
{% if img_exists == "true" %}
<img src="images/reference_designs/{{ filename }}.png">
{% endif %}
{% endif %}
Read http://ecommerce.shopify.com/c/ecommerce-design/t/testing-if-a-file-exists-29624. Also you might be able to play with capture.