How do I incorporate Multiple Markdown files into a Nunjucks template with Eleventy? - nunjucks

CONTEXT:
Eleventy and Nunjucks (and Markdown)
A lot of long-form text (easier to create/edit using markdown).
Complex layouts.
Still new to SSGs
GOAL:
Manage chunks of text content using markdown.
Use these markdown files with template partials.
Assemble partials into a page.
EXPECTED RESULT
Processed html page:
<html>
<body>
<div>
<p>Some content originating from a markdown file.</p>
</div>
<div>
<p>Some content originating from another markdown file.</p>
</div>
</body>
</html>
ATTEMPTED ACTIONS
Here is what I've tried so far...
(Note: I've excluded my base.njk (html doctype shell) for readability.)
1. NJK MAIN with NJK PARTIAL INCLUDES
INPUT
Directory Structure
src/
/_includes
base.njk
_layout-A.njk
_layout-B.njk
main-layout.njk
content-1.md
content-2.md
main-layout.njk
{% extends "base.njk" %}
{% block content %}
{% include '_layout-A.njk' %}
{% include '_layout-B.njk' %}
{% endblock %}
content-1.md
---
layout: _layout-A.njk
---
Some content.
_layout-A.njk
<div>{{ content | safe }}</div>
content-2.md
---
layout: _layout-B.njk
---
Some more content.
_layout-B.njk
<div>{{ content | safe }}</div>
RESULT
Directory structure 'splits'.
dist/
/content-1
index.html
/content-2
index.html
/main-layout
index.html
Markdown content not passed through to parent page. Empty child tags in parent.
main-layout/index.html
<html>
<body>
<div></div>
<div></div>
</body>
</html>
I'm at a loss for how the files are processed and what I can do to do what I set out to.

That's not how 11ty works. Each MD file is a single page.
If you want to include multiple MD files to page, you should add custom filter for 11ty, to render it to html.
See examples in this issue https://github.com/11ty/eleventy/issues/658

Related

issue with eleventy nunjucks exporting template code

any ideas why my configuration is exporting njk code instead of content?
<body class="font-sans" id="top" itemscope itemtype="http://schema.org/WebPage">
{{ content | safe }}
<script src="scripts/index.js"></script>
{ % include 'footer.njk' % }
</body>
You've got too many spaces in there.
Change
{ % include 'footer.njk' % }
to
{% include 'footer.njk' %}

How to embed html using plugin in Jekyll?

I have this problem I want to inject html into markdown file (blog post) but It's little bit long so I want to have plugin with parameters because it will change and I may add it multiple times. When search inject html I only found that you can insert html directly into markdown files, but I want to have one tag that will do this for me, to not duplicate the code, it will also be easier to update if Codepen decide to change the embed code.
This is the code I want to add, Codepen embed demo with button:
<div id="codepen">
<button class="btn" onclick="document.body.classList.toggle('sticky')">Dock</button>
<iframe height="265" scrolling="no" title="in browser sql terminal"
src="//codepen.io/jcubic/embed/dVBaRm/?height=265&theme-id=dark&default-tab=result"
frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen <a href='https://codepen.io/jcubic/pen/dVBaRm/'>in browser sql terminal</a> by Jakub T. Jankiewicz
(<a href='https://codepen.io/jcubic'>#jcubic</a>) on <a href='https://codepen.io'>CodePen</a>.
</iframe>
</div>
I want to have params username and id (maybe also title and full name), what is the easiest way to create such plugin and how to use in my markdown file?
You don't need a plugin to do this.
You can use a Jekyll include.
example_page.html
---
layout: page
title: Codepen include example
codepen:
author: jcubic
name: Jakub T. Jankiewicz
id: dVBaRm
title: "in browser sql terminal"
---
{% include codepen.html %}
_includes/codepen.html
{% if page.codepen %}
{% assign c = page.codepen %}
<div id="codepen">
<button class="btn" onclick="document.body.classList.toggle('sticky')">Dock</button>
<iframe height="265" scrolling="no" title="{{ c.title }}"
src="//codepen.io/{{ c.author }}/embed/{{ c.id }}/?height=265&theme-id=dark&default-tab=result"
frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen <a href='https://codepen.io/{{ c.author }}/pen/{{ c.id }}/'>in browser sql terminal</a> by {{ c.name }}
(<a href='https://codepen.io/{{ c.author }}'>#{{ c.author }}</a>) on <a href='https://codepen.io'>CodePen</a>.
</iframe>
</div>
{% endif %}
You can also use a parametrized include.
{% include codepen_param.html
author="jcubic"
name="Jakub T. Jankiewicz"
id="dVBaRm"
title="in browser sql terminal"
%}
_includes/codepen_param.html
{% assign pen = include %}
<div id="codepen">
<button class="btn" onclick="document.body.classList.toggle('sticky')">Dock</button>
<iframe height="265" scrolling="no" title="{{ pen.title }}"
src="//codepen.io/{{ pen.author }}/embed/{{ pen.id }}/?height=265&theme-id=dark&default-tab=result"
frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen <a href='https://codepen.io/{{ pen.author }}/pen/{{ pen.id }}/'>in browser sql terminal</a> by {{ pen.name }}
(<a href='https://codepen.io/{{ pen.author }}'>#{{ pen.author }}</a>) on <a href='https://codepen.io'>CodePen</a>.
</iframe>
</div>
Like this, you can call any number of pens from your page.

Use page attribute in include statement jekyll

I have a jekyll page where I have the the two folders: products _products/product_name
and I have a product page md file containg this:
---
title: product_title
subtitle: subtilte
layout: product
description: long description
product_icon: product_image_path
---
And this simple layout:
---
layout: default
---
<!-- Main -->
<div id="main">
<div id="content" class="container">
<header id="product_header">
<div class="half_left center">
<img id="product_icon" src="/assets/{{ page.product_icon }}" alt="">
<h2 id="product_title">{{ page.title }}</h2>
<h3 id="product_subtitle">{{page.subtitle}}</h3>
</div>
<div class="half_right center">
{% markdown _products/page.title/short.md %}
</div>
<div class="clear"></div>
</header>
{{content}}
</div>
</div>
However in: {% markdown _products/page.title/short.md %} I seem unable to capture the page title, how can I do this?
My markdown tag:
# From: http://wolfslittlestore.be/2013/10/rendering-markdown-in-jekyll/
=begin
Jekyll tag to include Markdown text from _includes directory preprocessing with Liquid.
Usage:
{% markdown <filename> %}
Dependency:
- kramdown
=end
module Jekyll
class MarkdownTag < Liquid::Tag
def initialize(tag_name, text, tokens)
super
#text = text.strip
end
require "kramdown"
def render(context)
tmpl = File.read File.join Dir.pwd, "", #text
site = context.registers[:site]
tmpl = (Liquid::Template.parse tmpl).render site.site_payload
html = Kramdown::Document.new(tmpl).to_html
end
end
end
Liquid::Template.register_tag('markdown', Jekyll::MarkdownTag)
Can someone tell me how I capture the page.title in the {% markdown _products/page.title/short.md %} I get this error: Liquid Exception: No such file or directory # rb_sysopen - /home/tools/git/pagename.github.io/_products/page.title/short in _layouts/product.html
I found a different a build in solution with jekyll, such that I did not neeed a plugin in
let us say you have markdown file john.md in path markdown_files we can then we can do the following:
{% capture john %}
{% include_relative markdown_files/john.md %}
{% endcapture %}
Then where we want to input the text of john.md now captured in john we can put this {{ john | markdownify }}
It is not a sleek an not a one liner, but it works. Depending on your setup you can use include instead of include_relative
Hope it can help someone else, and thank to the Jekyll IRC community for helping me find a solution.

Why won't datepicker work in a twig in userfrosting?

Bit of a beginner here and this issue has been causing me a headache for over a day. I'm using userfrosting as a framework, with the usual twig files for the web pages.
I'm trying to include a datepicker (bootstrap-datepicker.js hasn't worked, neither is the current iteration using jquery-ui) in a form in a twig - but no matter what I do, I can't get it to work!
Here's the basic setup:
{% block head %}
{{ parent() }}
<script src="{{site.uri.js}}/jquery-1.11.2.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="{{site.uri.js}}/custom.js" ></script>
{% endblock %}
{% block content %}
.... {{boring stuff missed out}}
<form class="form-inline" role="form">
.... {{boring stuff missed out}}
<div class="form-group row">
<label for="datepicker" class="col-sm-3 form-control-label">Subject Date:</label>
<div class="col-sm-6">
<input type="date" class="form-control" id="datepicker" />
</div>
</div>
.... {{boring stuff missed out}}
</form>
.... {{boring stuff missed out}}
{% endblock %}
{% block javascripts %}
<script type="text/javascript">
$(document).ready(function() {
$("#datepicker").datepicker();
});
</script>
{% endblock %}
The box is on the page, you can type a date into it etc, but nothing appears when you click on it (there should be a calendar appearing.)
Anyone have any ideas? I'm at a total loss. I've tried various versions, locally and (as you can see, currently) on a CDN, but nothing works. I'm sure it's probably something basic as I'm not an experienced web dev or anything, but any advice or working examples would be gratefully received!
Uh! facepalm
Well, after some digging and serious consideration of the inspector output (thanks CTRL-SHIFT-I!) it turns out to be a simple case of script loading order and multiple scripts being loaded.
I didn't realise twig loads a whole bucketload of scripts on top of what I ask it to load in the template I was creating. Only after seeing the inspector output for the page did I see that I was trying to load two different versions of jQuery and my own custom script was being loaded out of order - I was loading them here:
{% block head %}
{{ parent() }}
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
<script src="{{site.uri.js}}/custom.js" ></script>
{% endblock %}
that block should be reserved for stylesheets. Instead, I should be loading them here:
{% block page_scripts %}
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
<script src="{{site.uri.js}}/custom.js"></script>
{% endblock %}
... so that they are loaded AFTER all the default Bootstrap and userfrosting scripts.
https://jqueryui.com/datepicker/ uses type="text" for the input field. When I google the matter it seems that type="date" has at least previously caused problems.
In short: I would try changing type="date" to type="text".

Nunjucks, blocks defined within "include" partial file ignored by extend

Here is my use case
I have a file that pulls pieces together (holy-grail.njs) that then is extended by the actual page I want (single.njs). Problem is that the blocks defined in included files are ignored by the actual page template. You can see the extended sidebar text is not appearing in screenshot <p>Here is some additional content for the sidebar extended in</p>
Just for grins I moved that block code from sidebar.njs to holy-grail.njs and yes it is extended by single.njs so it is indeed as I suspected.
Is the a bug?, a non-feature? How about a work around? Or will Jade do what I want? I assumed that "included" files were just included as in before further processing but maybe they are processed then included? Without being able to do this my whole groovy way of organizing my template pieces/partials and then extending/customizing the content will be a no go.
this same question was asked three years ago and no one answered
Blocks in included files not being filled by extended templates
single.njs
{% extends "layouts/holy-grail.njs" %}
{% block sidebar %}
<p>Here is some additional content for the sidebar extended in</p>
{% endblock %}
{% block article %}
{% raw %}
{{ Hugo code here to grab the article title and content }}
{% endraw %}
{% endblock %}
holy-grail.njs
{% set reg = "regions/" %}
{% set cmp = "components/" %}
{% include "regions/head.njs" %}
<body class='page'>
{% include reg + "header.njs" %}
<div class="rollover-wrapper">
{% include reg + "topbar.njs" %}
<main>
{% include reg + "sidebar.njs" %}
<section id="content">
{% block article %}
{# This is where one melds in article content #}
{% endblock %}
</section>
</main>
{% include reg + "footer.njs" %}
</div>
{% include cmp + "javascripts.njs" %}
</body>
sidebar.njs
<aside id="sidebar" class="sidebar">
<p> some sidebar content set in the sidebar.njs file </p>
{% block sidebar %}
{# This is where one melds in more sidebar content #}
{% endblock %}
</aside>
This from one of the maintainers of Nunjucks
Your guess is correct: includes operate at a "higher level" than
template inheritance. So an included template can have blocks, and can
have its own "extends" tag, and a totally separate template
inheritance hierarchy, but its blocks don't in any way interact with
the blocks of the including template's inheritance hierarchy.
So the solution I came up with is to use another tool (gulp plugin) to pre-assemble the partials then run them through nunjucks like this.
N.B my preprocessor file uses extension *.pnjs and outputs to a corresponding *.njs file which then is processed/extended in the single.njs.
var merge = require('gulp-file-include')
var rename = require("gulp-rename");
gulp.task('html:pre', function() {
gulp.src(['assets/html/nunjucks/layouts/*.pnjs'])
.pipe(merge({
prefix: '##',
basepath: 'assets/html/nunjucks'
}))
.pipe(rename({extname: ".njs"}))
.pipe(gulp.dest('assets/html/nunjucks/layouts/'));
});
var nunjucks = require('gulp-nunjucks-render');
gulp.task('html:njs',['html:pre'], function() {
gulp.src('assets/html/nunjucks/*.njs')
.pipe(nunjucks({ path: ['assets/html/nunjucks'] // String or Array
}))
.on('error', console.log)
.pipe(gulp.dest('./builds/dev/'));
});
and then you'd have to change your include syntax to that supported by gulp-file-include
like this.
##include('regions/head.njs')
<body class='page'>
##include('regions/header.njs')
<div class="rollover-wrapper">
##include('regions/topbar.njs')
<main>
##include('regions/sidebar.njs')
<section id="content">
{% block article %}
{# This is where one melds in article content #}
{% endblock %}
</section>
</main>
##include('regions/footer.njs')
</div>
##include('components/javascripts.njs')
</body>

Resources