Published 2020-10-03.
Last modified 2023-05-18.
Time to read: 5 minutes.
jekyll_plugins
collection.
Jekyll's built-in include
tag does not support including files outside of the _includes
folder.
Originally called include_absolute
,
the tag plugin now does much more than just including absolute file names.
The plugin was renamed jekyll_flexible_include
,
and the tag is called flexible_include
.
This plugin now supports 4 types of includes:
-
Filenames relative to the top-level directory of the Jekyll web site.
It is unnecessary to preface these paths with
./
). -
Absolute filenames (first character is
/
). This feature can be modified or denied where security is a concern by specifying an array of Ruby glob expressions in theFLEXIBLE_INCLUDE_PATHS
environment variable. -
Filenames relative to the user home directory (first character is
~
). This feature can also be modified or denied where security is a concern by specifying an array of Ruby glob expressions in theFLEXIBLE_INCLUDE_PATHS
environment variable. -
Executable filenames on the
PATH
(first character is!
). This feature can be disabled by defining theDISABLE_FLEXIBLE_INCLUDE
environment variable before launching Jekyll.
In addition, filenames that require environment expansion because they contain a $
character are
expanded according to the environment variables defined when the jekyll build
process was launched.
Installation
Gem
Add the following highlighted line to your Jekyll project's Gemfile
,
within the jekyll_plugins
group:
group :jekyll_plugins do gem 'jekyll_flexible_include' end
And then execute:
$ bundle
Add the following to your Jekyll _config.yml
:
plugins: - flexible_include
CSS and Assets
Copy assets and CSS from the demo/
directory of the jekyll_flexible_include_plugin
GitHub project.
-
Copy
demo/assets/images/clippy.svg
to a directory of the same name in your Jekyll project. -
Copy
demo/assets/css/jekyll_flexible_include.css
to your Jekyll project assets directory. -
Copy
demo/assets/css/jekyll_plugin_support.css
to your Jekyll project assets directory. -
Copy
demo/assets/css/shared_include_pre.css
to your Jekyll project assets directory. -
Incorporate the CSS stylesheets into the appropriate layout in your Jekyll project:
_layouts/default.html{% assign nowMillis = site.time | date: '%s' %} <link rel="stylesheet" href="{{ '/assets/css/jekyll_flexible_include.css?v=' | append: nowMillis }}" type="text/css"> <link rel="stylesheet" href="{{ '/assets/css/jekyll_plugin_support.css?v=' | append: nowMillis }}" type="text/css"> <link rel="stylesheet" href="{{ '/assets/css/shared_include_pre.css?v=' | append: nowMillis }}" type="text/css">
JavaScript
Copy
demo/assets/js/clipboard.min.js
from thejekyll_flexible_include_plugin
GitHub project to your Jekyll project’s JavaScript directory.Modify the Jekyll layout or selected pages to load the JavaScript. You can load it from your project, as shown below, or from a CDN.
One way of loading JavaScript<script defer src="/assets/js/clipboard.min.js"></script>
Syntax
The following are equivalent:
- {% flexible_include path [ OPTIONS ] %}
- {% flexible_include 'path' [ OPTIONS ] %}
- {% flexible_include "path" [ OPTIONS ] %}
- {% flexible_include file='path' [ OPTIONS ] %}
- {% flexible_include file="path" [ OPTIONS ] %}
By default, the included file will escape characters
<
,{
and}
, unlessdo_not_escape
is specified. Note that the [square brackets] merely indicate optional parameters and are not intended to be written literally.The file must be specified as a relative or absolute path on the server, or a command to execute. A URL cannot be provided (you cannot write a file name that starts with
http:
orhttps:
). This capability is under consideration for a possible future release.Options
do_not_escape
includes the content without HTML escaping it.pre
causes the included file to be wrapped inside a<pre></pre>
tag, no label is generated.strip
removes leading and trailing whitespace.
The following options imply
pre
:copyButton
draws an icon at the top right of the<pre></pre>
area, which causes the included contents to be copied to the clipboard.download
uses the name of the file as a label, and displays it above the<pre></pre>
tag. Clicking the label causes the file to be downloaded. The file must be local to the Jekyll website.label
specifies that an automatically generated label be placed above the contents. There is no need to specify this option ifdownload
orcopyButton
options are provided.label="blah blah"
specifies a label for the contents; this value overrides the default label. The value can be enclosed in single or double quotes. If you want to display a text message other than the file name, use this option.number
numbers the lines.
Usage Examples
This example shows a typical set of options. A label is automatically generated from the file name or process output that is included:
HTML or markdown{% flexible_include copyButton download file="~/.mem_settings.yaml" %}
Here is what the above looks like when rendered by a web browser:
append_file_name: sample.html output_format: qt
... and without the
download
option, but still including thecopyButton
option:.mem_settings.yamlappend_file_name: sample.html output_format: qt
... now with just the
pre
option:.mem_settings.yamlappend_file_name: sample.html output_format: qt
... and finally this is the result of using
flexible_include
without any options. The generated text is outlined in a<pre></pre>
tag so it is noticable. The file has a trailing newline, which is apparent below, howeverflexible_include
trims any leading and trailing whitespace when thepre
keyword option is specified or implied, or when thestrip
keyword option is specified. You can disable this behavior by specifyingstrip=false
.append_file_name: sample.html output_format: qt
Dark Mode
Normally my website uses light colors, however some content displays better on a dark background. The
dark
option causes the generated <pre> tag to have thedark
class applied. You can define the CSS for thedark
anddarkLabel
classes. The CSS that defines those classes for this web site is here..mem_settings.yamlappend_file_name: sample.html output_format: qt
Home Directory
The included file path can use a tilde (
~
) to denote the user$HOME
directory.{% flexible_include ~/.mem_settings.yaml %}append_file_name: sample.html output_format: qt
Environment variables can be used; they will be expanded according to the environment variables that were current in the process when the Jekyll generator launched.
{% flexible_include '/home/mslinn/.gitconfig' %}[alias] lol=log --graph --decorate --pretty=oneline --abbrev-commit lola=log --graph --decorate --pretty=oneline --abbrev-commit --all ls=ls-files st = status ci = commit br = branch co = checkout df = diff dc = diff --cached dif = diff --word-diff=color --ignore-space-at-eol lg = log -p ign = ls-files -o -i --exclude-standard pwd = !pwd [branch "master"] remote = origin merge = refs/heads/master [core] filemode = false autocrlf = input safecrlf = false excludesfile = C:\\Users\\Mike Slinn\\Documents\\gitignore_global.txt pager = less -F [color] status = auto branch = auto ui = auto [gui] trustmtime = true [push] default = matching autoSetupRemote = true [user] name = Mike Slinn email = mslinn@mslinn.com [rebase] autostash = true [diff "exif"] textconv = exiftool [diff] compactionHeuristic = true renames = 0 [hub] protocol = git [pull] rebase = false [init] defaultBranch = master [log] date = local [creategem] githubuser = mslinn [nugem] githubuser = mslinn gemserver = "" [safe] directory = /mnt/f/work/ibm [credential] helper = store
Environment Variable Expansion
This example includes the output of running the bash command
which jekyll
, according to the Ruby environment that was current when the Jekyll generator was launched:{% flexible_include '!which jekyll' %}/home/mslinn/.rbenv/versions/3.1.2/bin/jekyll
Strip Leading and Trailing Whitespace
Sometimes a file or process contains leading or trailing whitespace.
{% flexible_include copyButton download .mem_settings.yaml %}
Renders as:
append_file_name: sample.html output_format: qt
The
strip
keyword option removes leading and trailing whitespace.{% flexible_include copyButton download strip .mem_settings.yaml %}
Renders as:
append_file_name: sample.html output_format: qt
Does This Make Your Brain Hurt?
Ready to have your mind twisted? This invocation:
Shell{% flexible_include '~/.mem_settings.yaml' download copyButton label='{% flexible_include download copyButton ~/.mem_settings.yaml %}' %}
Renders like this:
append_file_name: sample.html output_format: qt
Hint:
{
and}
are HTML entities for{
and}
, respectively.Highlighting Text
A regular expression can be passed to the
highlight
option. This causes text that matches the regex pattern to be wrapped within a<span class="bg_yellow"></span>
tag.The following highlights filenames in a directory listing that contain
django-admin
that might contain dots, underscores, dashes and forward slashes:HTML or markdown{% flexible_include highlight="[\w./\-_]*django-admin[\w.\-_]*" label="ls ~/venv/aw/bin/*" file="!ls ~/venv/aw/bin/*" %}
Renders as:
ls ~/venv/aw/bin/*/home/mslinn/venv/aw/bin/activate /home/mslinn/venv/aw/bin/activate.csh /home/mslinn/venv/aw/bin/activate.fish /home/mslinn/venv/aw/bin/activate.ps1 /home/mslinn/venv/aw/bin/activate.xsh /home/mslinn/venv/aw/bin/activate_this.py /home/mslinn/venv/aw/bin/django-admin /home/mslinn/venv/aw/bin/django-admin.py /home/mslinn/venv/aw/bin/easy_install /home/mslinn/venv/aw/bin/easy_install-3.8 /home/mslinn/venv/aw/bin/easy_install3 /home/mslinn/venv/aw/bin/faker /home/mslinn/venv/aw/bin/pip /home/mslinn/venv/aw/bin/pip3 /home/mslinn/venv/aw/bin/pip3.10 /home/mslinn/venv/aw/bin/pip3.11 /home/mslinn/venv/aw/bin/pybabel /home/mslinn/venv/aw/bin/python /home/mslinn/venv/aw/bin/python3 /home/mslinn/venv/aw/bin/python3.8 /home/mslinn/venv/aw/bin/sqlformat /home/mslinn/venv/aw/bin/wheel /home/mslinn/venv/aw/bin/wheel-3.8 /home/mslinn/venv/aw/bin/wheel3 /home/mslinn/venv/aw/bin/__pycache__: django-admin.cpython-39.pyc
Numbering Lines
HTML or markdown{% flexible_include label="ls ~/venv/aw/*" file="!ls ~/venv/aw/*" number %}
Renders as (notice that the numbers are unselectable):
ls ~/venv/aw/*1: /home/mslinn/venv/aw/pyvenv.cfg 2: 3: /home/mslinn/venv/aw/bin: 4: __pycache__ 5: activate 6: activate.csh 7: activate.fish 8: activate.ps1 9: activate.xsh 10: activate_this.py 11: django-admin 12: django-admin.py 13: easy_install 14: easy_install-3.8 15: easy_install3 16: faker 17: pip 18: pip3 19: pip3.10 20: pip3.11 21: pybabel 22: python 23: python3 24: python3.8 25: sqlformat 26: wheel 27: wheel-3.8 28: wheel3 29: 30: /home/mslinn/venv/aw/lib: 31: python3.10 32: python3.11 33: python3.8 34: python3.9
CSS
Below are the CSS declarations that I defined for the
flexible_include
tag that produced the above output. This CSS is the same as used bypre
..clear { clear: both; } ol li .codeLabel { padding-left: 1.75em; } .error { color: white; background-color: darkred; padding: 2px; } #main-content li > div.jekyll_pre, li > div.jekyll_pre { margin-top: 20px; } .jekyll_pre + div, .jekyll_pre + p, .jekyll_pre + ul, .jekyll_pre + ol, .jekyll_pre + dl { margin-top: 20px; } .jekyll_pre + .jekyll_pre { margin-top: 2em; } .pre_tag { margin-bottom: 1em; } .tree { line-height: 1; }
Restricting Directory Access
By default,
flexible_include
can read from all directories according to the permissions of the user account that launched thejekyll
process. For security-conscience environments, the accessible paths can be restricted.Defining an environment variable called
FLEXIBLE_INCLUDE_PATHS
prior to launching Jekyll will restrict the paths thatflexible_include
will be able to read from. This environment variable consists of a colon-delimited set of regular expressions. For example, the following restricts access to only the files within:- The
~/my_dir
directory tree of the account of the user that launched Jekyll. - The directory tree rooted at
/var/files
. - The directory tree rooted at the expanded value of the
$work
environment variable.
Shell$ export FLEXIBLE_INCLUDE_PATHS='~/my_dir/.*:/var/files/.*:$work/.*'
If a reference to an unauthorized file is intercepted, a big red message will appear on the generated web page that says something like
Access to #{path} denied by FLEXIBLE_INCLUDE_PATHS value.
... and an error message will be logged on the console that looks something like:
ERROR FlexibleInclude: _posts/2020/2020-10-03-jekyll-plugins.html - Access to #{path} denied by FLEXIBLE_INCLUDE_PATHS value.
Restricting Arbitrary Processes
By default,
flexible_include
can execute any command. You can disable that by setting the environment variableDISABLE_FLEXIBLE_INCLUDE
to any non-empty value.Shell$ export DISABLE_FLEXIBLE_INCLUDE=true
If a potential command execution is intercepted, a big red message will appear on the generated web page that says:
Arbitrary command execution denied by DISABLE_FLEXIBLE_INCLUDE value.
... and an error message will be logged on the console that looks something like:
ERROR FlexibleInclude: #{path} - Arbitrary command execution denied by DISABLE_FLEXIBLE_INCLUDE value.