Search code examples
jekyll

Jekyll - Assembing a model


I have some content originating from yaml and markdown in the normal Jekyll pattern.

I also have various content pulled in from an API that I access via Jekyll data. For example, I can link a page to its related data file with the following.

sita.data.API[page.api-id]

This is working quite nicely. However, I only use say the image from the site.data if there is none available in front-matter. I have achieved this but have all sorts of if statements in my template to control the output of say a URL to an image.

I've attempted to put in an include but this led to trouble when looping over site.pages, for example, outputting thumbnails for a collection of posts.

I really want to pull the data from site.data into the page's Jekyll model. So that all of the default values and other logic can be hidden from the templates. I can iterate over site.pages without having lots of copy and paste code scattered across the site or attempting to push the include tag beyond what it was designed for.

Is this something that can be done with a plugin?

Failing that, I could use a gulp or other build step that merged the data from the markdown files and the site.data into the third set of files - probably markdown? This solution feels like a step away from Jekyll towards using something like gatsby.


Solution

  • As per the Jekyll docs

    ... a generator [plugin] can inject values computed at build time for template variables.

    There are some quite usable examples on the page as linked.

    module Composite-model
        class Generator < Jekyll::Generator
          priority :lowest
          def generate(site)
    
            # get the target from collections.
            # you could also target site.page or site.post with various filters.
            customCollection = site.collections['my-collection']
    
            
            customCollection.each do |item|
    
              # Get data from another source and link on id.
              apiId = item["api-id"].to_s
              apiData = site.data["api"][apiId]
    
              # attach data to collection item
              item.data['api-data'] = apiData
    
              # please forgive the messy logic, first bit of ruby. 
              # Will refactor and update
              if apiData  && apiData["images"]
                  singleImage = apiData["images"].length == 1
                  item.data['single-image'] = singleImage
    
                  if item["custom-image"].to_s.strip.empty?
                    imageUri = apiData['images'][0]['uri'].split('/').last
                    image = File.join("/assets/images/", apiId, imageUri)
                    item.data['image'] = image
                  else
                    item.data['image'] = item["custom-image"]
                  end
              else
                item.data['image'] = item["custom-image"]
              end    
            end
          end
        end
      end
    

    N.B It looks like you can not overwrite a page variable from within a generator plugin. For example, I first tried to transform item.image directly from the front-matter. However, this did not work so have page front matter use custom-image and then image is first used by this generator. Might be worth a different question.