Strip url to 1 word in Jekyll - html

I am building a Jekyll blog, and I have come across an issue with permalinks.
My permalinks to blog posts are set like this in
_config.yml:
permalink: /:page/:categories/:title
It outputs like this when navigating to a blog post:
http://localhost:4000/blog/travel/netherlands-trip-prequesites/
I have some static pages in the site: Blog, Travel
The variable page.url outputs this url: /blog/travel/netherlands-trip-prequesites
The code my navigation bar uses to highlight the current page (giving it an "active" class):
{% assign url = page.url|remove:'index.html' %}
{% for nav in site.navigation %}
{% if nav.href == url %}
<li class="active">{{nav.name}}</li>
{% else %}
<li>{{nav.name}}</li>
{% endif %}
{%endfor%}
It works great when navigating to static pages, however when I click a blog post it doesn't highlight the correct static page. (ex.: If i navigate to a blog post with the url /blog/smth/title it should automatically highlight "Blog" in my navigation. When I navigate to /travel/smth/title it should highlight "Travel")
What I'd like to do is to strip down the output of page.url to its first part. For example I'd like to stip the following output
/blog/travel/netherlands-trip-prequesites
down to
/blog/
Why? So I can use it to check which static page it belongs to and highlight it accordigly.

The easiest way is to use split:
{{ page.url | split:'/' | first }}
That will give you the URL content up to the first / character.

I managed to solve it with three filters:
{{ page.url | replace:'/',' ' | truncatewords: 1 | remove:'...' }}
page.url outputs: /page/cat/title, then replace removes the forward slashes producing: page cat title. truncatewords truncates the string down to one word, producing: page... (for some reason three dots gets inserted after the remaining word). After all this I only needed to remove those dots with remove and voilá, my final string: page.
Hope this helps someone.

The answer provided by PeterInvincible was almost perfect, however, there's no need to get piping to remove involved...
The following also will produce desired output
{{ page.url | replace:'/',' ' | truncatewords: 1,"" }}
And to save it to a variable use capture redirection
{{ capture url_base }}{{ page.url | replace:'/',' ' | truncatewords: 1,"" }}{{ endcapture }}
Which can be called via {{url_base}} or mixed with other processing calls.
Also for file paths instead of URLs page.dir works well if you're not using permalink settings for layout, check the gh-pages branch (specifically _includes/nav_gen.html for functional, though rough'round the edges, example) for hosted examples of similar code examples related to liquid syntax and other magic.
Edits & Updates
The above linked script is now live/mostly-working/modular and auto-serving parsed sub-directories viewed currently at the related https://s0ands0.github.io/Perinoid_Pipes/ project site providing examples of recursive parsing of directories. Including and modding for nearly any theme should be possible just check the commented section at the top for currently recognized commands that maybe passed at inclusion call... on that note of inclusion and modularization here's how to turn the above example code for directory parsing into a function
{% comment %}
# Save this to _include/dir_path_by_numbers.html
# import with the following assigning arguments if needed
# {% include dir_path_by_numbers.html directory_argument_path="blog" directory_argument_depth=1 %}
{% endcomment %}
{% assign default_arg_directory_path = page.url %}
{% assign default_arg_directory_depth = 1 %}
{% if directory_argument_path %}
{% assign directory_to_inspect = directory_argument_path %}
{% else %}
{% assign directory_to_inspect = default_arg_directory_path %}
{% endif %}
{% if directory_argument_depth %}
{% assign directory_to_inspect_depth = directory_argument_path %}
{% else %}
{% assign directory_to_inspect_depth = default_arg_directory_depth %}
{% endif %}
{% comment %}
# Defaults read and assigned now to output results
{% endcomment %}
{{ directory_to_inspect_depth | replace:'/',' ' | truncatewords: directory_to_inspect_depth,"" | remove_first: '/' | replace:' ','/' }}
The above should output directory path lengths of whatever size desired and maybe included as shown previously or if feeling adventurous try what's shown below; though for looping and recursive features look to the linked script for how I've worked around stack size restrictions.
{% capture dir_sub_path %}{{include dir_path_by_numbers.html directory_argument_path="blog" directory_argument_depth=1}}{% endcapture %}
Note above is just speculation, untested, and maybe more buggy than scripts tested and hosted publicly... in other words inspiration.

Simplest way would be using
if page.url contains
example:
<li class="{% if page.url contains '/docs/' %}current{% endif %}">
Docs

Related

Searching for page in site.pages by path without iteration

I have a path to some page from root in Jekyll as a variable path. I want to get some variables from FrontMatter of that page. How could I find this page in site.pages without iterating over all pages?
I mean something like
{% assign aim = site.pages[path] %}
instead of
{% for p in site.pages %}
{% if p.path == path %}
{% assign aim = p %}
{% endif %}
{% endfor %}
Will this solution be faster for a site with a thousand of pages?
You can use the where liquid filter for this:
{% assign aim = site.pages | where:"path",path %}
Thanks #β.εηοιτ.βε for the hint!
That was what I expected, but when I used this template, I've faced the problem: the output of {{aim.title}} was empty.
The where filter produces list even it consists of just one element! But each filepath in a file system points exactly at one file, so I expected that aim will be the page, not a list. To fix this, I've added first filter:
{% assign aim = site.pages | where:"path",path | first %}
And now aim is the page variable I am searching for.
About speed. This solution builds a site 2X faster on my hardware.

Trying to get a collection from a Front Matter value

