Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

How to paginate a collection? #58

Closed
johnlane opened this issue Dec 14, 2017 · 38 comments
Closed

How to paginate a collection? #58

johnlane opened this issue Dec 14, 2017 · 38 comments
Labels

Comments

@johnlane
Copy link

Hello @sverrirs I am trying to use your plugin on a site with a main _pages blog and some collections (one now, but ultimately several). I can paginate the blog posts and that works great, but it isn't clear to me from the documentation how to paginate a collection. I don't think your examples cover this sceario.

I have _collections/_stuff containing a number posts and an index.md which has frontmatter:

---
layout: index
title: stuff
permalink: /:collection/index.html
pagination:
  enabled: true
  collection: stuff
---

The index of stuff is published as /stuff/ as one would expect. It uses the same layout as the blog page.

I have enabled pagination in _config.yml:

pagination:
  enabled: true
  per_page: 20
  title: :title
  sort_reverse: true
  trail:
    before: 2
    after: 2

but it only paginates the blog posts. If I add collection: stuff to _config.yml then it only paginates stuff but onto the blog index page. I saw this done here but guess it's wrong so removed it again. So I am back to having blog posts paginated at /blog and that looks good.

When the generator runs I can see it work through the blog pages but it doesn't process the collection at all (there are no page directories under /_site/stuff/).

So what is the right way to add pagination of stuff at /stuff/ ?

@ibrado
Copy link
Contributor

ibrado commented Dec 15, 2017

Hi @johnlane,

Here are some adjusted snippets from my _config.yml that might be helpful:

collections:
  stuff:
    output: true
    permalink: /stuff/:path/

autopages:
  enabled: true
  # ... etc.
  collections:
    permalink: /:coll/
    enabled: true

pagination:
  # ... etc.

You could copy _layouts/home.html to _layouts/autopage_collection.html and just finetune it.

@johnlane
Copy link
Author

Thank you @ibrado that helps.

I didn't make the connection between autopages and paginating collections. I thought paginating a collection would work like it does for _posts.

I have my _posts in a blog directory which contains an index.html that does for posts what I am trying to do for a collection. I thought creating _collections/_stuff/index.html (or .md) would achieve the same effect.

I have it partially working now.

The collection's front page, _collections/_stuff/index.md file, blocks out the first paginated page. Removing that gives me a properly paginated collection.

However I would like to include some material on the index page of the collection - ideally on the first page but, at a worse case, it could appear on all pages. But this material needs to be collection-specific - I don't know how to do that without the index.md file. I guess one way would be to add it to a collection-specific layout but that feels wrong and isn't really what I want - layouts aren't the place for content.

Is it possible to make a paginated collection work the same way as _posts ?

@ibrado
Copy link
Contributor

ibrado commented Dec 15, 2017

@johnlane Do you mean a separate collection index (which may have additional content, then lists/links to other entries), or something like a pinned post that appears as the first entry in your paginated collection?

@johnlane
Copy link
Author

I mean a page that has some content on it as well as the paginated index - so an index.md something like this:

---
layout: index
author_profile: true
title: Stuff
excerpt: some text
header:
    overlay_image: images/something.jpg
    caption: some text
---

# Stuff

Lorem ipsum

where the index layout is the same layout I use for my blog posts. I used the minimal mistakes theme as a starting point and my index is a derivative of its home layout. It looks like this:

---
layout: archive
---

{% include paginator.html %}

{% for post in paginator.posts %}
  {% include archive-single.html %}
{% endfor %}

{% include paginator.html %}

What that gives me is whatever is in index.md followed by a paginated index.

@ibrado
Copy link
Contributor

ibrado commented Dec 15, 2017

I'm afraid I don't have any direct solutions... @sverrirs..?

I do have a couple sub-optimal solutions... The first is so hacky that I don't think it's the proper way to do it. I have a feeling I'll be laughing my head off for missing something basic. It can't handle front-matter in index.md.

---
layout: page
---

{% unless paginator.previous_page %}
{% assign collection = paginator.posts[0].collection %}
{% capture my_index_file %}_{{collection}}/index.md{% endcapture %}
{% if collection != "posts" %}
  {% capture my_index %}{% include_relative {{my_index_file}} %}{% endcapture %}
  {{ my_index | markdownify }}
{% endif %}
{% endunless %}

# ... Usual pagination stuff goes here...

My other solution involves using my StickyPosts plugin. You'd set index.md to be sticky so it goes to the top of the list, then adjust its appearance in _layouts/autopage_collection.html. I've actually just updated the gem so it could help with this question, hehe. If you try it and need help, please open an issue at its repo. Thanks...

@sverrirs
Copy link
Owner

Currently if you want custom content on auto pages then you need to either have:

  1. code on the general layout page that detects which category and page number is being generated
  2. separate layout pages for each category you want to custimize.

