Flexible_include is a Jekyll plugin that includes the contents of a file
or the result of a process into a generated page.
Flexible_include is useful because Jekyll's built-in include tag only
supports the including of files residing within the _includes/ subfolder of a Jekyll project,
and because flexible_include offers additional ways of including content.
Originally called include_absolute,
this plugin has been renamed to flexible_include because it no longer just
includes absolute file names.
This plugin is available as a Ruby gem. More information is available on my website about my Jekyll plugins.
This plugin supports 4 types of includes:
Include Types
-
Absolute filenames (recognized by filename paths that start with
/). -
Filenames relative to the top-level directory of the Jekyll website (relative paths do not start with
.or/). -
Filenames relative to the user home directory (recognized by filename paths starting with
~/). -
Executable filenames on the
PATH(recognized by filename paths that begin with!).
In addition, filenames that require environment expansion because they contain a
$ character are expanded according to the environment variables
defined when jekyll build executes.
A file from a git repository can also be included. Files can be retrieved from at a given commit or tag. Two new options are provided for this purpose:
-
repo- directory where git repo resides; environment variables are expanded; defaults to current directory. -
git_ref- Git ref of commit or tag to be examined for the file; defaults toHEAD.
Configuration
Configuration parameters can be added to a section in _config.yml called flexible_include, like this:
flexible_include:
die_on_file_error: true
die_on_path_denied: true
die_on_run_error: true
die_on_other_error: trueThe default values for all of these parameters is false,
except for die_on_other_error, which defaults to true.
-
If
die_on_file_erroris enabled, then an attempt to include a file that fails will cause Jekyll to die with an error message. -
If
die_on_path_deniedis enabled (see Restricting Directory Access), then an attempt to include a file that should be blocked will cause Jekyll to die with an error message. -
If
die_on_run_erroris enabled, then an attempt to run a process that fails will cause Jekyll to die with an error message. -
If
die_on_other_erroris enabled, then any other exception will cause Jekyll to die with an error message.
Syntax
The following are all equivalent, however, the first two are recommended:
{% flexible_include file="path" [ OPTIONS ] %}
{% flexible_include file='path' [ OPTIONS ] %}
{% flexible_include path [ OPTIONS ] %}
{% flexible_include 'path' [ OPTIONS ] %}
{% flexible_include "path" [ OPTIONS ] %}Note that the [square brackets] merely indicate optional parameters and are not intended to be written literally.
Options
-
attributionseejekyll_plugin_support -
do_not_escapekeyword option caused the content to be included without HTML escaping it. By default, the included file will escape characters<,{and}unless thedo_not_escapekeyword option is specified. -
from='regex'specifies that the beginning of the output should discarded until the matching string or regex is encountered. -
highlight='regex pattern here'wraps content matching the regex pattern within a<span class='bg_yellow_nopad'></span>tag. Note that the pattern can simply consist of the exact text that you want to highlight. -
preis a keyword option that causes the included file to be wrapped inside a <pre></pre> tag; no label is generated. The <pre></pre> tag has andata-lt-active="false"attribute, so LanguageTool will not attempt to check the spelling or grammar of the contents. -
to='regex'specifies that the output should discarded after the matching string or regex is encountered (includes the matched line). -
until='regex'specifies that the output should discarded after the matching string or regex is encountered (excludes the matched line).
The following options imply pre:
-
darkkeyword option applies thedarkclass to the generated <pre></pre> tag. You can define thedarkanddarkLabelclasses as desired. This CSS is a good starting point. -
downloadkeyword option 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. -
copyButtonkeyword option draws an icon at the top right of the <pre></pre> tag that causes the included contents to be copied to the clipboard. -
labelkeyword option specifies that an automatically generated label be placed above the contents. There is no need to specify this option ifdownloadorcopy_buttonoptions 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.
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
file and directory glob patterns.
For example, the following restricts access to only the files within:
-
The
~/my_dirdirectory 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
$workenvironment variable.
export FLEXIBLE_INCLUDE_PATHS='~/.*:$sites/.*:$work/.*'Note that the above matches dot (hidden) files as well as regular files. To just match visible files:
export FLEXIBLE_INCLUDE_PATHS='~/my_dir/**/*:/var/files/**/*:$work/**/*'Note
The specified directories are traversed when the plugin starts, and the filenames are stored in memory. Directories with lots of files might take a noticable amount of time to enumerate the files.
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=trueIf 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 a red error message will be logged on the console that says something like:
ERROR FlexibleInclude: _posts/2020/2020-10-03-jekyll-plugins.html - Arbitrary command execution denied by DISABLE_FLEXIBLE_INCLUDE value.
Installation
Gem
-
Add the following to
Gemfile, inside thejekyll_pluginsgroup:group :jekyll_plugins do gem 'jekyll_flexible_include', '~> 2.0.15' end
-
Add the following to
_config.yml. This is necessary because the name of the plugin does not match the name of the entry point file:plugins: - flexible_include
-
Copy
demo/assets/images/clippy.svgto a directory that resolves toassets/images/in your Jekyll website. -
Copy the CSS from
demo/assets/css/jekyll_flexible_include.cssto your Jekyll project's CSS file. -
Install the
jekyll_flexible_includeRuby gem and mark it as a dependency of your project:$ bundle
CSS and Assets
Copy assets and CSS from the demo/ directory of the jekyll_pre GitHub project.
- Copy
demo/assets/images/clippy.svgto a directory of the same name in your Jekyll project. - Copy
demo/assets/css/jekyll_plugin_support.cssto your Jekyll project assets directory. - Copy
demo/assets/css/shared_include_pre.cssto your Jekyll project assets directory. - Copy
demo/assets/css/jekyll_flexible_include.cssto your Jekyll project assets directory. - Incorporate the CSS stylesheets into the appropriate layout in your Jekyll project:
{% assign nowMillis = site.time | date: '%s' %}
<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">
<link rel="stylesheet" href="{{ '/assets/css/jekyll_flexible_include.css?v=' | append: nowMillis }}" type="text/css">JavaScript
Copy demo/assets/js/clipboard.min.js from the jekyll_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.
<script defer src="/assets/js/clipboard.min.js"></script>Examples
-
Include files, escaping any HTML markup, so it appears as written; all four types of includes are shown.
{% flexible_include '../../folder/outside/jekyll/site/foo.html' %} {% flexible_include 'folder/within/jekyll/site/bar.js' %} {% flexible_include '/etc/passwd' %} {% flexible_include '~/.ssh/config' %} {% flexible_include '!jekyll help' %} {% flexible_include '$HOME/.bash_aliases' %} -
Include a JSON file (without escaping characters).
{% flexible_include do_not_escape file='~/folder/under/home/directory/foo.html' %}
Additional Information
The complete documentation is available on Mike Slinn’s website.
Topics that are not mentioned in this README.md file include:
- How environment variables are expanded on Linux, Mac and Windows.
- Numbering lines.
GitHub Pages
GitHub Pages only allows these plugins.
That means flexible_include will not work on GitHub Pages.
Following is a workaround.
-
Let's assume your git repository that you want to publish as GitHub Pages is called
mysite. This repository cannot be the source of your GitHub Pages because you are using theflexible_includeplugin. -
Make a new git repository to hold the generated website. Let's call this git repository
generated_site. -
Generate
mysitelocally as usual. -
Copy the generated HTML in the
mysite/_site/directory togenerated_site. -
Run
git commitongenerated_site. -
Tell GitHub that you want the
generated_siterepository to hold your GitHub pages. -
A moment later, your website will now be visible as GitHub Pages, with the included content, just as you saw it locally.
Known Issues
If the plugin does not work:
-
Ensure
_config.ymldoesn't havesafe: trueset. That prevents all plugins from working. -
If you have version older than v2.x.x, delete the file
_plugins/flexible_include.rb, or you will have version conflicts.
Development
After checking out the repo, run bin/setup to install dependencies as binstubs in the exe directory.
You can also run bin/console for an interactive prompt that will allow you to experiment.
Build and Install Locally
To build and install this gem onto your local machine, run:
$ bundle exec rake installExamine the newly built gem:
$ gem info jekyll_flexible_include
*** LOCAL GEMS ***
jekyll_flexible_include (2.0.4)
Authors: Mike Slinn, Tan Nhu, Maarten Brakkee
Homepage: https://www.mslinn.com/blog/2020/10/03/jekyll-plugins.html#flexibleInclude
License: MIT
Installed at (2.0.4): /home/mslinn/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0
Jekyll plugin supports various ways to include content into the
generated site.Demo Website
A test/demo website is provided in the demo directory.
You can run it under a debugger, or let it run free.
The demo/_bin/debug script can set various parameters for the demo.
View the help information with the -h option:
$ demo/_bin/debug -h
debug - Run the demo Jekyll website.
By default the demo Jekyll website runs without restriction under ruby-debug-ide and debase.
View it at http://localhost:4444
Options:
-e Restrict the allowable directories to read from to the following regexes:
jekyll_flexible_include_plugin/.*
/dev/.*
/proc/.*
/run/.*
-h Show this error message
-r Run freely, without a debugger
-x Disable the ability to execute arbitrary commandsDebugging the Demo
To run under a debugger, for example Visual Studio Code:
-
Set breakpoints.
-
Initiate a debug session from the command line:
$ demo/bin/debug
-
Once the
Fast Debuggersignon appears, launch the Visual Studio Code launch configuration calledAttach rdbg. -
View the generated website at
http://localhost:4444.
Build and Push to RubyGems
To release a new version,
-
Update the version number in
version.rb. -
Add a comment to the top of
CHANGELOG.md. -
Commit all changes to git; if you don't the next step will fail.
-
Run the following:
$ bundle exec rake releaseThe above creates a git tag for the version, commits the created tag, and pushes the new
.gemfile to RubyGems.org.
Contributing
- Fork the project
- Create a descriptively named feature branch
- Add your feature
- Submit a pull request
License
The gem is available as open source under the terms of the MIT License.