Jekyll: Generate an include once and include it to all pages - html

TL;DR: Can I say somehow to generate the content for a {% include %} once and just stamp it out in multiple places without having to regenerate it in every location?
I'm building a fairly big documentation site with Jekyll which has right now a bit over 50 articles on it. It has a sidebar where all articles are listed. the sidebar is built in a separate sidebar.html and then it is included into every page on the site with {% include sidebar.html %} in default.html.
The problem I have is that every single article runs the generation of sidebar.html separately, so I have over 50 generation passes on that piece of code. Every article I add adds another pass to this and make all the passes a bit slower, as generating the sidebar has to parse every single article in the project.
Build time has gone up from basically zero to over 100 seconds already, and if I remove the {% include sidebar.html %} then it drops down to 5 seconds. When I get all the articles in I'd estimate to have around 100-200 of them. Then I should have versioning in the future for all articles which means that there can easily be 1000+ articles in the long run. At that point I wouldn't be suprised if changing one letter in one file would take something like an hour to regenerate files in jekyll serveand jekyll build.
What I would like to do is to build sidebar.html once in the beginning of the build process and just stamp it out to every page when i generate said pages. Is this possible?

Fastest way to do this.
Move _includes/sidebar.html to sidebar-template.html
Add this front matter :
---
layout: null
permalink: sidebar-template.html
---
Create a Rakefile
TPL = "_site/sidebar-template.html"
TST = "_includes/sidebar.html"
task :default => :nav
desc "Generates sidebar then copy it to be used as an include"
task :nav do
if !File.exist?(TST)
puts "Creating dummy #{TST} file"
open(TST, 'w') do |f|
f.puts warning
end
end
puts "Building Jekyll 1st run"
system "jekyll build --trace"
# delete target file (TST) if exist
if File.exist?(TST)
puts "#{TST} exists deleting it"
rm TST
end
# copy generated file as an include
cp(TPL, TST)
puts "Building Jekyll AGAIN"
system "jekyll build --trace"
puts "task END"
end
Just run rake and you have your sidebar include generated.

There is now a better way to do this, thanks to Ben Balter.
instead of: {% include yourtemplate.html %}
use: {% include_cached yourtemplate.html %}
When used on larger items that need to be built once, such as a site hierarchy, the item will be cached. For other items that vary across pages, you'll still want to use the include as you always have done.
It is explained well here: https://github.com/benbalter/jekyll-include-cache
Definitely cuts down on site startup time!

Related

add subfolders to _includes directory in Jekyll

I'm trying to add folders inside the "_includes" directory on Jekyll. It doesn't work. I've tried adding an underscore to the folder but it doesn't work either. What am I doing wrong? I'm using Jekyll 3.7.0
The most useful link I found about it was this one
Here are some screenshots:
And the stacktrace is:
Incremental build: disabled. Enable with --incremental
Generating...
Pagination: Pagination is enabled, but I couldn't find an index.html page to use as the pagination template. Skipping pagination.
Liquid Exception: Could not locate the included file 'sidebar.html' in any of [".../_includes"]. Ensure it exists in one of those directories and, if it is a symlink, does not point outside your site source. in /_layouts/page.html
jekyll 3.7.0 | Error: Could not locate the included file 'sidebar.html' in any of [".../_includes"]. Ensure it exists in one of those directories and, if it is a symlink, does not point outside your site source.
I think I'm supposed to be able to use sub-directories. What am I doing wrong? Thank you in advance!
Apparently, I found the problem. I don't know why but Jekyll is somehow able to parse comments. It detected I had commented a piece of code referencing the old sidebar.html.
As #DavidJaquel mentions in a comment below, HTML comments <!-- --> are not stopping Liquid to parse our page content, so we should be using Liquid syntax:
{% comment %}
...
{% endcomment %}

How to paginate posts by author

