Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?
like image 492
JJ Geewax Avatar asked May 13 '14 19:05

JJ Geewax


3 Answers

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

like image 125
Yuval Avatar answered Oct 21 '22 00:10

Yuval


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');
like image 43
briangonzalez Avatar answered Oct 21 '22 00:10

briangonzalez


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.

like image 1
wgp Avatar answered Oct 21 '22 00:10

wgp