metalsmith / collections Goto Github PK
View Code? Open in Web Editor NEWA Metalsmith plugin that groups files together into collections, which it adds to the global metadata.
License: MIT License
A Metalsmith plugin that groups files together into collections, which it adds to the global metadata.
License: MIT License
How would I add image paths to collection? I want to display thumbnail of the article.
Hello, I'm creating a blog-post with metalsmith where I'm getting all my data from storyblok headless CMS,
I need to create a collection of blog posts from storyblok in order iterate on it and render it using handlebars, and I can't find a proper solutions, aby help will be appreciated
I have a modified version of this repo where a collection can have a parent and children. I can do a PR here or should I just publish it as a "new" plugin?
Note: It doesn't break existing behaviour.
Thanks, Woody
I am using both metalsmith-collections and metalsmith-in-place. I am using markdown and Nunjucks so my files are in the format of filename.md.njk, I also have noticed that the path for the filenames when collections is run is being set using the *.md.njk format.
I have created my own articles plugin that modifies the navigation for my articles based on the file structure and also the path. The issue I am having is that it appears I have to run metalsmith-in-place before metalsmith-collections in order to get the path to be correct so something like articles/first-series/first-page.md.njk
rather than articles/first-series/first-page.html
.
It would be fine to run metalsmith-in-place before metalsmith-collections however when I do that then I do not get the path, next or previous links for my posts collection. See the attached screenshot for more information.
Here is my build file as it currently sits.
/*jslint es6 */
/*
* Metalsmith build file
* Build site with `node build`
*/
'use strict';
const inplace = require('metalsmith-in-place');
const layouts = require('metalsmith-layouts');
const metalsmith = require('metalsmith');
const collections = require('metalsmith-collections');
const serve = require('metalsmith-serve');
const watch = require('metalsmith-watch');
const assets = require('metalsmith-assets');
const drafts = require('metalsmith-drafts');
const excerpts = require('metalsmith-excerpts');
const paginate = require('metalsmith-pager');
const archive = require('metalsmith-collections-archive');
const debug = require('metalsmith-debug-ui');
/* Local Plugins */
const utils = require('./lib/utils');
const articles = require('./lib/articles');
const permalinks = require('./lib/my-permalinks');
const templateConfig = {
engineOptions: {
highlight: utils.highlight,
filters: {
toUpper: utils.toUpper,
spaceToDash: utils.spaceToDash
}
}
};
let ms = metalsmith(__dirname);
debug.patch(ms);
ms.metadata({
site: {
name: 'A Developers Blog',
author: 'Joseph Crawford',
description: 'A Developers Blog'
}
})
.clean(true)
.source('./src/')
.destination('./build/')
.use(collections({
posts: {
pattern: 'posts/**/*.njk',
sortBy: 'date',
reverse: true
},
articles: {
pattern: ['articles/*.njk', 'articles/**/*.njk'],
refer: false
},
reviews: {
pattern: ['reviews/*.njk', 'reviews/**/*.njk'],
sortBy: 'date',
reverse: true
}
}))
.use(archive({
layout: 'archive.njk',
rootLevel: false,
collections: {
'posts': true
}
}))
.use(articles({
collection: 'articles'
}))
.use(drafts())
.use(excerpts())
.use(paginate({
collection: 'posts',
elementsPerPage: 1,
pagePattern: 'page/:PAGE/index.html',
index: 'post.njk',
paginationTemplatePath: '../layouts/partials/paginator.njk',
layoutName: 'post.njk'
}))
.use(inplace(templateConfig))
.use(layouts(templateConfig))
.use(permalinks({
relative: false,
pattern: ":title",
// each linkset defines a match, and any other desired option
linksets: [{
match: { collection: 'posts' },
pattern: 'post/:date/:title',
},{
match: { collection: 'articles' },
pattern: 'articles/:series.name/:title'
},{
match: { collection: 'reviews' },
pattern: 'reviews/:date/:title'
}]
}))
.use(assets({
source: __dirname + '/assets/',
destination: '.'
}))
.use(serve({
port: 8080,
verbose: true
}))
.use(watch({
paths: {
"${source}/**/*": true,
"lib/**/*": "**/*",
"layouts/**/*": "**/*"
}
}))
.build(function (err) {
if (err) {
console.log(err);
throw err;
}
console.log('Build finished!');
});
COLLECTIONS RUNNING FIRST
IN-PLACE RUNNING FIRST
MY BUILD DIRECTORY
Tests are there. Would be nice to have Travis test it for us.
I have a list page that I would like to template from a block of JSON, rather than from a set of markdown files. (I could create a file for each list item, but that seems excessive because they are just a few properties each, with no body, and I only need a list page, not pages for each of them individually).
The config could be something like this:
Metalsmith(__dirname)
.use(collections({
talks: {
json: 'content/talks.json'
},
Might you be interested in adding this feature to metalsmith-collections? I'd be happy to try adding it in a fork and submitting a PR if so.
Hi,
Is there a way to specify default frontmatter; in this case layout
, in an item matched by the glob specified in a collection if not specified already in the file?
I've been using Metalsmith static site generator for some time and I believe is a great tool. Now I started using metalsmith-collections plugin but I stumbled across this issue.
Given the case that I have two collections defined, for instance "en_news" and "sp_news" and the following news.hbt file:
<h1>{{title}}</h1>
{{contents}}
<ul>
{{#each collections.en_news}}
<li>
<h3>{{this.title}}</h3>
<article>{{this.contents}}</article>
</li>
{{/each}}
</ul>
Now in the .md file I want the collection to be either collection.en_news:
---
title: News
template: news.hbt
lang-collection: en_news
---
News in english language
...or collection.sp_news:
---
title: Noticias
template: news.hbt
lang-collection: sp_news
---
News in spanish language
How can I use "lang-collection" inside test.hbt to define the used collection?
Of course the following does not work:
{{#each collections.{{lang-collection}}}}
Thanks in advance!
for example if there is an /articles
folder, that way people don't have to add a collection
metadata property to every file
Currently, repeated calls to metalsmith.build()
is non-idempotent because metalsmith-collections will find the same files that belongs to a collection, and add them to the same array as exists in memory from the previous run.
This is due to metalsmith storing collections in the global metadata object. Maybe it should empty out the collections arrays every time it runs?
My workaround right now is essentially
metalsmith.build(function(err, files) {
if (err) throw err;
metalsmith.metadata(origMetadata);
});
I'm currently trying to put together an index page but I can't seem to call the collection in one of my files without it returning '0' or undefined. Any ideas?
My current file structure:
src
|-- posts
|-- index.html
|-- category1
|-- post.md
|-- category2
|-- category3
layouts
|-- post.html
This is what I'm calling in posts/index.html
{% for cat in collections.category1 %}
<li>{{ cat.title }}</li>
{% endfor %}
This is my index.coffee
metalsmith __dirname
.use define
config:
environment: 'develop'
.use collections
'category1':
pattern: 'posts/category1/*.md'
'category2':
pattern: 'posts/category2/*.md'
'category3':
pattern: 'posts/category3/*.md'
.use markdown
.use permalinks
pattern: 'posts/:collection/:url'
relative: false
.use layouts
engine: 'swig'
partials: 'partials'
pattern: '**/*.html'
.use inPlace
engine: 'swig'
partials: 'partials'
.use sass
outputStyle: 'compressed'
.use autoprefixer()
.use htmlMinify
removeAttributeQuotes: false
.use uglify()
.build (error) ->
if error
console.log error
I'm still pretty new at this and I've tried to dig through similar issues but none of the solutions worked for me. Any help would be appreciated!
I'm using metalsmith to render some SVG markup, which contain a lot of self closing tags:
For example:
<circle cx="33" cy="19" r="2"/>
When printing these out at the layout level with metalsmith there is no problem, everything is preserved.
However when I'm looping through a collection:
index.html
{{#each collections.components }}
{{>component}}
{{/each}}
component.html
<div class="demo-rendered cf">
{{{ this.contents }}}
</div>
output
<div class="demo-rendered cf">
<circle cx="33" cy="19" r="2">
</div>
All the self-closing tags are stripped out, which means the browser assumes these tags need nesting and everything goes downhill pretty quickly.
The fact these are only removed when returning from the collection implies the issue is with this plugin. Is this something anyone else has run into?
(note this also applies to more basic self closing tags: <br/>
, <input type="text />
Hi, could you please bump the version number and publish the latest version to npm? Having the path
property is very useful.
Thanks
How do you access the global collections object in a template via the CLI?
I have pulled in a collection of html files using this plugin. The collection is named posts. I then have a template that uses the collection
{{#each posts}}
{{contents}}
{{/each}}
This does print out the contents but the html is html encoded. '<' is '<' for instance. What am I doing wrong?
My metalsmith.json is simple
{
"metadata": {
"site": {
"title": "Tomaw Tech"
}
},
"plugins": {
"metalsmith-collections": {
"posts": "posts/*"
},
"metalsmith-page-titles":{},
"metalsmith-in-place": {
"engine": "handlebars"
},
"metalsmith-layouts": {
"engine": "handlebars",
"default": "layout.html"
},
"metalsmith-broken-link-checker": true
}
}
Hi - I'm trying to build up a collection of recent blog posts for a right nav section. I have the following configuration of the collections plugin.
.use(collections({
blogposts: '**/*.md'
}))
Unfortunately, whenever I run this, I was never seeing any data in my collection (there should have been 25 items in the array, but the array was always empty). In digging into the source, the spot that seems to be breaking me is at https://github.com/segmentio/metalsmith-collections/blob/master/lib/index.js#L25. I'm not exactly sure why, but Object.keys
always returns an empty array. Further, Object.getOwnPropertyNames
also returns an empty array.
I'm running Node 6.0.0 - not sure whether something changed wrt the JavaScript interpreter or if I'm just doing something incredibly dumb, but I'm a little stumped at the moment.
thoughts?
I seem to be having a simple problem. If I use only a pattern to describe a collection, it works fine:
article: {
pattern: 'articles/*/index.html'
...}
If I simple use the metadata, it works fine as well,
article: {
sortBy: 'date',
reverse: true}
If I try to use the pattern, when there is a metadata key in the front-matter, I get errors...
Can we not use both a pattern and metadata at the same time, or is it an either/or proposition?
So, rad tool by the way, the flexibility is impressive, and I'm looking forward to seeing the ecosystem of plugins expand.
I'm trying to use markdown, permalinks, and include in the following order
.use( drafts() )
.use( metaobj({
"site" : {
"title": "Site Name",
"description": "Tagline"
},
"styles": [
"/css/main.css"
],
"nav": [
{ "name": "…", "href": "…", "title": "…" },
]
}))
.use( minclude() )
.use( collections({
careers: {
sortBy: 'date',
reverse: true
}
}))
.use( markdown() )
.use( permalinks({
pattern: ':title'
}))
.use( templates({
engine: "swig",
directory: "templates"
}))
.use(beautify({
"html": true,
"js": false,
"css": false
}))
then i set up a few .md files with the following frontmatter (with different titles of course):
---
template: careerlisting.html
title: UX Engineer
collection: careers
date: 2014-10-8
---
however when i try and print out the variable in my templates and build...
the include partials function as expected
the permalinks structure works
but the collections dont echo.... the metadata seems to exist, but seems to be empty (im using swig templates)
Here's the template chunk
{% for career in collections.careers %}
{{career}}
{% endfor %}
Not sure how to get this… any tip?
would be nice if readme included an example of generating index pages.
Hey—unsure if this is a problem related to Metalsmith or this plugin. When I build the site the value of contents for each article sometimes changes.
For example, here's the value of contents of article one:
<p>A really short, rushed-feeling string of words.</p>
However, when I edit article two by adding a couple line breaks, the contents of article one becomes:
<html> <head> <title>My Blog</title> </head> <body> <h1>My Fourth Post</h1> <time>Thu Dec 06 2012 16:00:00 GMT-0800 (PST)</time> <p>A really short, rushed-feeling string of words.</p> </body> </html>
Any ideas?
I have a site with the following directory structure:
src
|-------films
| |-------film1.md
| |-------film2.md
|-------templates
|-------film-template.html
And my metalsmith.json
looks like this
{
"source": "src",
"destination": "build",
"metadata": {
"title": "A site",
"description": ""
},
"plugins": {
"metalsmith-markdown": {},
"metalsmith-collections": {
"films": {
"pattern": "films/*.md",
"sortBy": "title"
}
}
}
}
When I run metalsmith, I get the following error message
/ASite/node_modules/metalsmith-collections/lib/index.js:51
col.sort(function(a, b){
^
TypeError: Cannot call method 'sort' of undefined
at /ASite/node_modules/metalsmith-collections/lib/index.js:51:11
at Array.forEach (native)
at /ASite/node_modules/metalsmith-collections/lib/index.js:46:10
at Object.next [as _onImmediate] (/ASite/node_modules/metalsmith/node_modules/ware/lib/index.js:56:8)
at processImmediate [as _immediateCallback] (timers.js:330:15)
It appears that because the metalsmith-markdown
actually modifies the files array at https://github.com/segmentio/metalsmith-markdown/blob/master/lib/index.js#L43-L44 when the metalsmith-collections
runs, it can't find any .md
files.
Putting metalsmith-collections
first and metalsmith-markdown
second in metalsmith.json
fixes the problem.
I am not sure if this is intentional or if it could be considered a bug. I am not sure what the solution should be. A suggestion would be to have files
be an object with "transformed" and "original" path names, or possibly metalsmith-collections
could be modified to always re-read the original files.
I would like to use collections like this:
metalsmith.use(collections())
Where each file may contain a collection defined in the frontmatter:
---
collection: some_collection
---
Thoughts?
The documentation describes how to describe and ingest collections, but there is no explanation as to how the collections can be used in other files (such as in an index.jade).
The plugin isn't idempotent, running it twice will screw up the metadata.
app = metalsmith()
.use(collections({ articles: { ... } })
.build(done => ...)
.build(done => ...)
The workaround is to create a middleware that clears up metadata:
app = metalsmith()
.use((files, ms, done) => {
ms.metadata({ articles: [] })
done()
})
.use(collections({ articles: { ... } })
.build(done => ...)
.build(done => ...)
I have json array with me and i want to add these array into metalsmith-collections. how i do it please help me?
Somehow i can only add files to my collection by setting the metadata collection in the file.
I can not select any files with the pattern attribute like following:
"metalsmith-collections": {
"articles": {
"pattern": "*.md"
}
}
or
"metalsmith-collections": {
"articles": "*.md"
}
This will only give me an empty collection in the template
Not sure if this is related to the partial build bug, or CLI. But I'm building via the CLI interface and no posts in collection are receiving paths:
{
"source": "./views/blog-src",
"destination": "./views/blog-pub",
"plugins": {
"metalsmith-collections": {
"posts": {
"pattern": "./views/blog-src/posts/*.html",
"sortBy": "date",
"reverse": "true"
},
"latestPosts": {
"pattern": "./views/blog-src/posts/*.html",
"sortBy": "date",
"reverse": "true",
"limit": "10"
}
},
"metalsmith-permalinks": {
"pattern": ":date/:title"
},
"metalsmith-markdown": true,
"metalsmith-layouts": {
"engine": "ejs",
"default": "post.ejs",
"directory": "views",
"version": "lkebgw46346lbj",
"user": false,
"static": true,
"userID": false
}
}
}
This is what I get:
{ title: 'test post',
date: Thu Jan 01 2015 01:00:00 GMT+0100 (CET),
publishDate: Thu Jan 01 2015 01:00:00 GMT+0100 (CET),
modifyDate: Thu Jan 01 2015 01:00:00 GMT+0100 (CET),
author: 'Jesper Bylund',
collection: [ 'posts' ],
contents: '<p>This is just a test of the watch thing!</p>\n',
mode: '0644',
stats:
{ dev: 16777220,
mode: 33188,
nlink: 1,
uid: 501,
gid: 20,
rdev: 0,
blksize: 4096,
ino: 30144996,
size: 169,
blocks: 8,
atime: Sun Jul 03 2016 15:35:52 GMT+0200 (CEST),
mtime: Sun Jul 03 2016 15:28:18 GMT+0200 (CEST),
ctime: Sun Jul 03 2016 15:28:18 GMT+0200 (CEST),
birthtime: Sun Jul 03 2016 11:26:01 GMT+0200 (CEST) } }
Is there a way to do this currently? I don't see a way.
I'd be glad to send a PR to do this if desired.
With this setup my make serve
build hangs as soon as I include metalsmith-collections
. Removing metalsmith-collections
fixes this. However, as far as I can tell I'm not doing anything out of the ordinary.
Looks like it's running into an infinite loop of sorts. Any idea what's causing this?
Yep.
My collection's metadata isn't being added to the global metadata. When using node-debug, I see that my files don't match the path when they should. The pattern will be "_site_src/content/projects/*.html" but the given path is "projects/something.html"
My collection files do not have a collection metadata in the yaml front matter.
Here is my setup:
metalsmith: {
main: {
options: {
metadata: {
title: "My Blog",
description: "My second, super-cool blog."
},
plugins: {
"metalsmith-collections": {
projects: {
pattern: "_site_src/content/projects/*.html"
}
},
"metalsmith-templates": {
engine: "handlebars",
directory: "_site_src/templates"
},
"metalsmith-permalinks": {
pattern: "projects/:title"
}
}
},
src: "_site_src/content",
dest: "build"
}
}
Or maybe I'm doing something wrong???
I was using this plugin and noticed that path gave me the original file name. Depending on the order in which I place the plugin, this can be inconvenient. I noticed it would be an easy fix!
I would imagine that you want all paths to be HTML anyways, so it can probably be done without any additional options. The gist of it is that you include the function below and have data.path = replaceExtension(file).
Just a thought. If it seems like something worth implementing, here is a script that does this...
function replaceExtension(name) {
var splitNameName = name.split('.');
splitNameName.pop();
splitNameName.push('html');
return splitNameName.join('.');
}
This gets me every time I have to grab a collection from a file.
The property that is added to the file is: collection, yet its value is an array of collections
I get this would break everyone's code (unless we add both keys while people migrate), but it really makes zero sense.
Unless I am missing something :)
I keep getting this error when trying to run a build:
Path looks like: src/_projects/project.md
Build looks like:
.use(collections({
projects: {
pattern: "_projects/*.md"
},
posts: {
pattern: "_posts/*.md"
}
}))
I've narrowed this bug down to the collections plugin, and think it could be unique to the Swig template engine.
Running the following code produces the error:
https://github.com/jonlong/writing/tree/broken-swig-collections
Am still working on debugging this one, but would love a second set of eyes!
Hello.
Any chance someone could be brought aboard to help maintain this plugin?
It's used by nearly everyone who uses Metalsmith.
Or at least some clarity that this is the final version and we should fork if we want to add features or help out with potential issues.
Thanks - love Metalsmith and hope it doesn't go away.
Ran across this bug(?) today, so I'm reporting it:
$ make build
node_modules/.bin/metalsmith
/home/eduan/dev/eduantech-metalsmith/node_modules/metalsmith-collections/lib/index.js:51
col.sort(function(a, b){
^
TypeError: Cannot call method 'sort' of undefined
at /home/eduan/dev/eduantech-metalsmith/node_modules/metalsmith-collections/lib/index.js:51:11
at Array.forEach (native)
at /home/eduan/dev/eduantech-metalsmith/node_modules/metalsmith-collections/lib/index.js:46:10
at Object.next [as _onImmediate] (/home/eduan/dev/eduantech-metalsmith/node_modules/metalsmith/node_modules/ware/lib/index.js:56:8)
at processImmediate [as _immediateCallback] (timers.js:330:15)
Makefile:3: recipe for target 'build' failed
make: *** [build] Error 8
And here's my metalsmith.json
file in case it's relevant:
{
"source": "src",
"destination": "build",
"metadata": {
"title": "EduanTech"
},
"plugins": {
"metalsmith-drafts": true,
"metalsmith-markdown": {
"smartypants": false,
"gfm": true,
"tables": true
},
"metalsmith-collections": {
"menu": {
"pattern": "*.(md|toffee)"
}
},
"metalsmith-templates": "toffee"
}
}
I am using version 0.1.0. Help appreciated. :)
How are collections made available in templates, for example jade?
I'd like to hear your (@ianstormtaylor) .. or anyones, thoughts on the ability for a single document to be included in multiple collections. Most obviously via something like:
---
collection: foo bar
---
and
---
collection:
- foo
- bar
---
I'm likely going to submit a PR in the near future for this ability, but since it's a very core aspect to the design of this plugin, i figure it's worth discussing before i need the feature and end up submitting a PR heh.
All releases > 0.7.0 aren't documented. Also version 0.8.0 seems to be removed or at least missing, 0.9.0 seems to exist twice and 0.9.9 exist without previous patch levels:
What the hank is going on here @lambtron?
Examples of how to implement previous/next functionality in templates would be greatly appreciated.
I am having a one-page that should include some collections. But, I don't want to generate those include files. So I am using .ignore("mypath")
like described in the docs. However, when using ignore
after or before using collections
, those include files will be deleted from the stack of the collection. So, how can I use ignore
but still get even ignored files into the stack of collections
?
I am aware that this repository is not actively maintained, so in the meantime I will either don't use this plugin or delete the ignore files after using metalsmith.
This stops happening as soon as the collection is non-empty:
/Users/hunter/code/playfuljs/node_modules/metalsmith-collections/lib/index.js:56
col.sort(function(a, b){
^
TypeError: Cannot call method 'sort' of undefined
at /Users/hunter/code/playfuljs/node_modules/metalsmith-collections/lib/index.js:56:13
at Array.forEach (native)
at /Users/hunter/code/playfuljs/node_modules/metalsmith-collections/lib/index.js:47:10
at Object.next [as _onImmediate] (/Users/hunter/code/playfuljs/node_modules/metalsmith/node_modules/ware/lib/index.js:68:8)
at processImmediate [as _immediateCallback] (timers.js:330:15)
Hello!
I have a simple config:
{
"source": "./content",
"destination": "./_site",
"metadata": {
"title": "title",
"description": "desc"
},
"plugins": {
"metalsmith-drafts": {},
"metalsmith-markdown": {},
"metalsmith-permalinks": {
"pattern": ":title"
},
"metalsmith-templates": {
"engine": "swig",
"directory": "templates"
},
"metalsmith-collections": {
"genre": {}
}
}
}
If I try to build it $ metalsmith
, I can’t get collections
variable from within templates.
Maybe there should be some docs on basic usage of collections in templates?
I have to md files:
---
title: English
collection: articles
layout: article.hbs
---
---
title: Hindi
collection: articles
layout: article.hbs
---
I'm matching using the collection
metadata. How do I get the links for the pages??
Thanks!
Hi,
in jekyll there is an option to ignore the output of collections. That means e.g. the collection can be used in template code, but the file is not written to the output directory.
See http://jekyllrb.com/docs/collections/:
collections:
my_collection:
output: false
Can this be achieved with metalsmith-collections?
Adding metadata to a collection works fine, but as soon as that collection has any items in it, all the metadata goes away.
Scenario 1 - Empty collection with Metadata:
Config:
"posts": {
"sortBy": "date",
"reverse": false,
"metadata": {
"name": "Posts",
"path": "posts/index.html"
}
}
Metadata:
posts: {
name: "Posts",
path: "posts/index.html
}
Scenario 2 - Using pattern with metadata:
Config:
"posts": {
"pattern": "posts/**.md",
"sortBy": "date",
"reverse": false,
"metadata": {
"name": "Posts",
"path": "posts/index.html"
}
}
Metadata:
Posts data without a metadata
tag.
This is also an issue when using post metadata to define collections.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.