Recommendations, wrangled

An update on the lack of posts, and some discussion of recommendations, some of it misplaced.

Recommendations, wrangled
Howdy from my desk!

Prologue

Hello friends! I'm sorry to go silent for a couple weeks in a row. One of my fall activities is serving as a coach and volunteer for FIRST Lego League. It's an amazing organization, and it means I get to do science-y and programming-y things (maybe I should have said STEM, yeah) with 4th-8th graders. It always eats too much of my life in late fall, and this year was no exception. Add in a couple of client jobs that ran longer than expected, and trying to help my oldest kid get his college applications across the finish line, and... well, here we are.

(Before I stop talking about FLL, let me make a quick shout-out to my team, who are settings up a directory of FLL teams over at https://www.frogsrobotics.org. They're using Ghost, perhaps because their coach told them to, but also because as they describe it, "It's just like using Google Docs." It still looks rather like a kid product – because it is! – but by repurposing blog posts as directory entries, we were able to get them online really quickly.)

Recommendations for Ghost

I was excited to read about the release of the recommendations functionality for Ghost. I thought I'd do some quick edits to my theme and be able to recommend everyone I'd done work for, and then they could recommend me back, and that'd be awesome all around. And then I discovered that the newest version of Ghost needs Node 18.x, and my server is still running an older version of Ubuntu, that only supports Node 16.x. And while I could in theory just type sudo apt full-upgrade, I've got too much stuff running on the server and too little time to deal with fall-out if it doesn't work. And maybe too much experience with upgrades gone sideways to believe that it'll all just work. So I'm going to spin up a new Ubuntu 22.x server and reinstall. It'll be great, but I need a day to do it. Maybe that'll be my Christmas gift to myself?

🎄
This problem is exactly why I recommend hosting with Ghost Pro to the vast majority of my clients. I've got the expertise to deal with a distribution upgrade, but I'd rather be doing something else. Anything else. I have both a Ghost Pro account and a VPS, and let me tell you, one of them is a whole lot maintenance work than the other!

So it isn't Christmas yet, and I still haven't done it. Today's recommendation discussion will be based on Source, running on my local machine (which I did upgrade.)

Source includes a recommendations section (when turned on) right on the theme's front page. It also includes a "SEE ALL" link that opens the site's recommendations panel, which is part of Portal. (It links to /#/portal/recommendations)

⚠️
If you have a lot of users on small screens and are using Source, you may want to be aware that the recommendations are hidden on screen sizes smaller than 1199px. That's going to take out all mobile phones and most tablets.

Experimenting with recommendations

The code that produces the recommendations section is very simple. Here it is:

{{#if @site.recommendations_enabled}}
   <section class="gh-recommendations">
      <h4 class="gh-sidebar-title">Recommendations</h4>
         {{recommendations}}
   <button data-portal="recommendations">See all {{> "icons/arrow"}}</button>
</section>
{{/if}}

So we're calling a new recommendations helper, but of course, I wanted to do some playing with it, not just take the defaults.

So I added a new recommendations.hbs file to my partials folder. The default is this:

{{#if recommendations}}
    <ul class="recommendations">
        {{#each recommendations as |rec|}}
        <li class="recommendation">
            <a href="{{rec.url}}" data-recommendation="{{rec.id}}" target="_blank" rel="noopener">
                <div class="recommendation-favicon">
                    {{#if rec.favicon}}
                        <img src="{{rec.favicon}}" alt="{{rec.title}}" loading="lazy" onerror="this.style.display='none';">
                    {{/if}}
                </div>
                <h5 class="recommendation-title">{{rec.title}}</h5>
                <span class="recommendation-url">{{readable_url rec.url}}</span>
                <p class="recommendation-description">{{rec.description}}</p>
            </a>
        </li>
        {{/each}}
    </ul>
{{/if}}

The first thing that jumped out at me is that this partial uses the #each helper. I've never seen a 5.x theme do that, and in fact, I thought it caused gscan to throw an error.

I asked about it and Ryan F said it was necessary, but when I tried replacing it with #foreach, everything seemed to work fine, so I'm not sure quite what's up there!

The other thing that had me scratching my head is that there's no limit specified anywhere. If I have hundreds of recommendations, do they all show up on Source's front page? I made seven recommendations, and only five of them showed up. OK, so there's a default limit somewhere.

Readers, I tried playing with limit, to no avail. I also tried changing the order recommendations display in, also to no avail.

I did learn (by using the {{log}} helper) that this is what's available for each of the five recommendations available:

    {
      id: '656cc86e65b9cd336c4133ee',
      title: 'Spectral Web Services',
      description: 'Let our team handle the technology, while you focus on creating.  Ghost CMS experts.',
      excerpt: 'Let our team handle the technology, while you focus on creating.  Ghost CMS experts.',
      featured_image: 'https://www.spectralwebservices.com/content/images/2023/08/ghost-website-6.png',
      favicon: 'https://www.spectralwebservices.com/content/images/2023/08/witch-hat-icon_rev-1-01-3.png',
      url: 'https://www.spectralwebservices.com/',
      one_click_subscribe: true,
      created_at: '2023-12-03T18:26:54.000Z',
      updated_at: '2023-12-03T18:26:54.000Z',
      count: undefined
    },

So, if you'd like to do something more interesting than the default, there are some values to play with! There's a lot more available than what's being shown by Portal.

I really wanted to get all seven recommendations. Did I need a #get "recommendations"? Nope, resource doesn't exist. So I was stumped for a while. There should surely be a way to access all the recommendations through handlebars, shouldn't there?

And then I found it. Logging was showing me that there's pagination of recommendations. So, in the hbs file that calls the {{recommendations}} partial, I changed it to {{recommendations page="2"}}. And bingo. There were my other two recommendations (but only them). That was the hint I needed.

That helper is also where you can override the number of recommendations passed in. So I changed it to {{recommendations limit="30"}}. I also found that it'll take an order parameter. So if you wanted your recommendations sorted by date or name or something, that's an option. And if you just want a few more to show up in your theme, there you go!

JavaScript alternatives:

If you want something more sophisticated than what's available in handlebars, a little network sniffing tells me that there's a workaround. I resorted to opening the #/portal/recommendations link and looking at the network calls. There's a call to this endpoint: /ghost/api/content/recommendations/?key=CONTENTAPIKEY&limit=100 that isn't under the same limit of five recommendations. So, if you want your recommendations in a randomized order, one option would be to make an API call with JavaScript to get the recommendations and add them to the page that way. If the recommendations are "below the fold" (not visible when the page loads) or only in a pop-up anyway, that's a fine workaround.

Addendum

And then, after all my flailing around, I realized that the recommendations documentation actually includes the use of page and limit.

Sometimes, it just doesn't pay to get out of bed. I hope that I have at least provided you with some entertainment at my own expense. Always read the documentation, ya'll!