How to add a new property to Jekylls posts? - jekyll

I want to do something like:
{% for post in site.posts %}
{% assign post.myProprty = "something" %}
{% endfor %}
But it doesn't work. Is that another way to do it?

I could make it happen using a plugin.
plugin code:
module Jekyll
module AddProp
def addProp(input, key, value)
input[key] = value
return input
end
end
end
Liquid::Template.register_filter(Jekyll::AddProp)
Usage:
{% for post in site.posts %}
{% assign post = post | addProp: "myProprty", "something" %}
{% endfor %}
Plugin GitHub repository

Related

Idiomatic way in Jekyll to inherit default data if project specific data unavailable

I am completely new to Jekyll. I did something like this:
{% assign top_nav = site.data.menus %}
{% if site.data.orgs[site.orgData].menus %}
{% assign top_nav = site.data.orgs[site.orgData].menus %}
{% endif %}
<ul>
{% for menu in top_nav %}
<li>
{{ menu.title }}
</li>
{% endfor %}
</ul>
Basically, I will grab an array of navigation items from a default folder. But if I notice the existence of a menu for a specific organization, then I will override the menu provided by the default folder.
What I don't like about this approach is I now have hundreds of places in my jekyll templates that does this if statement check. If this were any other scripting programming language, I would define a function like function($org_name,$prop) {return $site.data.orgs[$org_name][$prop] ? $site.data.orgs[$org_name][$prop] : $site.data[$prop]; } . What would be the idiomatic way to achieve the same objective in jekyll?
I tried a variation of David Jacquel's suggestion by doing this
./org_var.html
{% assign prop = include.prop %}
{% assign orgVar = site.data[prop] %}
{% if site.data.orgs[site.orgData][prop] %}
{% assign orgVar = site.data.orgs[site.orgData][prop] %}
{% endif %}
./_include/nav.html
{% include_relative ../org_var.html prop=menus %}
{% for menu in orgVar %}
... print menu items
./_layout/header.html
{% include_relative ../org_var prop='electronics.televisions' %}
{% for tv in orgVar%}
{{ tv.modelName }}
... print tv values
{% endfor %}
But I get a syntax error in ../org_var.html saying {% include_relative file.ext param='value' param2='value' %} . The documentation says I can't use relative path with include or include_relative. How do I make my org_var.html a reusable and global function? And will electronics.televisions even evaluate properly to the proper path of my site.data.org.[site.orgData][...path] variable?
Just realized there is a default: modifier for a variable like smarty templates.
{% assign top_nav = site.data.orgs[site.orgData].menus | default: site.data.menus %}
You can use Jekyll includes.
From anywhere you want to use your include :
{% include nav.html org_name=org_name prop=prop %}
Will call _include/nav.html that can be something like this :
{% assign org_name = include.org_name %}
{% assign prop = include.prop %}
{% if site.data.orgs[org_name][prop] %}
{% assign top_nav = site.data.orgs[site.orgData].menus %}
{% else %}
{% assign top_nav = site.data.orgs[site.orgData].menus %}
{% endif %}
<ul>
{% for menu in top_nav %}
...

Jekyll -- possible to cycle through all post types?

Is it possible to cycle through all content types on Jekyll?
Instead of {% for post in site.pages %}
I want to do something like
{% for post in site.pages or site.posts %}
You can use concat filter :
{% assign all = site.posts | concat: site.pages %}
{% for post in all %}
...

Passing parameters to inclusion in Liquid for loop

have trouble with passing
{% include /components/home-lastest-posts.html nb=8 %}
code in my template home-lastest-posts.html :
{% for post in site.posts offset:0 limit:{{ include.nb }} %}
do something
{% endfor %}
It's listing my posts blog but my param not working. What is wrong ?
have try nb="8" too but not working too
Simply use : {% for post in site.posts offset:0 limit:include.nb %}.

Jekyll (Liquid): Setting post state in included templates