This actually sounds like a feature that is missing from the autopages at the moment (inclusion of some piece of text/html at the top of the pagination. If you feel up to making the feature I'll accept a PR.

@ibrado
Copy link
Contributor

ibrado commented Dec 22, 2017

I seem to remember while trying this out that index.md was being skipped...? Not sure now, but maybe that's something we can build on. I'll check over the weekend and perhaps try my hand at a PR. 😃

@ibrado
Copy link
Contributor

ibrado commented Jan 20, 2018

I actually have a partial solution to this... For collections, you'd just drop an "intro.md" (configurable) into the collection's folder, and it would get rendered at the top of the AutoPage (via paginator.intro). For posts and tags, it's still clunky. You'd need to make an actual post ending in -intro.md 😞 ... Still trying to make it a little more palatable.

@johnlane
Copy link
Author

Hi @ibrado that sounds good. So to get some text content on the index page of _collections/_stuff I would create a file _collections/_stuff/intro.md with that text content ?

I'd like to try that... I presume I need some development branch for this?

@ibrado
Copy link
Contributor

ibrado commented Jan 21, 2018

Yes, that's how you'd do it... it's also a full render (not just text) so you can use Liquid and Markdown.

I just pushed it onto my fork for you; some feedback would be good...

Gemfile (don't forget to run bundle afterwards):

gem 'jekyll-paginate-v2', :github => 'ibrado/jekyll-paginate-v2', :branch => 'autopage-intro'

You'd need to put something like the ff in your _config.yml:

pagination:
  intro: 'intro.md'

Then in your autopage_collection.html, add a {{ paginator.intro }} right before your paginator loop:

{{ paginator.intro }}
{% for post in paginator.posts %}
...
{% endfor %}

Please note that I'm still not totally happy with the code, but it should work.

@johnlane
Copy link
Author

johnlane commented Jan 21, 2018

@ibrado I wanted to do a quick test and turn it around for you quickly but it is late evening here and my test is therefore not very deep...

I followed your instructions and it does display the intro but there is a problem whereby the layouts are nesting. What I mean is that the page content also contains a second copy of the header, footer and sidebar of the page.

I guess this is to do with the layout in the front matter in intro.md and/or autopages_collection.md. I've tried various combinations without success.

In essence what I have is autopages_collection.md uses the same layout as index.html. I've tried intro.md with that layout also and with no layout. If I remove the front matter from intro.md then the page layout renders correctly, albeit without the intro, except for the first paginated item which isn't rendered properly.

I think I mentioned it before, I'm using the minimal mistakes layouts.

I can look at this again tomorrow - not sure where you are but it's gone 11pm here :)

@ibrado
Copy link
Contributor

ibrado commented Jan 21, 2018

It's 7:18am here but I haven't slept yet, hehe... Good night!

Have you tried layout: none in intro.md vs just removing the front matter?

Here's what it looks like, here:

screenshot 2018-01-22 at 4 56 41 am

I'll try to mock something up with minimal mistakes.

@ibrado
Copy link
Contributor

ibrado commented Jan 22, 2018

Hi @johnlane. I can't seem to replicate the issue if intro.md has no layout:

screenshot 2018-01-22 at 4 26 42 pm

Of course, my mockup is quite simple. I've attached it here; perhaps you can glean something from it.

demo-intro.zip

$ unzip demo-intro.zip
$ cd demo-intro
$ export GEM_HOME="./.gem"
$ bundle install
$ jekyll serve

http://localhost:4000/stuff/

@johnlane
Copy link
Author

Thanks @ibrado . I've now worked out what the problem is and have a work-around, if not a solution.

I used your example to reproduce the problem and found that it is caused by conflcting defaults.

I have my site configured to display a side-bar with my author bio.

The default display in the vanilla minimal mistakes does not include this. To get that I had added a default for pages:

defaults:
  - scope:
      path: ""
      type: pages
    values:
      layout: single
      author_profile: true

That sets the default layout parameters used by the collection index (i.e. /stuff). It affects the layout of all collection indexes but not the layout of collections' pages (e.g. hello.md).

To set default layout parameters for a collection's pages requires another defaults block specific to that collection:

  - scope:
      path: ""
      type: stuff
    values:
      layout: single
      author_profile: true

Note that this block does not affect the collection's index, only its pages. But intro.md is considered a page so this block does affect an index page containing an intro.

Trying to specify layout:null in intro.md does not work because it is overridden by the stuff default. Instead, a blank layout, like this allows it to render without additional layout. I created _layouts/intro.html:

{{ content | markdownify }}

and then specified that in intro.md:

---
layout: intro
---

I think the fact that stuff defaults don't apply to the stuff index is a little confusing, more so that the pages defaults do apply there.

There may be a better way to achieve the effect of this workaround. I don't know if the code that includes the intro would be able to remove any implicit layout from it ?

@ibrado
Copy link
Contributor

ibrado commented Jan 22, 2018

Actually I did have that code (set it to "none") but removed it in a second commit heheh.... I'll revert. I guess I did have a reason for putting that there. Give me a few mins.

@ibrado
Copy link
Contributor

ibrado commented Jan 22, 2018

Try now. You may need to run bundle again.

@ibrado
Copy link
Contributor

ibrado commented Jan 22, 2018

BTW, I'm not sure if layout: null is the same as layout: none. I'd prefer being able to keep a custom layout, if none works for you.

@johnlane
Copy link
Author

Did you push? last commit showing is #75e29b4

@ibrado
Copy link
Contributor

ibrado commented Jan 22, 2018

Was lazy and reset :D 75e29b4 is original code with the resetting of layout to none.

@johnlane
Copy link
Author

johnlane commented Jan 22, 2018

Ok well that works without specifying a layout now :)

Not sure what you're suggesting with layout: none. Are you saying you'd prefer for it to require layout: none in the frontmatter of intro.md ?

minor point.... a title in the frontmatter is not displayed. But I can just put the title in the body so hardly a big deal.

@ibrado
Copy link
Contributor

ibrado commented Jan 22, 2018

I mean, if specifying layout: none in your intro.md works (you were using layout: null I believe), I'd rather users be able to specify something like: layout: table in the future.

OTOH, not having to specify a layout also is good for the end-user. Maybe I'll just make it none if no layout was specified (to override layout inheritance). Hmmm.

@ibrado
Copy link
Contributor

ibrado commented Jan 22, 2018

Ok, I just pushed the "override inherited layout" idea.

@johnlane
Copy link
Author

yes that's what I was thinking... support a layout if given but none otherwise. I'll try that push for you now :)

