Getting someone to do something is hard. Asking them to type their email or to click a button isn't a foregone conclusion, you need to show them why the effort is worthwhile.
Clicking is hardwork đ
But as a creator, it's also hard to come up with effective CTAs.
With Ghost's templating layer, you can create more than your run-of-the-mill CTA by generating dynamic copy to increase engagement. Below, I'll show you how to easily create these dynamic CTAs in your post template.
The Basic CTA
We'll start with a simple CTA that asks our readers to sign up for a free newsletter.
Ghost provides some template magic we can use to add a signup form to any page. By adding the data-members-form
attribute to a form
element, we can tell Ghost to capture the subscriber's email and initiate a signup flow.
To make this work, you also need to add the data-members-email
attribute to an input element and include a button to submit the form.
<p>Your life is missing something...</p>
<p>Sign up for our free newsletter and get the goodness right in your inbox.</p>
<form class="form" data-members-form >
<label>Email <input type="email" required data-members-email />
</label>
<button>
<span class="loading">Loading...</span>
<span class="default">Sign Up</span>
<span class="success">Check Your Inbox!</span>
<span class="error">Error! Try again</span>
</button>
</form>
Ghost's template magic also automatically adds state to your form by toggling classes on the form element. These classes will be merged with existing classes and removed when state is updated.
<form class="loading"...
: added after the user clicks submit<form class="success"...
: added when signup is successful<form class="error"...
: added when signup is unsuccessful
Before moving on, we can make an immediate improvement to user experience. Right now, this CTA will be present wherever it's added to a theme. That means a user will see it, even if they're already a member, which can be confusingâwhy am I seeing this signup form if I'm already a member?
By using the @member
object and the {{#if}}
helper, you can control when the signup form is displayed. The caret (^) in front of if
in the code below inverts the if helper and means: show this content if the current user is not a signed-in member. In other words, the CTA will only show to users who are not signed in.
{{^if @member}}
<form class="form" data-members-form>
...
</form>
{{/if}}
Styling the Sign Up Form
To show and hide the default, loading, success, and error states, you need to add a bit of CSS, as shown below.
In the markup above, state is indicated via text ("Loading..."), but you could just as easily use icons instead of or in addition to the textâthe principle would be the same.
/* Hide stateful content */
.form .loading,
.form .success,
.form .error {
display: none;
}
/* Show stateful content */
.loading .loading,
.success .success,
.error .error {
display: initial;
}
/* Hide default when stateful content is shown */
.loading .default,
.success .default,
.error .default {
display: none;
}
The Dynamic CTA
Member data isn't all we have access to via the Ghost template layer. Within the context of a post, we have access to its data, which includes its title, tag, and more.
We can use this data to generate a dynamic CTA.
{{! Make sure you're in the post context}}
{{#post}}
{{! Only show the CTA if user is not a signed-in user }}
{{^if @member}}
<p>What if you never had the chance to read <em>{{title}}</em> or my other articles about
<a href={{primary_tag.url}}>{{primary_tag.name}}</a>
?</p>
<p>Avoid the possibility of your life getting much worse by subscribing to my newsletter. It's totally free.</p>
<form class="form" data-members-form>
<label>Email <input type="email" required data-members-email />
</label>
<button>
<span class="loading">Loading...</span>
<span class="default">Sign Up</span>
<span class="success">Check Your Inbox!</span>
<span class="error">Error! Try again</span>
</button>
</form>
{{/if}}
{{/post}}
While you'll need to find copy that'll suit your needs, the idea here is to update the CTA automatically based on the post's data. Instead of just saying, "Sign up for my wonderful newsletter," you can say, "Reading Title of My Article was truly wonderful, wasn't it? Don't miss other posts about x topic and sign up for my newsletter."
In the example above, I reference the article's title, its primary tag, and the link to that tag, so the reader can explore other posts on the same subject. Within the post object, you also have access to the post's author(s), description, publication date, excerpt, and more, all of which can be used to build creative CTAs to grow your audience.
Incorporating this data into a post's CTA is only a very small part of the battle of formulating an effective call to action. I hope, though, that having a few more tools at hand will spur your creativity in crafting kick-ass copy, and if I can have you take away anything from this tutorial, it's that your life will surely be much better if you sign up for my newsletter.
Resources
![](https://ryanfeigenbaum.com/content/images/hubfs/call-to-action-examples.jpg)
![](https://mk0adespressoj4m2p68.kinstacdn.com/wp-content/uploads/2020/05/perfect-cta-update-2020.png)
![](https://ryanfeigenbaum.com/content/images/wp-content/uploads/2021/07/killer-call-to-action-1.jpg)
![](https://ghost.org/images/meta/Ghost-Docs.jpg)