How to add exceptions to front-matter defaults in Jekyll? - jekyll

I have some front matter defaults in my _config.yaml file:
defaults:
- scope:
path: "./Articles"
values:
parent: Articles
nav_exclude: true
- scope:
path: "./Books"
values:
parent: Books
nav_exclude: true
Basically, it takes every file in the directory ./Articles and ./Books and makes it a child of the index files in the directory (github repo: https://github.com/Fr06t/reading-notes/). The problem is, it also makes the index files childs of themselves. Is there a way to exempt them?

The front matter defaults fill in the gaps for your front matter from your files targeted. If you want the index files to have a different value, the easiest way would be to add parent: null to those files.
e.g. ./Books/index.md:
---
parent: null
nav_exclude: false
# Existing front matter here as well
---
This null value would be prioritised over the defaults in your _config.yml. Alternatively, you could add another defaults entry for those files, you'd just want to check it's taking priority:
defaults:
- scope:
path: "./Articles/index.md"
values:
parent: null
nav_exclude: false

Related

Can I have a Jekyll collection that uses a date in its filename?

I need to build a Jekyll collection – events – that has a title, a date, and a few other front matter variables:
---
title: Tournament
date: 2018-03-09 00:00:00
date_end: 2018-03-01 20:00:00
description: A big tournament is coming.
---
My collection is configured as:
collections:
events:
output: true
I want these to exist in the _events folder like
- 2018-03-09-tournament.md
and to be output in _site like:
- /event/2018-03-09-tournament/index.html
I've tried many combinations of things on the permalink attribute in _config.yml, but am unable to get my event to render if it includes a date in the filename.
Is this possible? What am I missing?
You can configure permalink like this :
collections:
events:
output: true
future: true
permalink: "/event/:year-:month-:day-:name/index:output_ext"

Applying multiple layouts to same collection item in jekyll

I have a jekyll collection _persons, with multiple peoples' profiles. Now I want to create multiple layouts for each person, e.g., a "Publications", and a "Bio" subpage for the same person.
How can I associate different layouts with the same person object? I'd also like to use sub-urls, such as:
\personA\publications\
\personA\bio\
Assuming that "bios" are the content type that you will be editing, you might create a symlink in your project root from _bios to _publications:
# Unix/Linux
ln -s _bios _publications
If you use windows, you'll need to check out mklink.
Then set up your config.yml like this:
collections:
bios:
output: true
publications:
output: true
defaults:
-
scope:
path: "_bios"
values:
layout: bio
permalink: /biographies/:title/
-
scope:
path: "_publications"
values:
layout: publication
permalink: /publications/:title/
Edit markdown files for your people in the _bios directory, and do not specify layout or permalink in their frontmatter.
When your site builds, you'll get permalinks like example.com/publications/personA and example.com/bios/personA. You can loop through site.publications and site.bios as usual.
You'll need to define the bio and publication layouts, and these will have access to any data you define in the frontmatter of your bio collection items.
Credit for this idea: https://github.com/jekyll/jekyll/issues/3041#issuecomment-267730851
It might be more semantic to have a collection _persons as a single point of truth and make two symlinks from this collection.
Good luck!

Gulp concatenation with custom iteration ordering

I am attempting to concat a number of js files within a nested directory structure to a single file in a different location. They have to be concatenated in a specific order and I cannot find a way of changing the default order in which gulp's glob search retrieves nested files. I have tried various glob patterns to no avail.
My directory structure is as follows:
components
- componentA
- controllers
- controllerA1.js
- controllerA2.js
- services
- serviceA1.js
- configA.js
- moduleA.js
- componentB
- controllers
- controllerB1.js
- controllerB2.js
- services
- serviceB1.js
- configB.js
- moduleB.js
I want the files to concatenate to a single file in the following order:
configA.js
moduleA.js
controllerA1.js
controllerA2.js
serviceA1.js
configB.js
moduleB.js
controllerB1.js
controllerB2.js
serviceB.js
So that gulp iterates into each component and iterates down through as far as it can go before moving onto the next component and doing the same.
Instead it concatenates in the following order:
configA.js
moduleA.js
configB.js
moduleB.js
controllerA1.js
controllerA2.js
serviceA1.js
controllerB1.js
controllerB2.js
serviceB1.js
In other words it goes into a top level directory, iterates through each of the top level files in that directory and then jumps to the next top level directory and does the same, before returning to the first top level directory and iterating through the next level down etc etc.
I've tried a couple of different methods which have each presented problems.
I have tried using the gulp-recursive-folder plugin to customise the iteration order as follows:
gulp.task('generateTree', recursivefolder({
base: './components',
exclude: [ // exclude the debug modules from thus build
//'debug-modules'
]
}, function(folderFound){
//This will loop over all folders inside pathToFolder main and recursively on the children folders, secondary
//With folderFound.name gets the folderName
//With folderFound.path gets all folder path found
//With folderFound.pathTarget gets the relative path beginning from options.pathFolder
return gulp.src(folderFound.path + "/**/*.js")
.pipe($.concat("app.js"))
.pipe(gulp.dest('./build/assets/js/'));
}));
This iterates in the order I want but I believe it is writing the first top level dir as one stream and then writing the second dir as another stream so that the second stream overwrites the first. So I am left with only the following files being concatenated:
configB.js
moduleB.js
controllerB1.js
controllerB2.js
serviceB.js
So I've also tried using the add-stream plugin to recursively add to the same stream before writing to file. I won't bore anyone with the details but basically I can't get this to work as desired either. Can anyone recommend a post/tutorial/plugin? Thanks.
gulp.src() respects the ordering of globs that are passed to it and emits files in the same order. That means if you explicitly pass a glob for each component to gulp.src() it will first emit the files for the first component, then for the second component and so on:
gulp.task('default', function() {
return gulp.src([
'components/componentA/**/*.js',
'components/componentB/**/*.js'
])
.pipe($.concat('app.js'))
.pipe(gulp.dest('./build/assets/js/'));
});
Obviously you don't want to maintain that array manually. What you want to do is generate the array based on the components that are available in your project. You can use the glob module for that:
var glob = require('glob');
gulp.task('default', function() {
return gulp.src(glob.sync('components/*').map(c => c + '/**/*.js'))
.pipe($.concat('app.js'))
.pipe(gulp.dest('./build/assets/js/'));
});

Ansible testing variable type

I'm using an existing role, and I wish to modify it to extend its capabilities. Currently, one of its tasks is to create directories. These directories get passed as a variable containing a list of strings to the role, and then iterated over in a with_items statement. However, I would prefer to pass a list of dictionaries of the form e.g. {name: foo, mode: 751}.
So far so good; I can simply edit the role to make it take this sort of input. However, I also want to make it backwards compatible with the old format, i.e. where the items are strings.
Is there a way to test the type of a variable and then return different values (or perform different tasks) based on this? Perhaps using a Jinja2 filter? I was briefly looking at the conditionals listed in the manual, but nothing caught my eye that could be used in this situation.
You could use default() for backwards compatibility.
- file:
path: "{{ item.name | default(item) }}"
mode: "{{ item.mode | default(omit) }}"
state: directory
with_items: your_list
If the item has a name property, use it, else simply use the item itself.
Same goes for all other properties you might have in your dict. The special variable omit would omit the whole option from the task, as if no mode was passed to the file module. Of course you could set any other default.
Documentation references:
default
omit
The quickest solution would be to have two tasks, and have they trigger with opposed conditions. Unfortunately, all items in the list will have to use the same form (you can't mix and match strings and dicts).
- name: create dirs (strings)
file:
...
with_items: items
when: string(items[0])
- name: create dirs (dicts)
file:
...
with_items: items
when: not string(items[0])

Upload Files to custom location before date folder

I have built a custom contenttype with an image field in Bolt 2.0.
image:
type: image
If no folder is specified the uploaded file goes to a folder named by the year-month
Result: 2014-11/myFileName.jpg
With the tag upload I can change this to something else.
image:
type: image
upload: "News/"
Result: News/myFileName.jpg
Is it possible to get the year-month folders after my costom path?
Result: News/2014-11/myFileName.jpg
The answer to this is yes, but not very simply so if you want a configurable way to do this you need to wait for 2.1 of Bolt where we're going to add variables to the upload: setting.
If you don't mind setting up your own bootstrap file and modifying the application then you can do it now.
The date prefix is generated by the $app['upload.prefix'] setting and currently returns the date string. What you need to do to modify this is change this to your own closure. I haven't tested this on a project so tweak if needed but after:
$app->initialize();
// Redefine the closure
$app['upload.prefix'] = function() {
$setting = $app['request']->get('handler');
$parts = explode('://', $setting);
$prefix = rtrim($parts[0], '/') . '/';
return $prefix.date('Y-m') . '/';
};
$app->run();
What we're doing here is reading the setting which is passed in the request and then concatenating the default date prefix onto the end of it.
As mentioned earlier 2.1 will see variable support introduced into the paths so options like
upload: news/{%month%}/{%day%}
upload: uploads/{%contenttype%}/{%id%}
will be easily definable in the contenttypes.yml file so If you don't mind waiting for a couple of months then this is obviously much simpler.
As of 3.2.9 this {%id%} principle doesn't seem to work yet ... :(