Just a comment... while this is great, it still doesn't work like _posts. For example, in posts I can specify things in the layout of index.html like a header image etc but because the intro is nested within an index I can't do that.

I don't understand why collections are so fundamentally different to posts that they can't work in the same way - probably some limitation to how Jekyll works I guess. I really wanted to be able to style collections in the same way as _posts.

@ibrado
Copy link
Contributor

ibrado commented Jan 22, 2018

I guess @sverrirs would be the one to answer that properly. It does seem that you actually don't need AutoPages for what you want to do, come to think of it. You could probably just create index.html in the collections folder. I'll give it whirl...

@johnlane
Copy link
Author

Hmm, my site now fails with

jekyll 3.6.2 | Error:  undefined method `data' for nil:NilClass

Reverting to #75e29b4 fixes it.

The test site works. but the rendering issue is back unless you specify layout:none. Is that how you expected it to work?

@ibrado
Copy link
Contributor

ibrado commented Jan 22, 2018

Oops. I'm an idiot. Wait...

Fixed.

@johnlane
Copy link
Author

You could probably just create index.html in the collections folder. I'll give it whirl...

That blocks out the first page of pagination; it was the first thing I tried :)

@ibrado
Copy link
Contributor

ibrado commented Jan 22, 2018

Hmmm. I'm not seeing the "blocks out the first page" here. The pagination path for the next page is wrong (/page2 instead of /stuff/2) but I do see the 1st and 2nd pages (of 1 post each). The path could probably be fixed in the include or template. Will check some more.

@ibrado
Copy link
Contributor

ibrado commented Jan 22, 2018

Ah I had index.html hidden: true.

Not thinking clearly, will take a break... it's 8:30pm here. ;-)

@johnlane
Copy link
Author

Well, well well... I've been able to do what I wanted.

I created a directory called stuff and, in there, index.html with all the content that I wanted. And frontmatter:

pagination:
  enabled: true
  collection: stuff

This paginates the collection located at _collections/_stuff.
This is exactly the same set-up as I have for my blog except that does not specify a collection in its frontmatter and, therefore, gets posts.

The index.html is not inside the collection but in a separate directory.

If I want any content in index.html to only be displayed on a specific page (e.g. the first) then I can wrap that content with liquid

{% if paginator.page == 1 %}
some first-page content
{% endif %}

So I think it was possible to do what I wanted all along, without anything else; collections do paginate the same as posts.


So one might question the need for the intro.md mechanism but I think it's still useful to have a simpler way of doing things that allows all of the content to be kept together --- intro and posts --- in a single collection directory.

@ibrado
Copy link
Contributor

ibrado commented Jan 22, 2018

Actually, I just realized this (and your solution) is very similar to #60 which I answered before in that it involved creating a file in separate/parallel folder... no wonder it felt familiar. 😆

@johnlane
Copy link
Author

Re:

jekyll 3.6.2 | Error: undefined method `data' for nil:NilClass

Commit #4b3dcfa fixes it. All good :)

@ibrado
Copy link
Contributor

ibrado commented Jan 22, 2018

Thanks... Sorry for not remembering re #60 before, could have saved us a lot of time, hehe.

@sverrirs
Copy link
Owner

Seems to be fixed, closing this issue.

@ibrado
Copy link
Contributor

ibrado commented Jan 28, 2018

Would the "intro" code (saving an "intro.md' etc. file in the collections folder) still be useful?

@johnlane
Copy link
Author

I am not using it at present but I do think it's a useful capability to have. I am now using the separate index page along with some liquid tags to limit output to first page, as I described previously. Given the feature is there now it might as well be integrated, no?

@ibrado
Copy link
Contributor

ibrado commented Jan 29, 2018

Ok, I've submitted a PR. :-)

Sverrir, kindly take a look and feel free to modify/decline as you see fit, as usual. Thanks!

@ibrado
Copy link
Contributor

ibrado commented Feb 1, 2018

This could probably be closed since the original question/problem has been solved. For the intro feature, we could continue discussions in #75 for now...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants