Jekyll: Include a file from directory outside of _includes
Asked Answered
E

10

25

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`?

Ethelyn answered 27/9, 2016 at 20:53 Comment(0)
S
10

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 %}
Susysuter answered 16/5, 2018 at 18:42 Comment(0)
A
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.

Ariana answered 27/9, 2016 at 22:6 Comment(0)
C
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.

Carminecarmita answered 27/9, 2016 at 21:41 Comment(3)
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.Ethelyn
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.Carminecarmita
Also if you open the index.html file you can see how to include it both in liquid and in an iframe.Carminecarmita
P
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.

Photography answered 13/12, 2017 at 21:45 Comment(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.Shanon
W
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' %}
    
Windfall answered 2/10, 2020 at 17:8 Comment(2)
I tried it but plugin does not working ... github.com/mslinn/jekyll-flexible-include-plugin/issues/2 ... What is wrong did I do?Avitzur
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.Windfall
R
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 %}
Raggedy answered 15/11, 2022 at 11:16 Comment(0)
L
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's a bit mindboggling 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>

Very odd that we would need a custom plugin for this.

Lovieloving answered 11/2, 2023 at 14:45 Comment(0)
L
-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

Leatherwood answered 27/9, 2016 at 20:59 Comment(8)
Great! If I set that option, will /patterns still compile and show up in /_site?Ethelyn
If you put an index.html within /patterns, I believe so!Leatherwood
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?Ethelyn
@BradFrost I think you need to remove the folder from the file path: {% include file-name.html %}Photocathode
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.Ethelyn
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 jekyllrb.com/docs/configurationAriana
@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.Sommerville
^ 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 dirPeriderm
S
-1

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

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

Suomi answered 25/11, 2019 at 8:29 Comment(0)
U
-1

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

include_dir: ./pattern
Uhlan answered 9/10, 2022 at 7:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.