What I'm trying to do
Jekyll can use front matter variables like tags and categories and access them with site.tags and site.categories to iterate over them using liquid.
Now my problem is that I can't do this with a custom front matter variable like author (as in site.authors) because Jekyll will not store it in a list format. This makes it very hard to paginate it.
The problem
Every solution I have looked at i.e.
how to handle multiple authors in Jekyll
adding authors to Jekyll
jekyll-author
requires me to hardcode a list of authors to _config.yml or some other .yml (i.e. in _data/authors.yml).
The problem here is that I don't use a fixed list of authors. The authors list needs to get updated when I throw in another post with a front-matter tag author: exampleAuthor or a list of authors (as in multiple authors per post, as currently only possible with categories and tags as well), while the server is running. It works with tags and categories splendidly, but not with custom tags like authors.
The easiest solution would to have a site.authors list to iterate over and just extending it with a ruby plugin.
I haven't found a plugin that provides me with a solution and thinking this was a common problem that I'm probably not the first to have.
What I tried
I then looked at writing my own ruby plugin (Which is hard on it's own because of the lack of documentation. Maybe I'm to dumb to google, but the resources I found where very limited and hardly enough to guide you through the process) but there has to be a reason why this is so hard to do that makes all the existing solutions require hard-coding the author list in a .yml (or .json, but most people go with .yml for some reason).
Doing this is out of the question for me, since I want to only throw in posts with author names in it later on and manipulating a .yml (I am under the impression that .yml-files don't get compiled once the server is started, like _config.yml, correct me if I'm wrong) would be counterproductive because it requires you to restart the server to have them compiled.
Even very advanced plugins like jekyll-paginate-v2 (which I use successfully to paginate posts by tags and categories) don't have a solution to this, as shown by this issue. As per this issue, it is getting recommended to misuse the category variable to paginate by author. In my opinion, that is desperate workaround and too hacky to be considered.
I have found suggestions that it could also be done with collections, but this would again
requiring to hard-coding the author list (again, I don't want that. I don't have a fixed list of authors. All of the author information has to come from the front-matter in the /_posts directory .md files)
As of now I don't see how it can be done with collections.
However I'm open to suggestions.
Edit: I found this dated issue on Jekylls github page which highlights that people are trying to do the same but to no avail.
Has this become viable in the last 4 years?
For someone still looking for a way to
Generate author pages automatically just by dropping author: name to post front matter,
Have pagination on the author pages (a good optimization).
I built a plugin jekyll-auto-authors that works in sync with jekyll-paginate-v2 to enable author auto pages along with pagination.
I wrote this guide and made this video to help with the setup.
The bare minimum setup instructions:
Install the plugin:
group :jekyll_plugins do
# other gems
gem "jekyll-paginate-v2" # reqiured for jekyll-auto-authors to work
gem "jekyll-auto-authors"
end
Enable it:
plugins:
# other plugins
- jekyll-paginate-v2
- jekyll-auto-authors
Make a data file with author data, for example using _data/authors.yml:
johndoe:
name: "John Doe"
bio: "John Doe is a software engineer."
email: "john#example.com"
socials:
github: "john-doe"
twitter: "john_doe"
janedoe:
name: "Jane Doe"
bio: "Jane Doe is a systems engineer."
email: "jane#example.com"
socials:
github: "jane-doe"
twitter: "jane_doe"
Make a layout for the author page, let's say _layout/author.html. Example layout can be taken from the article.
Enable pagination and auto pages for authors in _config.yml file:
pagination:
enabled: true
per_page: 9
permalink: '/page/:num/'
title: ':title - page :num'
sort_field: 'date'
sort_reverse: true
autopages:
enabled: true
# enable auto pages for tags/categories/collections as per need. Disabling for this demo.
tags:
enabled: false
categories:
enabled: false
collections:
enabled: false
authors:
enabled: true # adding false here stops the auto-generation
data: '_data/authors.yml' # Data file with the author details
layouts:
- 'author.html' # We'll define this layout later, will be used for each author
title: 'Posts by :author'
permalink: '/author/:author/'
slugify:
mode: 'default' # choose from [raw, default, pretty, ascii or latin]
cased: true # if true, the uppercase letters in slug will be converted to lowercase ones.
That's the initial setup!
Now drop in the author value in the front matter of posts:
---
# other configs
author: johndoe
---
This will generate a page as defined in the permalink block of the auto pages configuration. If there's pagination enabled, and per_page value is exceeded, the additional pages will be generated in /page/:num/ format.
To render the author values, the plugin exposes page.pagination.author_data value
{% assign author = page.pagination.author_data %}
<!-- Use {{ author.name }} or any such value, as defined inside the data file -->
To show next and previous buttons, you can use this logic that paginator exposes:
{% if paginator.total_pages > 1 %}
<ul>
{% if paginator.previous_page %}
<li>
Newer
</li>
{% endif %}
{% if paginator.next_page %}
<li>
Older
</li>
{% endif %}
</ul>
{% endif %}
The initial setup is overwhelming, but once done you can then just drop in author data inside _data/authors.yml file and add author: value inside post frontmatter and it is fairly easy then!
P.S. I developed this solution for Genics Blog as managing multiple authors got hard. To learn how I've implemented it at Genics, please check out the theme-files repository.
Update
I released v1.0.1 just now, which makes adding the data parameter to author autopage configuration optional.
If data isn't defined, you can still access the author username string with page.pagination.author. You can use it to show the username on the page.
If data is defined, page.pagination.author_data variable is available. This would be a hashmap that has data as defined in the data file.
This means that you just have to:
Add and enable the plugin.
Set up pagination and author pages config.
Make a layout file.
And you can just drop in author: username to post files to generate autopages for them with pagination!
Adding authors to Jekyll posts is easy with collections. Here's a proof of concept for you. Specifically, in this commit I add everything you need for it.
As for your question about pagination, will need to use a pagination plugin (paginate-v2 is good), as I believe the built in pagination only supports the posts collection.

