Robert Buchberger
Robert Buchberger

Reputation: 311

Calling one jekyll plugin from another

I'm writing a jekyll plugin to create a custom tag. It takes an argument and spits out a string of HTML. I've got it mostly working - I can pass it arguments and get back HTML based on those arguments. Great.

Here's what has me stumped: I want to include the render of another plugin as part of my own.

My aspirational plugin is jekyll_icon_list, the plugin I want to use is jekyll-inline-svg. Here's the (abbreviated) code:

require 'jekyll_icon_list/version'
require 'jekyll'
require 'jekyll-inline-svg'

module JekyllIconList
  class IconList < Liquid::Tag
    def initialize(tag_name, raw_args, tokens)
      @raw_args = raw_args
      @tokens = tokens
      super
    end

    def parse_arguments(raw_args, settings)
        # (Unrelated stuff)
    end

    def generate_image(icon, settings, context)
      # (Unrelated stuff)

      # Problem Here: 
      Liquid::Tag.parse(
        'svg',
         icon,
        @tokens, 
        Liquid::ParseContext.new
      ).render(context)
    end

    def render(context)
      # Builds my HTML, using generate_image in the process        
    end
  end

end

Liquid::Template.register_tag('iconlist', JekyllIconList::IconList)

This doesn't throw any errors, but it also doesn't return anything at all.

Other things I've tried:

Jekyll::Tags::JekylInlineSvg.new( returns a private method error. Jekyll doesn't want me making my own tags directly.

'{% svg #{icon} %}' Returns exactly that literally with the icon substituted in; jekyll clearly doesn't parse the same file twice.

I'm trying to figure it out from Jekyll's source, but I'm not so practiced at reading source code and keep hitting dead ends. Can anyone point me in the right direction? Much appreciated.

Upvotes: 4

Views: 308

Answers (2)

citelao
citelao

Reputation: 6046

I found this question and answer, and while it's correct, I wanted to provide a full end-to-end example.

I wanted to wrap Jekyll Scholar's {% cite %} tags in my own content:

module Jekyll
    class RenderTimeTag < Liquid::Tag
        
        def initialize(tag_name, text, tokens)
            super
            @text = text
        end
        
        def build_cite(content, context)
            tag = "{% cite #{content} %}"
            return liquid_parse(tag, context)
        end
        
        def liquid_parse(input, context)
            template = Liquid::Template.parse(input)
            template.render(context)
        end
        
        def render(context)
            citation =  build_cite(@text, context)
            # Yeah, I know this is bad HTML:
            "<span tabindex=\"0\" class=\"citeblock\">#{citation}</span>"
        end
    end
end

Liquid::Template.register_tag('pretty_cite', Jekyll::RenderTimeTag)

Upvotes: 0

Robert Buchberger
Robert Buchberger

Reputation: 311

Answering my own question:

def build_svg(icon_filename)
  tag = "{% svg #{icon_filename} %}"
  liquid_parse(tag)
end

def liquid_parse(input)
  Liquid::Template.parse(input).render(@context)
end

Basically create a tiny template consisting of the tag you want to call, and hand it off to Liquid for parsing.

Below is the dirty way, which I used before I found the proper way:

Jekyll::Tags::JekyllInlineSvg.send(:new, 'svg', icon_filename, @tokens).render(context)

Upvotes: 4

Related Questions