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

Support multiple page types for query-posts plugin #560

Open
andreasvirkus opened this issue Nov 8, 2019 · 15 comments
Open

Support multiple page types for query-posts plugin #560

andreasvirkus opened this issue Nov 8, 2019 · 15 comments
Assignees

Comments

@andreasvirkus
Copy link
Contributor

Feature request

What problem does this feature solve?

Having multiple page collections, besides the standard _posts/ type, e.g. _jobs/ (to list all available job ads), _projects (for a portfolio maybe), etc.

What does the proposed API look like?

Maybe the user could add injectByType: 'slug' in the YAML frontmatter, where slug would have to match _<slug> in the directory name?

How should this be implemented in your opinion?

Within the saber-plugin-query-posts package, not yet sure of the technical implementation.

Are you willing to work on this yourself?

Yes. Would this feature be an OK addition? Is it maybe already solvable today somehow?

@issue-label-bot
Copy link

Issue-Label Bot is automatically applying the label feature_request to this issue, with a confidence of 0.92. Please mark this comment with 👍 or 👎 to give our bot feedback!

Links: app homepage, dashboard and code for this bot.

@krmax44
Copy link
Contributor

krmax44 commented Nov 8, 2019

I think this is a good idea. Maybe instead of only adding this feature, query-posts could be overhauled so that you can query pages in a more customisable way (the current implementation doesn't resemble that much of a query plugin, in my opinion, which would be awesome if it was).

@egoist
Copy link
Collaborator

egoist commented Nov 8, 2019

I had thought about some kind of query syntax like this:

jobs.md

---
jobs:
   where: 
      - page.job === true
paginate:
   by: jobs
   segment: p
   perPage: 10
---

The front matter above makes Saber generate:

/jobs
/jobs/p/2
/jobs/p/3

And job posts are injected as page.jobs

@krmax44
Copy link
Contributor

krmax44 commented Nov 8, 2019

I don't know how I feel about doing querying in Markdown, since displaying the queried posts isn't usually done in the Markdown either. Maybe a layout-focused/Vue-page-focused API/query syntax would make sense.

@andreasvirkus
Copy link
Contributor Author

andreasvirkus commented Nov 9, 2019

@krmax44 do you mean something with a Vue plugin's syntax, so the user could call this.$queryPosts, e.g. 👇 ?

computed: {
  postsOfCurrentPage () {
    return this.$queryPosts(this.page)
  }
}

Edit: could this new proposed state API be utilised here somehow?
#553

@krmax44
Copy link
Contributor

krmax44 commented Nov 9, 2019

@andreasvirkus an API like that would be tricky to implement, as then pages would be fetched at runtime rather than at buildtime.

Maybe something like this would facilitate it:

export const data = {
  title: 'foo',
  queryPosts: { // Mongo-style querying
    where: {
      category: 'jobs'
    }
  }
}

or with a function:

export const data = {
  title: 'foo',
  queryPosts: (post) => post.title.startsWith('Job')
}

Would be awesome if this worked on layouts and pages.

The proposed state API could be used here, but I don't think it's necessary.

@andreasvirkus
Copy link
Contributor Author

andreasvirkus commented Nov 9, 2019

Good point about the runtime vs buildtime. In an .md file, would this then be:

where: 
  - category: 'jobs'

@krmax44
Copy link
Contributor

krmax44 commented Nov 11, 2019

Another possible API:

<template>
  <div>
    <h2>My posts</h2>
    <ul>
      <li v-for="page in $pages" :key="page.permalink">{{ page.title }}</li>
    </ul>
  </div>
</template>

<script>
// all posts created after 2019-01-01
export const data = {
  title: 'foo',
  queryPages: {
    // Mongo-style querying
    where: {
      type: 'post',
      createdAt: { $gt: new Date('2019-01-01') }
    },
    process(pages) {
      // only return title and permalink of posts (smaller bundle files)
      return pages.map(({ title, permalink }) => ({ title, permalink }));
    },
    // alternatively:
    process: ['permalink', 'title', 'attributes.createdAt']
  }
}
</script>

This could also be incorporated into #511.

@egoist
Copy link
Collaborator

egoist commented Nov 14, 2019

Maybe it's finally the time to consider GraphQL? 😅

@krmax44
Copy link
Contributor

krmax44 commented Nov 14, 2019

Personally, I'd like to avoid GraphQL since it's intimidating to newcomers and usually adds a lot of overhead to simple projects. I can see the appeal due to its flexibility though, so if we can keep the overhead to a minimum (by making it optional when the defaults aren't enough) and explaining it really well in the docs so that anyone understands, it might work out.

@egoist
Copy link
Collaborator

egoist commented Nov 15, 2019

I tried GraphQL again but there're too many restrictions, so here's my updated proposal for mongo-like query syntax:

Query all pages:

export const data = {
  pages: {
    $query: 'page'
  }
}

Query last 5 posts written in this Year:

export const data = {
  lastFivePosts: {
    $query: 'page',
    $sortBy: 'createdAt',
    $order: 'DESC'
    $where: {
      type: 'post',
      createdAt: {
        $gt: '2019-01-01'
      }
    }
  }
}

$query is pointed to a collection name, by default in Saber there will be only one collection which is page, a plugin can create a new collection to store custom data, like author collection which resolves to a list of authors.

For pagination, it's only possible to create pagination based on a single property, i.e. you can have multiple queries, but the pagination can be only created from one of them, so here we introduce the paginate property:

export const data = {
  posts: {
    $query: 'page',
    $where: { type: 'post' },
    $sortBy: 'createdAt',
  },
  paginate: {
    by: 'posts',
    perPage: 30,
    segment: 'page' // => /page/2 /page/3
  }
}

Note:

  • In markdown pages you should use front matter instead of export const data.
  • We should make export const data work in layout component as well.
  • Make a GraphiQL alternative for Saber queries: /_saber/query.

@krmax44
Copy link
Contributor

krmax44 commented Nov 15, 2019

Maybe Sift.js could be used to implement a portion of the querying part.

What about scoping queries instead of adding them to the main data object? Maybe like this:

export const data = {
 queries: {
    posts: {
      $query: 'page',
      $where: { type: 'post' },
      $sortBy: 'createdAt'
    }
  }
}

or

export const queries =  {
  posts: {
    $query: 'page',
    $where: { type: 'post' },
    $sortBy: 'createdAt'
  }
}

(which would also remove the data ambiguity with things like title etc. in layouts)

@krmax44 krmax44 self-assigned this Nov 18, 2019
@sustained
Copy link

I also need support for multiple collection, like Jekyll has and without it I don't think I can use Saber.

I don't personally care for this pseudo-GraphQL query stuff however.

@andreasvirkus
Copy link
Contributor Author

Yeah... I think the universal approach that has been discussed here is over-optimizing for issues that users aren't facing yet. We've currently forked the query-posts plugin and just added options for different types besides post like job and case-study, etc. 🤷‍♂

@sustained
Copy link

I agree, I think it'd be nice to just add basic support for multiple collections at first, that will stand alone as a rather nice feature and then afterwards discussion can be had about a querying system and whatever other bells and whistles?

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

No branches or pull requests

4 participants