Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Programmatically create pages from data files #136

Closed
jmegs opened this issue May 26, 2018 · 10 comments
Closed

Programmatically create pages from data files #136

jmegs opened this issue May 26, 2018 · 10 comments

Comments

@jmegs
Copy link

jmegs commented May 26, 2018

Maybe I am missing something in the docs but I have an array of data from contentful that needs to get turned into pages using the same template. I'd love to hear how you'd approach this currently, but I think it would be amazing to be able to do something like this:

// projects is an array of objects that each look like 
// { ... title: 'whatever', description: 'whatever' ...}

projects.forEach(project => {
    createPage({
        data: project,
        template: 'project.njk',
        dir: /projects
    })
}
@zachleat
Copy link
Member

We don’t support a programmatic API yet but this is the ground that the pagination module covers!

https://github.com/11ty/eleventy/blob/master/docs/pagination.md

@zachleat zachleat added education needs-votes A feature request on the backlog that needs upvotes or downvotes. Remove this label when resolved. labels May 29, 2018
@zachleat
Copy link
Member

Moving this to be a feature request. This will require upvotes to get traction.


This repository is now using lodash style issue management for enhancements. This means enhancement issues will now be closed instead of leaving them open.

The enhancement backlog can be found here: https://github.com/11ty/eleventy/issues?utf8=%E2%9C%93&q=label%3Aneeds-votes+sort%3Areactions-%2B1-desc+

@philhawksworth
Copy link

I was all set to vote for this until I discovered how pagination can do this for me. SO slick.

---
layout: layouts/base.njk
pagination:
  data: eventslist.events
  size: 1
  alias: event
permalink: events/{{ event.date }}/index.html
---
<h1>{{ event.title }}</h1>
<p>{{ event.date }}</p>
...

❤️

@matthewjumpsoffbuildings
Copy link

matthewjumpsoffbuildings commented Jun 14, 2019

i am using this approach to convert a big json file into a bunch of pages. there are a couple of pain points with this though

  1. because the pages are created via pagination, if i add a tag to the front-matter, eg posts, each item isnt properly added to collections.posts
  2. because of 1, if i want to generate a sitemap entry, i currently have to manually create a collection which i populate by loading the json file, which isnt ideal either
  3. because front-matter yaml doesnt process template vars, i have to use renderData to set things like title and description in the main layout, and have to use unwieldy things like title = (renderData && renderData.title ? renderData.title : title) in the main layout, instead of just being able to use title

theres a few other things that make using the pagination size:1 approach for converting a data file into a bunch of pages not quite ideal. its close enough to get it going but it would be nice if either this pagination approach was fine-tuned to allow for generated 'pages' to be treated like unique items if size == 1, or perhaps if there was another way to turn a data file into a bunch of pages

@hdoro
Copy link

hdoro commented Jun 28, 2019

A big use case for me when it comes to programmatically generating pages is the following:

I have a posts array that includes posts in multiple languages. If I want to create multiple paginated and localized post list pages, what do I do? One way is to create multiple collections with a key of post-${lang} and then creating multiple .11ty.js files (my templating language of choice) that paginate over each collection. Here's an example:

const lang = 'en'

class BlogTemplateEN {
  data() {
    return {
      pagination: {
        data: `posts-${lang}`,
        size: 1
      },
      permalink: props => {
        return `/${lang}/blog${
          props.pagination.pageNumber === 0
            ? ""
            : `/${props.pagination.pageNumber + 1}`
        }/index.html`;
      }
    };
  }
  render(props) {
    // final template...
  }
}

Problem is: I then have to copy and paste the same file, solely changing the lang to something else. I can't even abstract the BlogTemplate class into its own file and spin an instance of it with a different lang, as Eleventy won't be able to pass down its props to it... And say I have to include a new language: instead of simply changing a configuration, I now have to create a whole new file 😔

I'm super open to ways of solving this specific problem, but overall I miss an imperative API for creating pages as it'd be much easier to leverage JS without having to get into data strings, sizes and other Eleventy-specific ways of doing pagination (which I don't think is super intuitive, honestly!).

#558 and #463 will greatly help with this, as they'll give more power to JS, but it still won't be quite there yet, IMO! And hey, I'm down to helping with this API, count on me 😄

@therealshark
Copy link

therealshark commented Aug 5, 2019

@hcavalieri can't you do something like this:
BlogTemplate.js

class BlogTemplate {
  language;
  data() {
    return {
      pagination: {
        data: `posts-${this.language}`,
        size: 1
      },
      permalink: props => {
        return `/${this.language}/blog${
          props.pagination.pageNumber === 0
            ? ''
            : `/${props.pagination.pageNumber + 1}`
        }/index.html`;
      }
    };
  }
  render(props) {
    // final template...
  }
}

export default BlogTemplate;

BlogTemplateEn.11ty.js

import BlogTemplate from './BlogTemplate';
class BlogTemplateEn extends BlogTemplate {
  language = 'EN';
}

That way you don't need to duplicate code.

@hdoro
Copy link

hdoro commented Aug 6, 2019

That makes perfect sense, @therealshark ! I was trying to implement something similar but failed miserably, not much into classes haha

The thing is, though, this approach has limitations: you have to create on file for each language, for each template. Say I'm fetching an array of languages from an API and their respective content: how would I go about setting this up? One way is to manually create files, or to pre-fetch the languages and use fs to create these template files before running Eleventy... Regardless of how, it's not the nicest workflow, right?

Honestly, I'm a bit of a control freak and really want to get into the nitty gritty of how and when pages will be created, and that's why I'm putting Eleventy on hold for a while in favor of other options such as Metalsmith. Love the project, would love to use it, but it needs to work better on Windows (less bugs) and allow for controlling page creation. And be sure that I'll contribute if I find the time in the near future 😄

Thanks for the input, though, definitely helped o/

@zachleat
Copy link
Member

Related #620

@rshemant
Copy link

rshemant commented Jun 26, 2020

I was all set to vote for this until I discovered how pagination can do this for me. SO slick.

---
layout: layouts/base.njk
pagination:
  data: eventslist.events
  size: 1
  alias: event
permalink: events/{{ event.date }}/index.html
---
<h1>{{ event.title }}</h1>
<p>{{ event.date }}</p>
...

❤️

But does it work for the large collection? I have 24k pages to generate. If I fetch whole data in a single call (in _data folder) then the response will be huge. it may fail.
I am looking for one by one web page generation. wondering how to do that in 11ty

@zachleat
Copy link
Member

Going to defer this one to #620—although this one was created earlier. #620 has a bit better discussion and example code 👍🏻

@zachleat zachleat removed the needs-votes A feature request on the backlog that needs upvotes or downvotes. Remove this label when resolved. label Aug 11, 2020
@zachleat zachleat added this to the Eleventy 1.0.0 milestone Mar 19, 2021
This was referenced Mar 26, 2023
# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

7 participants