23

I have an directory called /patterns in my Jekyll site, whose structure generally looks generally like this:

_includes _layouts _site /patterns index.html

I need to keep the /patterns directory outside _includes for a number of reasons, but mostly because I need to pull the files in /patterns into an iframe to display in a pattern library).

I'd like to include files from /patterns in my Jekyll pages, but using {% include /patterns/file.html %} doesn't work as it points to the_includesfolder. How would I go about including a file from a directory that isn't_includes`?

Brad Frost
  • 401
  • 1
  • 4
  • 9

10 Answers10

7

You can change the directory that the include tag uses with includes_dir in your _config.yml. It doesn't look like you can set multiple paths (source: https://jekyllrb.com/docs/configuration/).

In any case, the files in _includes don't end up in your output. You could separate pattern-specific includes into _includes/patterns/, but the only thing that'd have any effect on your live site would be where those files were included.

Ross
  • 2,701
  • 16
  • 25
7

You can choose to include file fragments relative to the current file by using the include_relative tag for your /patterns/file.html

enter image description here

For the directory structure you have:

_includes
_layouts
_site
/patterns/file.html
index.html

In this case the following doesn't work:

{% include /patterns/file.html %}

Use include_relative as /pattern is relatif to index.html as the current file:

{% include_relative patterns/file.html %}

Note:

You can't use the include_relative tag with any files inside your layouts folder. You can only use include_relative on a page or post. Layouts code is executed in the context of page/post rendering and the include_relative is calculated relative to this page or post, not from the layout itself.

In this case your code on index.html shall be:

---
layout: null
---
(put all code from _layouts/default.html)
{% include_relative patterns/file.html %}
eQ19
  • 9,880
  • 3
  • 65
  • 77
4

I think that collections will do what you need. They can be included and rendered as public html.

Here's an example project that does just this.

Ben Ubois
  • 49
  • 1
  • Thanks for this! I may be mistaken, but I think that prefixing the directory with an `_` means that Jekyll won't include that directory in `_site` when it compiles. For my use case, I need to include `/patterns` in `/_site` because I'm referencing those files in an iframe. – Brad Frost Sep 27 '16 at 22:05
  • 1
    Generally that is true about the underscore, however collections have a special option to write out publicly accessible html as well. I encourage you to download the sample project and run `jekyll build` to see how it works. – Ben Ubois Sep 27 '16 at 22:24
  • 1
    Also if you open the index.html file you can see how to include it both in liquid and in an iframe. – Ben Ubois Sep 27 '16 at 22:27
3

I put a symlink in place of the _includes directory that points where I want, since includes_dir doesn't seem to like ../ to specify a relative (one or more directories higher) path.

KFunk
  • 2,956
  • 22
  • 33
  • 1
    Does not work with Jekyll 3.8.5 and results in this error message `Ensure it exists in one of those directories and, if it is a symlink, does not point outside your site source.` – stefanglase Mar 03 '19 at 17:29
2

I improved the plugin that @Jeremy Lynch referred to. Here is the documentation:

include_absolute

Jekyll's built-in include tag does not support including files outside of the _includes folder. This plugin supports 4 types of includes:

  1. Absolute filenames (start with /).
  2. Filenames relative to the top-level directory of the Jekyll web site (Do not preface with . or /).
  3. Filenames relative to the user home directory (preface with ~).
  4. Executable filenames on the PATH (preface with !).

Syntax:

{% include_absolute path [ optionalParam1='yes' optionalParam2='green' ] %}

The optional parameters can have any name. The included file will have parameters substituted.

Installation

Copy include_absolute.rb into /_plugins and restart Jekyll.

Examples

  1. Include files without parameters; all four types of includes are shown.

    {% include_absolute '../../folder/outside/jekyll/site/foo.html' %}
    {% include_absolute 'folder/within/jekyll/site/bar.js' %}
    {% include_absolute '/etc/passwd' %}
    {% include_absolute '~/.ssh/config' %}
    
  2. Include a file and pass parameters to it.

    {% include_absolute '~/folder/under/home/directory/foo.html' param1='yes' param2='green' %}
    
Mike Slinn
  • 7,705
  • 5
  • 51
  • 85
  • 1
    I tried it but plugin does not working ... https://github.com/mslinn/jekyll-flexible-include-plugin/issues/2 ... What is wrong did I do? – TYPO3UA Nov 28 '20 at 11:50
  • The issue you opened at the URL you gave is sufficient, no need to repost here. As I said in my response, possible reasons for this error message are: - A directory called assets/js, based at the top of your Jekyll project, does not exist - The directory exists but does not contain a file called my.js - The directory and/or file lacks read permission. – Mike Slinn Nov 29 '20 at 14:25
0

You can change the root folder that include looks for files under to the root of your site by adding the following to _config.yml

include_dir: "."

You will then need to change any existing include calls to prefix the path with _includes/. For example:

{% include an_include.html %}

should become:

{% include _includes/an_include.html %}

Once done, you can then include files from under patterns using:

{% include patterns/file.html %}
Andrew Coates
  • 1,775
  • 1
  • 10
  • 16
0

None of the plugins referenced in other answers worked. So here's my plugin in 20 lines that did work for me:

class RootInclude < Liquid::Tag
  def initialize(_tag_name, markup, _parse_context)
    super
    @markup = markup.strip
  end

  def render(context)
    expanded_path = Liquid::Template.parse(@markup).render(context)
    root_path = File.expand_path(context.registers[:site].config['source'])
    final_path = File.join(root_path, expanded_path)
    read_file(final_path, context)
  end

  def read_file(path, context)
    file_read_opts = context.registers[:site].file_read_opts
    File.read(path, **file_read_opts)
  end
end

Liquid::Template.register_tag('root_include', RootInclude)

Create a folder called _plugins in the root of your project if you don't already have one. Then place a file there with this content. Then restart Jekyll.

Now in your pages, layouts and includes you can do this:

{%- root_include assets/blocks/code-sample.html -%}

or this:

{%- root_include /assets/blocks/code-sample.html -%}

or this:

{%- root_include ./assets/blocks/code-sample.html -%}

They're all the same.

If you have a post with front matter like this:

title: "My Post"
code:  /assets/blocks/code-sample.html
---

You can then do this:

{%- root_include {{ page.code }} -%}

If you have a post with front matter like this:

title: "My Post"
code:  code-sample.html
---

You can then do this:

{%- root_include /assets/blocks/{{ page.code }} -%}

After 7 years I find it incredible that such a basic use-case is still unsupported by Jekyll. I wanted exactly the same as Brad. I wanted to have a code-snippet in a single place, that I could both include and make available through an iframe. For whoever is interested, this is a simplified version of what I'm using:

{%- assign block_path = page.block.path | prepend: '/assets/blocks/' -%}
<div class="block-embed">
  <iframe src="{{ block_path }}" sandbox="allow-scripts allow-forms" marginwidth="0" marginheight="0" scrolling="no"></iframe>
  <a href="{{ block_path }}" target="_blank" class="open-new-tab-link">{%- include icons/new-tab.svg -%}</a>
</div>

<div class="block-source">
  {% highlight html linenos %}
    {%- root_include {{ block_path }} -%}
  {% endhighlight %}
</div>

I shouldn't need a custom plugin for this. It's just infuriating. I probably should just migrate to bridgetownrb.

Ashitaka
  • 19,028
  • 6
  • 54
  • 69
-1

In your _config.yml, you can add additional directories like so:

includes:
- patterns

Just as simple as that!

In action here on my Jekyll site: https://github.com/pschfr/pschfr.github.io/blob/master/_config.yml

Paul
  • 145
  • 2
  • 11
  • 2
    Great! If I set that option, will `/patterns` still compile and show up in `/_site`? – Brad Frost Sep 27 '16 at 21:01
  • If you put an index.html within `/patterns`, I believe so! – Paul Sep 27 '16 at 21:03
  • Hmmm, here's what I'm getting when I add your recommendation to my `_config.yml`: `Liquid Exception: Included file '_includes/patterns/file-name.html' not found`. To be clear, I'm trying to include the file like: `{% include /patterns/file-name.html %}` Maybe I'm doing that wrong? – Brad Frost Sep 27 '16 at 21:05
  • 1
    @BradFrost I think you need to remove the folder from the file path: `{% include file-name.html %}` – Nicolas Hoizey Sep 27 '16 at 21:08
  • Thanks for the answers! Unfortunately it still looks like it's looking in `_includes`: `Error: Included file '_includes/file-name.html' not found` is the error I'm getting. – Brad Frost Sep 27 '16 at 21:21
  • 10
    The `includes` setting is actually called `include`, and does not set additional folders for the `{% include %}` tag. It includes otherwise-excluded files/folders in the output. See https://jekyllrb.com/docs/configuration/ – Ross Sep 27 '16 at 21:58
  • 2
    @pschfr Can you show where you are calling an include from outside the _includes dir on your site? I'd like to see an example of how you are doing this, but can't see one. Thanks. – Seth Warburton Sep 28 '16 at 07:22
  • ^ they aren't including anything outside the `_includes` dir. clone the linked website and `grep -r '{%.\?include'`, it's only ever including `head.html`, `header.html`, `contact.html`, and `footer.html` which are all in the `_includes` dir – svenevs Apr 12 '17 at 03:28
-1

The ONLY solution I have found for this is to use this plugin

https://github.com/tnhu/jekyll-include-absolute-plugin

Jeremy Lynch
  • 6,780
  • 3
  • 52
  • 63
-1

this should be help https://jekyllrb.com/docs/configuration/default/

include_dir: ./pattern
Memet_
  • 19
  • 3