django allauth how to make a custom design html

I know there's a lot of documentation over the topic, this one, and this one but i couldn't find one that explains so that a 5 year old - or a designer - could understand :) .
My knowledge is html and css, and I need to design the templates for the user login process using Django AllAuth. I'm alone in this one, with no knowledge of python.
Someone please point me to some good documentation to help answering my question:
1 - How can I design each account/page html if I don't know what element is coming? Do I need to work on the views.py file? (possible to do so without any python knowledge?)
2 - how can I actually test all error messages without having to go thru all the login steps every time?
Thank you, guys
I did something like this. It was for django-registration, but the idea is the same.
-Go to github, and clone all the templates. In case, you are not familiar, there will be a folder called templates inside allauth app folder, and download the whole folder. Inside it , there will be base.html, and a folder called allauth.
-base.html is not needed, and you can delete it.
-inside all-auth folder, you will have a bunch of self-evident html files. Open the files, now, the only important content lies between {% block content %}{% endblock %}. Copy that to the html files you want, but make sure to have the same file name; otherwise, allauth woent recognize.
-If you want even more customization, run server, obtain the (soem name)" html codes, and you will see a bunch of html form fiels with id = "(some name)" and name = "". These are HTML fields. As long as you keep the same id and name for each field, you can use them however you want.
Summary: Run server with default allauth templates that you get from github. Go to source of the django generated html files. Copy all the fields that are relevant, and use them however you want.
I know I am not full clear, but it is somewhat a long process.
Here is the official django page: https://docs.djangoproject.com/en/dev/topics/forms/#customizing-the-form-template

How can a Jekyll page access its filename?

My goal is to create links from any published jekyll page back to its location on Github.
And so, I'd need access to a page's pathname when constructing this url. However, I don't see anything in the api for templates that provides this info. I looked at the source for page, but none of the file/path attributes had values, when accessed via the template.
Update: nowadays you can use {{page.path}}.
It seems like you can construct your link just fine using the liquid code: {{ page.url }}
For instance, if you want this page: http://railsdocs.org/pages/get-involved.html to link to this page: https://github.com/dogweather/railsdocs.org/blob/gh-pages/pages/get-involved.md
Seems like you could add something like:
[source](https://github.com/dogweather/railsdocs.org/blob/gh-pages/{{page.url | replace:'.html','.md'}})
to the markdown and get the link you want.
A more general solution:
Alternatively, we could write a generator that allows a page to access its file name directly. Add this to a .rb file in your _plugins directory:
module Jekyll
class PagePathGenerator < Generator
safe true
## See post.dir and post.base for directory information.
def generate(site)
site.posts.each do |post|
post.data['path'] = post.name
end
end
end
end
and then we can reliably get the post's filename as {{ page.path }}. This solution is more robust than converting from the URL, since page names can have characters that get 'sanitized' out when converting them to URLs. (Posts would also need their date information, etc added back in). Instead, this plugin gives us direct access to a post's name.
A similar strategy could allow us to get the path to the post if that data is also needed.
I'm not sure when this was added, but page.path gives the source file's path relative to the Jekyll root directory.

Jekyll use config.yml values in the HTML

Is it possible to setup configuration values within the config.yml file and have them be printed within the HTML page within Jekyll? I would like to set the default title and description of my website within the config.yml file and have them printed out in the header of all my layouts.
Every template has a site variable, which contains the settings from _config.yml. For example, if you have something like my_setting: "string" in _config.yml, you can access the value in a template using {{ site.my_setting }}.
Note: if you are using jekyll serve, you will need to restart the process for changes to take place. Indeed, _config.yml is not reloaded with the watch option.