saberland/saber

Do you want to work on this issue?

You can request for a bounty in order to promote it!


1 active bounty request

$150.00
Solve someone else's bounty request by clicking on it and completing the funding to earn additional credits

Support multiple page types for query-posts plugin #560

andreasvirkus posted onGitHub

<!-- Please don't delete this template or we'll close your issue -->

<!-- Before creating an issue please make sure you are using the latest version of Saber. -->

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 is automatically applying the label feature_request to this issue, with a confidence of 0.92. Please mark this comment with :thumbsup: or :thumbsdown: to give our bot feedback!

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

posted by issue-label-bot[bot] over 5 years ago

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).

posted by krmax44 over 5 years ago

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

posted by egoist over 5 years ago

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.

posted by krmax44 over 5 years ago

@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? https://github.com/saberland/saber/issues/553

posted by andreasvirkus over 5 years ago

@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.

posted by krmax44 over 5 years ago

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

where: 
  - category: 'jobs'
posted by andreasvirkus over 5 years ago

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.

posted by krmax44 over 5 years ago

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

posted by egoist over 5 years ago

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.

posted by krmax44 over 5 years ago

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.
posted by egoist over 5 years ago

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)

posted by krmax44 over 5 years ago

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.

posted by sustained about 5 years ago

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. 🤷‍♂

posted by andreasvirkus about 5 years ago

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?

posted by sustained about 5 years ago

Fund this Issue

$0.00
Funded
Only logged in users can fund an issue

Pull requests