Maybe this is a case of a Python programmer trying to work with Ruby and maybe this is a "feature" -- I don't know. For the life me I can't figure out how to set state on posts during the rendering process.
I have a _layout that just calls include twice:
{% include templateA %}
{% include templateB %}
templateA walks the posts and renders some of them on the basis of some_condition.
{% for post in site.posts %}
{% if some_condition %}
<!-- Render the post -->
{% assign post.rendered = true %}
{% endif %}
{% endfor %}
templateB attempts to walk the posts and render the rest:
{% for post in site.posts %}
{% unless post.rendered %}
<!-- Render the post -->
{% endif %}
{% endfor %}
This does not work as expected. I have also tried the {% assign post[rendered] = true %} syntax. No errors are thrown; just silent failure.
Where am I failing here? Is my mental model for the rendering process just totally wrong? Thanks!
Your first though was nearly ok. The unless tag does the contrary of if.
But you cannot change jekyll's variables, they are "freezed".
So, this might work :
templateA
{% for post in site.posts %}
{% if same_condition %}
<!-- Render the post -->
{% endif %}
{% endfor %}
With the same condition unless will render posts not rendered by the first loop.
templateB
{% for post in site.posts %}
{% unless same_condition %}
<!-- Render the post -->
{% endunless %}
{% endfor %}

Get Django User group in HTML

I am trying to get Django user's group in HTML for an if tag. This is what I tried:
{% ifequal user.groups.all.0 'ABC' %}
{% endif %}
But this is not working. What other way is there?
Try this:
{% for group in request.user.groups.all %}
{% if group.name == 'ABC' %}{% endif %}
{% endfor %}
Or
{% if request.user.groups.all.0.name == 'ABC' %}{% endif %}
You have to access the current user object from the request context variable. For this, make sure that django.template.context_processors.request is in your template settings.
request.user.groups.all.0 returns a Group model object, so you have to compare against the name field.
I think you will have to use a little Python here. For example, a custom template tag:
#register.filter(name='has_group')
def has_group(user, group_name):
return user.groups.filter(name=group_name).exists()
And in your template:
{% if request.user|has_group:"ABC" %}
...
{% endif %}
(Source: http://www.abidibo.net/blog/2014/05/22/check-if-user-belongs-group-django-templates/)
But maybe you should actually use permissions here.
https://docs.djangoproject.com/en/1.8/topics/auth/default/#authentication-data-in-templates
Edit: Here is a more complete example of the custom template tag:
settings.py:
INSTALLED_APPS = [
...
'yourapp',
...
]
Filesystem:
yourproject/
manage.py
yourproject/
settings.py
wsgi.py
...
yourapp/
__init__.py
templatetags/
__init__.py
yourapp_extras.py
...
yourapp_extras.py:
from django import template
register = template.Library()
#register.filter(name='has_group')
def has_group(user, group_name):
return user.groups.filter(name=group_name).exists()
Template:
{% load yourapp_extras %}
{% if request.user|has_group:"ABC" %}
...
{% endif %}
To get a more thorough understanding of this, I highly recommend reading Django's excellent documentation.
<h1>{{ user.groups.all.0 }}</h1>
{% if user.groups.all.0.name == 'Team2' %}
<h1>YES</h1>
{% else %}
<h1>NO</h1>
{% endif %}
Here, the user.groups.all.0 gives you the first group assigned to the user.
For eg. if the logged in user has groups assigned to him as- 'Team2', 'Programmer', 'Beginner'.
Then {{user.groups.all.0}} will print Team2.
I've used it to print and check the logged in user's group in html template.
OR
{% if request.user|has_group:"mygroup" %}
<h1>Has group mygroup</h1>
{% endif %}
Also works fine in django v1.11. This will check if the current user has 'mygroup' assigned to it or not.
However you'll need to add
from django import template
from django.contrib.auth.models import Group
register = template.Library()
#register.filter(name='has_group')
def has_group(user, group_name):
group = Group.objects.get(name=group_name)
return True if group in user.groups.all() else False
inside a group_check.py in below file structure
--app
|templates
|templatetags
|-- group_check.py