Hi I'm new to Jekyll and have a basic blog set up. Now my idea is to loop through a collection per blog post to get some fancy HTML going on. Because as far as I'm aware you can't simply add HTML to the markdown.
// config.yml
collections:
- hollowknight
So I've set up a collection named hollowknight and I got a blog post about Hollow Knight.
In the Front Matter of the blog post I have collectionid: 'hollowknight'. And in the Layout I use for blog posts I tried the following:
// post.html
{% capture collection %}site.{{ page.collectionid }}{% endcapture %}
{% for section in collection %}
{{ section.title }}
{% endfor %}
So the idea was to set the collection variable to site.hollowknight as configured in the config and the Front Matter. I set up a single article inside the collection, but it isn't showing up.
Is there any way to realise this?
Edit: https://talk.jekyllrb.com/t/list-collection-with-name-from-front-matter/3619/6
Or is there a way to use paragraphs in the Front Matter, because then I could just use arrays and objects in the Front Matter of the posts to do my magic?
Edit: https://github.com/jekyll/jekyll/issues/246#issuecomment-1639375
Or am I just stretching to far from what Jekyll is supposed to be?
Edit
So I found out I was getting the collection the wrong way, https://talk.jekyllrb.com/t/list-collection-with-name-from-front-matter/3619/6.
{% for section in site.[page.collectionid] %}
{{ section.content | textilize }}
{% endfor %}
The only weird part is, everywhere I see | textilize being used but can't get it to work.
This is the final solutions:
{% for section in site.[page.collectionid] %}
{{ section.content | markdownify }}
{% endfor %}
It's markdownify instead of textilize.
Also I ended up using a Front Matter array with objects to loop through instead of a collection to keep it more organized.

Getting current url from a collection in Jekyll

If I want to get a page's url it's not exactly complicated:
page.url
However, what if I make a collection who's job it is to be used like an include instead of like a page?
If I make such a collection and ask for page.url it gives me the path to the collection instead of the path to the current url.
Is there a way to get the real current URL in Jekyll?
Edit: example
test.md:
---
title: Test page
permalink: /test/
---
Test page
{% for block in site.blocks %}
{% if block.whatever %}
{{ block.content }}
{% endif %}
{% endfor %}
_blocks/block.md:
---
whatever: true
---
{% page.relative_path %}
Got:
Test page
/_blocks/block.md
Expected:
Test page
test.md
I've been using jekyll for a short time and I'm relying on collections to build my first static portfolio site. So far all my attempts when trying to get the path to the current url simply fails.
In order to achieve the desired result, I've used Jekyll Liquid filters.
Here is how you'd get the expected result you as per your question:
test.md:
---
title: Test page
permalink: /test/
---
Test page
{% for block in site.blocks %}
{% if block.whatever %}
{{ block.content }}
{% endif %}
{% endfor %}
_blocks/block.md:
---
whatever: true
---
{{ page.relative_path | replace:'index.html', '' | remove: '_blocks/' | prepend: site.baseurl }}
Output on Test page
Test page
test.md
Update:
Perhaps the following is not the most straightforward method to get the path to the current url, but by defining relative_path: in the front-matter definitions of a document you'd also get the result you expect, of course this is something required on a per page basis.
---
whatever: true
relative_path: test.md
---
{% page.relative_path %}
So in this very specific case
{% page.relative_path %}
should output
test.md
A Jekyll's doc reminder:
As per Jekyll's doc, when you create a collection it becomes available via the site Liquid variable, pretty much like site.posts and site.pages, so you're able to use the available filters in most cases.
I hope it helps!

Jekyll filter to remove pages from site.pages based on page.url?

While generating a Google site map for my (non-github) Jekyll site, I would like to exclude certain files based on the page URL (or file name). In shell-speak, something like
site.pages | grep -v forbidden_name
In Liquid, I imagine a signature something like
site.pages | exclude 'url', forbidden_name
In a related note, is there a catalog of the standard, built-in filters, tags, and generator? Something a bit handier than grep -Rl register_filter ~/.rvm/gems?
You can try something like
{% for p in site.pages %}
{% if p.url contains 'ca' %}
{% comment %}Do nothing{% endcomment %}
{% else %}
{{ p.title }}
{% endif %}
{% endfor %}
A little hacky an case unsensitive and no wild card.
I've made a list of tags and filters that works on Github.

Evaluate a liquid "if" statement based on value of liquid filter

I have a custom Liquid filter I use in a Jekyll site,
{{ page.url | git_modified }}
Which generates the modification date from the git log (plugin code here).
Often I may add the additional filter to convert this to a string or XML schema, depending on context, e.g. {{ page.url | git_modified | date_to_string }}. Everything is hunky-dory unless for some reason my git_modified filter fails to return a time object for some post. In that case, I am trying to write a decent fail condition but cannot quite figure this out.
I'd like to just wrap my call in a liquid if statement to check if the variable is defined first:
{% if defined?( {{ page.url | git_modified }} %}
But I don't seem to be able to use Liquid tags ({{) inside Liquid block options ({%, %}). I thought I could get around this with Liquid capture:
{% capture page_modified %}{{ page.url | git_modified }}{% endcapture %}
{% if defined?(page_modified) %}
{{ page.url | git_modified | date_to_string }}
{% endif %}
but said variables do not seem to be available to the if statements. Any suggestions?
try doing it this way:
{% capture page_modified %}
{{ page.url }}
{% endcapture %}
{% if page_modified %}
{{ page.url }}
{% endif %}
If page_modified isn't defined, its value will be nil anyway, so just use the if construct as you would in pure Ruby. I tested here with jekyll 1.0.0.beta2 — jekyll new test, then created a file with the above code — and it worked. :)