How to pass a variable to the include tag #176

Closed
StefanLiebenberg opened this Issue Jun 18, 2010 · 18 comments

Comments

Projects
None yet

How can I implement something like

{% for entry in entries %}
{% include $entry %}
{% endfor %}

Thank you

That would be very usefull but not supported by Jekyll right now! Any plan to support it on the future?

This would indeed be very useful. +1.

c-abird commented Apr 7, 2012

I just monkey patched the include tag with a plugin:

# _plugins/include_patch.rb
module Jekyll

  class IncludeTag < Liquid::Tag
    def render(context)
      @file = context[@file] || @file
      includes_dir = File.join(context.registers[:site].source, '_includes')

      if File.symlink?(includes_dir)
        return "Includes directory '#{includes_dir}' cannot be a symlink"
      end 

      if @file !~ /^[a-zA-Z0-9_\/\.-]+$/ || @file =~ /\.\// || @file =~ /\/\./
        return "Include file '#{@file}' contains invalid characters or sequences"
      end 

      Dir.chdir(includes_dir) do
        choices = Dir['**/*'].reject { |x| File.symlink?(x) }
        if choices.include?(@file)
          source = File.read(@file)
          partial = Liquid::Template.parse(source)
          context.stack do
            partial.render(context)
          end 
        else
          "Included file '#{@file}' not found in _includes directory"
        end 
      end 
    end 
  end 

end

I just added

@file = context[@file] || @file

Dirty, but works for me.

Did this ever get made into a pull request for Jekyll? Definitely looking at having this so I can have dynamic includes based on page variables. Very, very useful to have.

@c-abird c-abird added a commit to c-abird/jekyll that referenced this issue Jul 3, 2012

@c-abird c-abird Fix #176 : Allow variables as include tag argument d316894

c-abird commented Jul 3, 2012

I just sent a pull request: mojombo#593

What about the inclusion of multiple fragments? Suppose that I have a page with:

----
...
incluir:
 - porque-emap.html
 - porque-matematica-aplicada.html
 - vestibular.html
---

And in the layout file something like:

{% for i in page.incluir %}
   {% include i %}
{% endfor %}

Why is it not working? It is only including the first file. The loop is working but not the include tag. I mean, If I write

{% for i in page.incluir %}
   {{ i }}
{% endfor %}

the names of the files are correctly listed in the output.

c-abird commented Jul 4, 2012

OK, that's a bug. Use this code instead

# _plugins/include_patch.rb
module Jekyll

  class IncludeTag < Liquid::Tag
    def render(context)
      file = context[@file] || @file
      includes_dir = File.join(context.registers[:site].source, '_includes')

      if File.symlink?(includes_dir)
        return "Includes directory '#{includes_dir}' cannot be a symlink"
      end

      if file !~ /^[a-zA-Z0-9_\/\.-]+$/ || file =~ /\.\// || file =~ /\/\./
        return "Include file '#{file}' contains invalid characters or sequences"
      end

      Dir.chdir(includes_dir) do
        choices = Dir['**/*'].reject { |x| File.symlink?(x) } 
        if choices.include?(file)
          source = File.read(file)
          partial = Liquid::Template.parse(source)
          context.stack do
            partial.render(context)
          end
        else
          "Included file '#{file}' not found in _includes directory"
        end
      end
    end
  end

end```

Hum.. What is the difference between the @file and file vars? I mean, in that context, what is the difference between the local var and the instance var?

c-abird commented Jul 4, 2012

The @file variable is set in the constructor of the include tag class. Apparently the constructor is called only once in the context of the for loop. The @file variable contains the argument of the include call, which is the string "i" in your case. If @file is overwritten with the value of the variable i at the first call of render this value remains for the rest o the loop.

Rutix commented Aug 5, 2012

Precisely what I needed! Thanks c-abird. +1

Rutix commented Aug 10, 2012

After playing with it for some days I noticed that this breaks some functionality which was allowed before this change.

If you have an include file called "pages" (note: no extension).
And you do this in a layout template:

<div id="contents">
    {% assign pages = site.pages %}
    {% include pages %}
    {{ content }}
</div>

It wont use the include file "pages" but it will display the message: "Include file '#{#.#}' contains invalid characters or sequences" . This is i think because the context[@file] will look this:

[#<Jekyll:Page @name="index.html">, #<Jekyll:Page @name="otherpage.html">] 

which of course fails. I don't know how we would be able to solve this without putting some restrictions on one or the other.

gnuwilliam referenced this issue in braziljs/conf-boilerplate Sep 20, 2012

Closed

Dynamically include active sections #3

Contributor

qrush commented Jan 2, 2013

This is getting super close to partials, and ERB. I'm pretty convinced that if you need this kind of layout, you need something more like Sinatra or Rails than Jekyll. Jekyll is just dynamic enough...and this pushes it too far IMO. Closing for now.

qrush closed this Jan 2, 2013

qrush referenced this issue Jan 2, 2013

Closed

Fix for #176 #593

Hello @c-abird, I have being using your include tag patch and everything was working fine until my last upgrade to jekyll 1.0.0. Any idea why your patch doesn't work anymore? I am not a ruby programmer. This makes my understanding of the jekyll include plugin a bit harder than expected! ;-)

Solved with a simple chance. The class now is created inside the module Tags

module Jekyll
  module Tags
    class IncludeTag < Liquid::Tag
    ....
    end
  end
end

This is very helpful, but i think breaks the option to include parameters with your include. I'm a designer and don't know much ruby unfortunately.

Hoping to accomplish something like this:

 {% include {{variable}} param="value" %}
Contributor

maul-esel commented Sep 12, 2013

#1495 is an attempt to include this in the core (while preserving parameter functionality).

#1495 is an attempt

Being able to do the same with a plugin response would be handy, though nested plugins might get messy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment