Sign up cards broke my search

Turns out the sign-up card doesn't play nice with the Algolia fragmenter -- at all.

A ghost holding a magnifying glass.
Something's not right here somewhere!

I was working on a client job tonight and discovered that I could not for the life of me get his existing content to load into Algolia, using the Ghost team's Algolia packages.

This happens some times, especially if the client has ignored my instructions to sign up for the Algolia Grow plan, which is a paid plan that costs small sites nothing but allows bigger 'fragments' to be loaded into the search index than the actually-free Build plan. [And yes, they're badly named, and I had to look up AGAIN which is which.]

Fragments can be too big for posts without enough headings, since the algolia-fragmenter package breaks post content by heading. I've never met a client who didn't have at least one monster post that didn't have enough headings. (Top 100 lists are especially bad.)

But that wasn't the problem here. On further investigation, I was getting an error on every post.

The problem turned out to be the new 'sign-up cards'. They've got a couple of embedded SVGs, and the content-api writes those out long-form, resulting in that little 200px sign-up card being 3k characters long. Yes, really.

(Oops. I originally said they were 80k characters long. I'm sorry. They're not. But with a 10k limit to upload size, that 3k is killing me.)

Here's a quick fix for the problem:

Edit (or replace) node_modules/@tryghost/algolia-fragmenter/lib/transformer.js

Add a the top of the file: const cheerio = require('cheerio');

/** (This is about line 80 of the file)
 * Algolia Object Transformer
 * takes a Ghost post and selects the properties needed to send to Algolia
 *  @param {Array} posts
module.exports.transformToAlgoliaObject = (posts, ignoreSlugs) => {
    const algoliaObjects = []; => {
      // Lines below are new // 
        // load the post.html into cheerio so we can manipulate it
        const $ = cheerio.load(post.html);
        // remove the sign-up cards - they're evil.
        post.html = $.html();
      // End of new lines // 

I already load a custom transfomer.js on Netlify. Time to go add this update, so that sign-ups don't break new indexing if one of my clients adds a sign up card.

And then I've gotta go file a bug on Github...

Hey, before you go... If your finances allow you to keep this tea-drinking ghost and the freelancer behind her supplied with our hot beverage of choice, we'd both appreciate it!


So just how bad is that card really? Here's the card...

Actually, no it's not a live card, because then it'd be invisible to folks signed in. So please enjoy this totally useless image.

And here's the HTML that generates it:

<div class="kg-card kg-signup-card kg-width-regular kg-style-accent" data-lexical-signup-form="" style="">
            <div class="kg-signup-card-content">
                <div class="kg-signup-card-text ">
                    <h2 class="kg-signup-card-heading" style="color: #FFFFFF;"><span style="white-space: pre-wrap;">Sign up for Spectral Web Services</span></h2>
                    <p class="kg-signup-card-subheading" style="color: #FFFFFF;"><span style="white-space: pre-wrap;">Let our team handle the technology, while you focus on creating. This is a live subscription box, although it's mostly here to demonstrate how bloated it is.</span></p>
        <form class="kg-signup-card-form" data-members-form="signup">
            <div class="kg-signup-card-fields">
                <input class="kg-signup-card-input" id="email" data-members-email="" type="email" required="true" placeholder="Your email">
                <button class="kg-signup-card-button kg-style-accent" style="color: #FFFFFF;" type="submit">
                    <span class="kg-signup-card-button-default">Subscribe</span>
                    <span class="kg-signup-card-button-loading"><svg xmlns="" height="24" width="24" viewBox="0 0 24 24">
        <g stroke-linecap="round" stroke-width="2" fill="currentColor" stroke="none" stroke-linejoin="round" class="nc-icon-wrapper">
            <g class="nc-loop-dots-4-24-icon-o">
                <circle cx="4" cy="12" r="3"></circle>
                <circle cx="12" cy="12" r="3"></circle>
                <circle cx="20" cy="12" r="3"></circle>
            <style data-cap="butt">
                .nc-loop-dots-4-24-icon-o *{opacity:.4;transform:scale(.75);animation:nc-loop-dots-4-anim var(--animation-duration) infinite}
                .nc-loop-dots-4-24-icon-o :nth-child(1){transform-origin:4px 12px;animation-delay:-.3s;animation-delay:calc(var(--animation-duration)/-2.666)}
                .nc-loop-dots-4-24-icon-o :nth-child(2){transform-origin:12px 12px;animation-delay:-.15s;animation-delay:calc(var(--animation-duration)/-5.333)}
                .nc-loop-dots-4-24-icon-o :nth-child(3){transform-origin:20px 12px}
                @keyframes nc-loop-dots-4-anim{0%,100%{opacity:.4;transform:scale(.75)}50%{opacity:1;transform:scale(1)}}
            <div class="kg-signup-card-success" style="color: #FFFFFF;">
                Email sent! Check your inbox to complete your signup.
            <div class="kg-signup-card-error" style="color: #FFFFFF;" data-members-error=""></div>
                    <p class="kg-signup-card-disclaimer" style="color: #FFFFFF;"><span style="white-space: pre-wrap;">No spam. Unsubscribe anytime.</span></p>