Published 2020-10-03.
Last modified 2023-05-18.
Time to read: 5 minutes.
jekyll_plugins
collection, categorized under Jekyll.
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
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
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 }
,
unless do_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:
or https:
).
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.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:
{% flexible_include ~/.mem_settings.yaml download copyButton %}
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 the copyButton
option:
append_file_name: sample.html output_format: qt
... now with just the pre
option:
append_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,
however flexible_include
trims any leading and trailing whitespace when the
pre
keyword option is specified or implied,
or when the strip
keyword option is specified.
You can disable this behavior by specifying strip=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 the dark
class applied.
You can define the CSS for the dark
and darkLabel
classes.
The CSS that defines those classes for this web site is here.
append_file_name: sample.html output_format: qt
Home Directory
The included file path can use a tilde (~
) to denote the user $HOME
directory.
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.
[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 [branch "master"] remote = origin merge = refs/heads/master [core] filemode = false autocrlf = input safecrlf = false excludesfile = C:\\Users\\Mike Slinn\\Documents\\gitignore_global.txt [color] status = auto branch = auto ui = auto [gui] trustmtime = true [push] default = matching autoSetupRemote = true autoSetupRemote = true [user] name = Mike Slinn email = mslinn@mslinn.com [rebase] autostash = true [diff "exif"] textconv = exiftool [diff] compactionHeuristic = true [init] defaultBranch = master [pull] rebase = false
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:
/home/mslinn/.rbenv/versions/3.1.0/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:
{% 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:
{% flexible_include highlight="[\w./\-_]*django-admin[\w.\-_]*" label="ls ~/venv/aw/bin/*" file="!ls ~/venv/aw/bin/*" %}
Renders as:
/home/mslinn/venv/aw/bin/Activate.ps1 /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/pip /home/mslinn/venv/aw/bin/pip3 /home/mslinn/venv/aw/bin/pip3.10 /home/mslinn/venv/aw/bin/python /home/mslinn/venv/aw/bin/python3 /home/mslinn/venv/aw/bin/python3.10
Numbering Lines
{% flexible_include label="ls ~/venv/aw/*" file="!ls ~/venv/aw/*" number %}
Renders as (notice that the numbers are unselectable):
1: /home/mslinn/venv/aw/pyvenv.cfg 2: 3: /home/mslinn/venv/aw/bin: 4: Activate.ps1 5: activate 6: activate.csh 7: activate.fish 8: pip 9: pip3 10: pip3.10 11: python 12: python3 13: python3.10 14: 15: /home/mslinn/venv/aw/include: 16: 17: /home/mslinn/venv/aw/lib: 18: python3.10 19: 20: /home/mslinn/venv/aw/lib64: 21: python3.10
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 by pre
.
/* Shared between jekyll_pre and jekyll_flexible_include_plugin */ .jekyll_pre { display: inline-block; margin-bottom: 30px; max-width: 100%; width: 100%; } .jekyll_pre + ul, .jekyll_pre + ol, .jekyll_pre + dl { margin-top: 0; } pre.dark { color: #eee; background-color: #222; } pre.dark .unselectable, pre.dark .unselectable > code { color: rgb(155, 150, 150); } .bg_yellow { background-color: yellow; padding: 2px; } .codeLabel { color: white; background-color: #666; display: flow-root; font-family: $mono-font; font-stretch: semi-condensed; margin-bottom: 0; padding-bottom: 2px; padding-left: 10px; padding-right: 10px; padding-top: 2px; } .darkLabel { color: ivory; } li div.codeLabel { padding-left: 2em; } .clear { clear: both; } .codeLabel.unselectable, div.codeLabel.unselectable > code { color: yellow; } .codeLabel + pre { margin-top: 0; } .codeLabel a { color: #c0e6fb; } .codeLabel a:hover { color: #FFE59F; } .copyBtn { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; background-color: #eee; background-image: linear-gradient(#fcfcfc, #eee); border: 1px solid #d5d5d5; border-radius: 3px; color: #333; cursor: pointer; float: right; font-size: 13px; font-weight: 700; line-height: 20px; padding: 2px 2px 0 4px;; position: -webkit-sticky; position: sticky; right: 4px; top: 0; user-select: none; z-index: 1; } .copyContainer { position: relative; } ol li .codeLabel { padding-left: 1.75em; } .maxOneScreenHigh { max-height: 500px; } .numbered_line, .unselectable.numbered_line, .numbered_line.unselectable { color: #5fb25f; } .unselectable { color: #7922f9; -moz-user-select: none; -khtml-user-select: none; user-select: none; } .wrap_pre { white-space: pre-wrap; } /* Added for jekyll_pre v1.2.2 */ .error { color: white; background-color: darkred; padding: 2px; } /* Flexible include only */ .flexible_error { color: white; background-color: red; padding: 2pt 1em 2pt 1em; } .flexible_error code { color: lightgray; font-size: 9pt; }
Restricting Directory Access
By default, flexible_include
can read from all directories according to the
permissions of the user account that launched the jekyll
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 that flexible_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.
$ 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 variable DISABLE_FLEXIBLE_INCLUDE
to any non-empty value.
$ 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.