Is there a way to give Ghost static pages access to the 'posts' variable that index.hbs is passed?
Asked Answered
B

6

5

I'm looking to use Ghost to host both a blog and a static website, so the structure might look something like this:

  • /: the landing page (not the blog landing page, doesn't need access to posts)
  • /blog/: the blog landing page (needs access to posts that index.hbs typically has access to)
  • /page1/, etc: static pages which will use page.hbs or page-page1.hbs as needed
  • /blog-post-whatever/, etc: blog posts which will use post.hbs

The only thing I foresee being an issue is that only index.hbs (as far as I know) is passed the posts template variable (see code on GitHub here).

Before I go submit a pull request, it'd be nice to know whether:

  1. Is there an existing way to get access to the posts variable in page.hbs?
  2. If not, is it worthwhile to submit a pull request for this?
  3. If yes, would we really want to send posts to all the pages? or should the pull request split apart page.hbs and only send it to those? or is there a better way to do this?
Biles answered 13/5, 2014 at 19:51 Comment(0)
L
4

If you don't mind hacking the Ghost core files then here is how you can do it for the current version of Ghost (0.7.4). This hack will require recreation if upgrading to a new Ghost version.

First create the template files (that will not change if you upgrade):

Create the home page template in:

contents/themes/theme-name/home.hbs

home.hbs now supersedes index.hbs and will be rendered instead of it.

Also create the blog template file in:

contents/themes/theme-name/blog.hbs

The handlebars element that adds the paged posts is

{{> "loop"}}

so this should be in the blog.hbs file.

Again, the above files do not change if you upgrade to a new version of Ghost.

Now edit the following files in the core/server directory:

I have added a few lines before and after the sections of code that you need to add so that you can more easily find the location of where the new code needs to be added.

/core/server/routes/frontend.js:

Before:

indexRouter.route('/').get(frontend.index);
indexRouter.route('/' + routeKeywords.page + '/:page/').get(frontend.index);

After:

indexRouter.route('/').get(frontend.index);
indexRouter.route('/blog/').get(frontend.blog);
indexRouter.route('/' + routeKeywords.page + '/:page/').get(frontend.index);

This calls the Frontend controller that will render the blog page with the same data level as ‘index’ and ‘home’ (the default is load a the first page of the recent posts) thus enabling us to use the “loop” in the /blog/ page.

/core/server/controllers/frontend/index.js

Before:

frontendControllers = {
    index: renderChannel('index'),
    tag: renderChannel('tag'),

After:

frontendControllers = {
    index: renderChannel('index'),
    blog: renderChannel('blog'),
    tag: renderChannel('tag'),

/core/server/controllers/frontend/channel-config.js

Before:

getConfig = function getConfig(name) {
    var defaults = {
        index: {
            name: 'index',
            route: '/',
            frontPageTemplate: 'home'
        },
        tag: {

After:

getConfig = function getConfig(name) {
    var defaults = {
        index: {
            name: 'index',
            route: '/',
            frontPageTemplate: 'home'
        },
        blog: {
            name: 'blog',
            route: '/blog/',
            frontPageTemplate: 'blog'
        },
        tag: {

/core/server/controllers/frontend/channel-config.js Before:

indexPattern = new RegExp('^\\/' + config.routeKeywords.page + '\\/'),
rssPattern = new RegExp('^\\/rss\\/'),
homePattern = new RegExp('^\\/$');

After:

indexPattern = new RegExp('^\\/' + config.routeKeywords.page + '\\/'),
rssPattern = new RegExp('^\\/rss\\/'),
blogPattern = new RegExp('^\\/blog\\/'),
homePattern = new RegExp('^\\/$');

and

Before:

 if (indexPattern.test(res.locals.relativeUrl)) {
        res.locals.context.push('index');
    } else if (homePattern.test(res.locals.relativeUrl)) {
        res.locals.context.push('home');
        res.locals.context.push('index');
    } else if (rssPattern.test(res.locals.relativeUrl)) {
        res.locals.context.push('rss');
    } else if (privatePattern.test(res.locals.relativeUrl)) {
        res.locals.context.push('private');

After:

 if (indexPattern.test(res.locals.relativeUrl)) {
        res.locals.context.push('index');
    } else if (homePattern.test(res.locals.relativeUrl)) {
        res.locals.context.push('home');
        res.locals.context.push('index');
    } else if (blogPattern.test(res.locals.relativeUrl)) {
        res.locals.context.push('blog');
    } else if (rssPattern.test(res.locals.relativeUrl)) {
        res.locals.context.push('rss');
    } else if (privatePattern.test(res.locals.relativeUrl)) {
        res.locals.context.push('private');

Restart the server and you should see the new /blog/ page come up with the list of recent blog posts

Lesslie answered 31/12, 2015 at 7:49 Comment(0)
M
3

Here's a solution that I am currently using. I have an off-canvas nav that I want to use to display links to my latest posts. On the home page, this works great: I iterate over posts and render some links. On the other pages, I don't have the posts variable at my disposal.

My solution is this: wrap the pertinent post links on the homepage in a div with an id of "posts", then I make an ajax request for that specific content (using jQuery's load) and inject it into my nav on all other pages except the home page. Here's a link to jQuery's load docs.

Code:

index.hbs

<div id='posts'>
  {{#foreach posts}}
    <li>
      <a href="{{url}}">{{{title}}}</a>
    </li>
  {{/foreach}}
</div>

app.js

var $latest = $('#posts');

if ( location.pathname !== '/' )
  $latest.load('/ #posts li');
Millimeter answered 19/5, 2014 at 16:6 Comment(0)
D
1

There is no way currently (Ghost v0.5.8) to access posts within a page template.

I would think its probably not worth submitting the pull request. The Ghost devs seem to have their own plans for this and keep saying they'll get around to this functionality. Hopefully its soon because it is basic functionality.

The best way to go about this would be to hack the core yourself. Eventually the better way to do this would be with a hook. It looks like the Ghost API will eventually open up to the point where you can hook into core functions for plugins pretty much the same way Wordpress does it. https://github.com/TryGhost/Ghost/wiki/Apps-Getting-Started-for-Ghost-Devs

If this is a theme others will be using I would recommend working within the current limitations of Ghost. It's super annoying, I know, but in the long run its best for your users and your reputation.

If this is only for you, then I would hack the core to expose a list of posts or pages as locals in each route. If you're familiar with Express then this shouldn't be very difficult.

I think the way you've done it is pretty creative and there's a part of me that likes it but it really is a seriously ugly hack. If you find yourself hacking these kinds of solutions together a lot then Ghost might not be the tool you want to be using.

Demonism answered 14/2, 2015 at 0:46 Comment(0)
F
0

A better solution than briangonzalez one, is to get the posts-info from the RSS-feed, instead of the home page.

See this gist for how it can be done.

Friedly answered 19/5, 2015 at 18:48 Comment(0)
B
0

Now you can use the ghost-url-api, it's currently in beta but you can activate it in the administration (Settings > labs).

For example the {{#get}} helper can be use like this in a static page:

{{#get "posts" limit="3" include="author,tags"}}
 {{#foreach posts}}
    ... call the loop
 {{/foreach}}
{{/get}}

More informations : http://themes.ghost.org/docs/ghost-url-api

Babbitt answered 30/6, 2016 at 12:51 Comment(0)
H
0

As of Ghost v0.9.0, the Channels API is still under development. However, achieving this is much simpler now. It still requires modification of core files, but I'm planning on submitting some pull requests soon. Currently, one downside of the following method is that your sitemap-pages.xml will not contain the /blog/ URL.

Thanks to @Yuval's answer for kicking this off.


Create a template file for your index page with the path content/themes/theme-name/index.hbs. This can contain whatever you would like for your "static" homepage.


Create a template file for your blog index page with the path content/themes/theme-name/blog.hbs. This simply needs to contain:

{{> "loop"}}

In /core/server/controllers/frontend/channel-config.js:

Edit the var defaults object to include:

blog: {
  name: 'blog',
  route: '/blog/'
}
Heth answered 8/8, 2016 at 10:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.