Skip to content

Instantly share code, notes, and snippets.

@jgatjens
Created February 10, 2014 22:03
Show Gist options
  • Save jgatjens/8925165 to your computer and use it in GitHub Desktop.
Save jgatjens/8925165 to your computer and use it in GitHub Desktop.
jekyll-plugin loop_directory
#usage:
#{% loop_directory directory:images iterator:image filter:*.jpg sort:descending %}
# <img src="{{ image }}" />
#{% endloop_directory %}
module Jekyll
class LoopDirectoryTag < Liquid::Block
include Liquid::StandardFilters
Syntax = /(#{Liquid::QuotedFragment}+)?/
def initialize(tag_name, markup, tokens)
@attributes = {}
@attributes['directory'] = '';
@attributes['iterator'] = 'item';
@attributes['filter'] = 'item';
@attributes['sort'] = 'ascending';
# Parse parameters
if markup =~ Syntax
markup.scan(Liquid::TagAttributes) do |key, value|
@attributes[key] = value
end
else
raise SyntaxError.new("Bad options given to 'loop_directory' plugin.")
end
#if @attributes['directory'].nil?
# raise SyntaxError.new("You did not specify a directory for loop_directory.")
#end
super
end
def render(context)
context.registers[:loop_directory] ||= Hash.new(0)
images = Dir.glob(File.join(@attributes['directory'], @attributes['filter']))
if @attributes['sort'].casecmp( "descending" ) == 0
# Find files and sort them reverse-lexically. This means
# that files whose names begin with YYYYMMDD are sorted newest first.
images.sort! {|x,y| y <=> x }
else
# sort normally in ascending order
images.sort!
end
result = []
context.stack do
# remove filename extension
images.each { |pathname|
context[@attributes['iterator']] = File.basename(pathname, @attributes['filter'].sub('*', ''))
result << render_all(@nodelist, context)
}
# return pathname
# images.each_with_index do |item, index|
# context[@attributes['iterator']] = item
# result << render_all(@nodelist, context)
# end
end
result
end
end
end
Liquid::Template.register_tag('loop_directory', Jekyll::LoopDirectoryTag)
@lmmx
Copy link

lmmx commented Nov 8, 2015

@planemad
Copy link

@jgatjens this is an amazing plugin and should probably be probably be part of liquid!

I'm trying to pass a variable subdirectory to loop through but can't get it to work. Something like this:

{% loop_directory directory:{{page.url | remove_first: "/"}}thumbnail

I'm looking through stackoverflow questions on passing variables as arguments in liquid, but can't get any to work.

@adenta
Copy link

adenta commented Mar 26, 2016

@planemad, were you able to get this working? This seems like a common use case. I am trying to solve the same problem as well.

@adenta
Copy link

adenta commented Mar 26, 2016

For now I am using the solution presented here.

@skuzzymiglet
Copy link

I get a

> jekyll serve --trace 
Configuration file: /home/skuzzymiglet/ysgol/gwefan-jekyll/_config.yml 
            Source: /home/skuzzymiglet/ysgol/gwefan-jekyll 
       Destination: /home/skuzzymiglet/ysgol/gwefan-jekyll/_site 
 Incremental build: disabled. Enable with --incremental 
      Generating... 
  Liquid Exception: undefined method `render_all' for #<Jekyll::LoopDirectoryTag:0x000056284e5f07e0> in index.md 
Traceback (most recent call last): 
        41: from /home/skuzzymiglet/.gem/ruby/2.6.0/bin/jekyll:23:in `<main>' 
        40: from /home/skuzzymiglet/.gem/ruby/2.6.0/bin/jekyll:23:in `load' 
        39: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/exe/jekyll:15:in `<top (required)>' 
        38: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/mercenary-0.3.6/lib/mercenary.rb:19:in `program' 
        37: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/mercenary-0.3.6/lib/mercenary/program.rb:42:in `go' 
        36: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/mercenary-0.3.6/lib/mercenary/command.rb:220:in `execute' 
        35: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/mercenary-0.3.6/lib/mercenary/command.rb:220:in `each' 
        34: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/mercenary-0.3.6/lib/mercenary/command.rb:220:in `block in execute' 
        33: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/commands/serve.rb:86:in `block (2 levels) in init_with_program' 
        32: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/command.rb:89:in `process_with_graceful_fail' 
        31: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/command.rb:89:in `each' 
        30: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/command.rb:89:in `block in process_with_graceful_fail' 
        29: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/commands/build.rb:36:in `process' 
        28: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/commands/build.rb:65:in `build' 
        27: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/command.rb:28:in `process_site' 
        26: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/site.rb:76:in `process' 
        25: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/site.rb:202:in `render' 
        24: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/site.rb:515:in `render_pages' 
        23: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/site.rb:515:in `each' 
        22: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/site.rb:516:in `block in render_pages' 
        21: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/site.rb:523:in `render_regenerated' 
        20: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/renderer.rb:63:in `run' 
        19: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/renderer.rb:80:in `render_document' 
        18: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/renderer.rb:127:in `render_liquid' 
        17: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/liquid_renderer/file.rb:32:in `render!' 
        16: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/liquid_renderer/file.rb:60:in `measure_time' 
        15: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/liquid_renderer/file.rb:33:in `block in render!' 
        14: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/liquid_renderer/file.rb:53:in `measure_bytes' 
        13: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/liquid_renderer/file.rb:34:in `block (2 levels) in render!' 
        12: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/liquid_renderer/file.rb:49:in `measure_counts' 
        11: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/jekyll-4.0.0/lib/jekyll/liquid_renderer/file.rb:35:in `block (3 levels) in render!' 
        10: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/liquid-4.0.3/lib/liquid/template.rb:220:in `render!' 
         9: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/liquid-4.0.3/lib/liquid/template.rb:207:in `render' 
         8: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/liquid-4.0.3/lib/liquid/template.rb:242:in `with_profiling' 
         7: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/liquid-4.0.3/lib/liquid/template.rb:208:in `block in render' 
         6: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/liquid-4.0.3/lib/liquid/block_body.rb:82:in `render' 
         5: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/liquid-4.0.3/lib/liquid/block_body.rb:103:in `render_node_to_output' 
         4: from /home/skuzzymiglet/ysgol/gwefan-jekyll/_plugins/loop_dir.rb:52:in `render' 
         3: from /home/skuzzymiglet/.gem/ruby/2.6.0/gems/liquid-4.0.3/lib/liquid/context.rb:123:in `stack' 
         2: from /home/skuzzymiglet/ysgol/gwefan-jekyll/_plugins/loop_dir.rb:56:in `block in render' 
         1: from /home/skuzzymiglet/ysgol/gwefan-jekyll/_plugins/loop_dir.rb:56:in `each' 
/home/skuzzymiglet/ysgol/gwefan-jekyll/_plugins/loop_dir.rb:58:in `block (2 levels) in render': undefined method `render_all' for #<Jekyll::LoopDirectoryTag:0x000056284e5f07e0> (NoMethodError) 

my index.md:

---
layout: default
title: "Happy Jekylling!"
---

## You're ready to go!

{% loop_directory directory:images iterator:image filter:*.jpg sort:descending %}
   <img src="{{ image }}" />
{% endloop_directory %}

Clean, jekyll new --blank site

@jgatjens
Copy link
Author

jgatjens commented Nov 1, 2019

@skuzzymiglet do you have some repo with the code to see what's going on there?

@miko007
Copy link

miko007 commented Feb 24, 2020

i have come across the same problem. seems like Liquid::Block does not provide the render_all method anymore. Even the regular Liquid::Block::render() method is marked "For backwards compatibility". Likewise, the whole API for liquid blocks has changed.

I will have a more in-depth look into the problem, but never having wrote a liquid/jekyll module myself, it will not be very successful, i fear.

@photm5
Copy link

photm5 commented May 14, 2021

For a simpler version that works well with the built-in for block and works with current versions of liquid, see https://gitlab.com/baldrian/klimacamp-augsburg/-/blob/91244ae327380714e6d62778598a4bc69917c557/_plugins/list_files.rb. It creates a Page object for each of the files that were found, so if you don't want that, remove the .map do ... end part (you can also remove the site = ... and source = ... lines as well as the comment in that case) – without the map call, you'll get a list of filenames instead of a list of pages. See https://gitlab.com/baldrian/klimacamp-augsburg/-/blob/91244ae327380714e6d62778598a4bc69917c557/feeds/pressemitteilungen.xml#L14-15 for an example usage.

@meiadvanture
Copy link

meiadvanture commented May 22, 2024

I can't seem to get it work.
my directory for the image folder is /images under root directory.
The frontmatter in the post, I have "photos: /images"
and in my layout html, I have:

{% loop_directory directory: {{ page.photos }} iterator:image filter:*.jpg sort:descending %}
<img src="{{ image }}" />
{% endloop_directory %}

but nothing's showing. What did I do wrong?

@jgatjens
Copy link
Author

@meiadvanture this is like 8 years old or more, try this tho:

{% loop_directory directory:images iterator:image filter:*.jpg sort:descending %}
   <img src="{{ image }}" />
{% endloop_directory %}

Not sure about your {{ page.photos }} try it without that first and see.

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