ghost-3.0
  • John O'Nolan

    John O’Nolan

    John O'Nolan

Today we released the third major version of Ghost, representing a total of more than 15,000 commits across almost 300 releases. The product is as fast and stable as it has ever been, and now it also has support for memberships, subscription revenue, and API driven modern site architectures.

But you probably want to know about the $5M thing.

About 6 years ago we came up with an unconventional funding idea. We decided that rather than selling share capital and control of a business in return for money to operate, we would instead sell goods and services in return for money to operate. As a result of this choice, we were very fortunate to attract some of the world’s most forward thinking investors to help steer the company: Our customers.

To date, Ghost has made $5,000,000 in customer revenue whilst maintaining complete independence and giving away 0% of the business.

Ghost is now used by the likes of Apple, DuckDuckGo, OpenAI, The Stanford Review, Mozilla, Cloudflare, Digital Ocean, and many, many more — all whilst operating as an independent non-profit organisation releasing open source software.

We care a lot about making great publishing software, but we also care about proving that it’s possible to build a company which is fundamentally good.

If you’re just looking for the highlights of what’s new: check out our 3.0 launch page. What follows below is the extended story of how it all came to be, and everything that went into it.

Ghost 3.0 — The Story

Ghost 3.0 is far and away the biggest release we’ve ever done, in terms of scale. We announced more today in one go than at any other point in our history – and more people were involved in this release than ever before.


Memberships & subscriptions

About three years ago we first started talking about what the next big focus for Ghost might be. We’d done a reasonable job of creating a new publishing tool which was much better to use than the alternatives, but we felt like we were missing out on solving a real, pressing need of modern publishers.

In the conversations that we had with people, one core theme kept emerging that we couldn’t ignore. Everyone seemed to be struggling with a viable business model for publishing, and an editorial strategy beyond trying to compete for as much traffic as possible.

At the same time, a handful of publishers were beginning to have success with a new approach: Selling premium subscriptions to their work, creating a direct relationship with their audience – and providing value to them as customers.

Ben Thompson’s Stratechery proved that this type of business could work with only a single person running it, while Dutch news site De Correspondent quickly proved that it could also function at a national scale, and Patreon began to show that it could work for artists and creators.

These new publishers were bringing the business model of Software as a Service (SaaS) to publishing, and proving that subscription commerce could work in that space, just as it had in software. As a subscription software business ourselves, this was a set of problems we understood all too well, and a set of economics which we knew inside out.

When it comes to subscription billing, the hard part isn’t actually the subscriptions or the billing. The hard part is the publishing platform to integrate with the subscriptions and the billing – that’s the part nobody else is doing – and we were getting pretty good at building a flexible, modern publishing platform.

As of today, Ghost is the first totally independent product out there with publishing<>subscriptions deeply integrated at the core, allowing anyone to build a recurring revenue subscription business.

Ghost Membership Software: Sustainable revenue for publishers

Develop a relationship with your audience & start a membership business in few clicks to generate a predictable, recurring revenue from your creative work.

Ghost

This is a first release, and one we’re incredibly excited about, but there’s a lot more to come. We think memberships and subscriptions fundamentally changes the relationship between publishers and their audiences in a way which is better for everyone involved.


Ghost in the JAMstack

The second half of the Ghost 3.0 is the shift in how we think about the technical architecture of the product itself. As we talked about earlier in the year, we’ve been keeping a close eye on how modern web based products are evolving. We’ve been particularly excited by the JAMstack movement, which turns the traditional application model on its head:

Old way:

Make a dynamic app ? Generate cached HTML to make it fast

New way:

Generate a static site ? Add dynamic features to make it powerful

This new architecture unlocks content management that is fundamentally built via APIs, webhooks and frameworks to generate robust modern websites. We’ve expanded everything Ghost can do in this space as a headless CMS, including detailed content APIs, admin APIs and custom integrations.

Plus, we now also have native support and documentation for all of the most popular static site frameworks out there:

In fact, all of Ghost.org (including this post) is itself a Gatsby.js app with a headless Ghost back-end where this post was written, deployed statically to hundreds of different locations on Netlify‘s global CDN — connected to our fast growing library of Ghost integrations.

We’ve been really enjoying this new workflow, and adapting Ghost to be a full-featured open source headless CMS wherever possible — because no matter how much you love static sites, code editors and development environments are never the best place to write blog posts.


Continuous theme deployment with Github Actions

One of the most common requests we’ve gotten over the years (understandably) is for a better way to deploy Ghost themes to production. The process of manually making a zip, navigating to Ghost Admin, and uploading an update in the browser can be pretty arduous over time.

Casper 3.0

Now, a combination of our JAMstack work to make a great Admin API and Github Actions means it’s incredibly easy to continuously sync custom Ghost themes to your live production site with every new commit.

Create a new custom integration in Ghost, copy your Admin API keys into your repository’s Secret tokens, then copy and paste over the template Github Actions workflow.yaml – that’s all there is to it. Here’s an example.


A brand new WordPress migration plugin

We launched Ghost with a very basic WordPress migrator plugin, which we then proceeded to neglect for about 5 years, making it exceedingly difficult for anyone to move their data between the platforms or have a smooth experience.

That changes today, with our completely overhauled WordPress migration plugin:

The new plugin provides a single-button-download of your full WordPress content image archive in a format which can be dragged and dropped into Ghost’s importer. It’s an infinitely better experience all round, and fully compatible with Ghost 3.0.

Credit for this belongs entirely to Nathan Jeffery, who singlehandedly took on rewriting the plugin for us as an open source contributor. He did an incredible job and we’re immensely grateful for all his help.


How to get Ghost 3.0

All new sites on Ghost(Pro) are running Ghost 3.0. You can spin up a new site in a few clicks with an unrestricted 14 day free trial. If you haven’t tried Ghost for a while, now’s a great time to give it a fresh shot!

Already got a site on Ghost(Pro)? You’ll be automatically upgraded. If you’d like to expedite that process, you can log into Ghost.org and click the “Upgrade to 3.0” button!

Self-hosting Ghost? Upgrading to 3.0 is very straightforward with Ghost-CLI and should take about 15 mins – here’s the Ghost update guide.

What’s coming up next

Ghost 3.0 is our first step into a totally new set of use-cases and features. We’re keen to hear your feedback about using members over on the Ghost forum — or come and help out on Github if you’re interested in being a part of building the next features along with us.

Nearly everything we do is open source, and we can always use the help!

Ghost Newsletter

Stay up to date with the latest Ghost news, tutorials and resources. All the best bits, delivered every Sunday.

ghost-buttons-with-directional-awareness-in-css

It would surprise me if you’d never come across a ghost button ?. You know the ones: they have a transparent background that fills with a solid color on hover. Smashing Magazine has a whole article going into the idea. In this article, we’re going to build a ghost button, but that will be the easy part. The fun and tricky part will be animating the fill of that ghost button such that the background fills up in the direction from which a cursor hovers over it.

Here’s a basic starter for a ghost button:

See the Pen


Basic Ghost Button ?
by Jhey (@jh3y)


on CodePen.

In most cases, the background-color has a transition to a solid color. There are designs out there where the button might fill from left to right, top to bottom, etc., for some visual flair. For example, here’s left-to-right:

See the Pen


Directional filling Ghost Button ?
by Jhey (@jh3y)


on CodePen.

There’s a UX nitpick here. It feels off if you hover against the fill. Consider this example. The button fills from the left while you hover from the right.

Hover feels off ?

It is better if the button fills from our initial hover point.

Hover feels good ?

So, how can we give the button directional awareness? Your initial instinct might be to reach for a JavaScript solution, but we can create something with CSS and a little extra markup instead.

For those in camp TL;DR, here are some pure CSS ghost buttons with directional awareness!

See the Pen


Pure CSS Ghost Buttons w/ Directional Awareness ✨??
by Jhey (@jh3y)


on CodePen.

Let’s build this thing step by step. All the code is available in this CodePen collection.

Creating a foundation

Let’s start by creating the foundations of our ghost button. The markup is straightforward.

Our CSS implementation will leverage CSS custom properties. These make maintenance easier. They also make for simple customization via inline properties.

button {
  --borderWidth: 5;
  --boxShadowDepth: 8;
  --buttonColor: #f00;
  --fontSize: 3;
  --horizontalPadding: 16;
  --verticalPadding: 8;

  background: transparent;
  border: calc(var(--borderWidth) * 1px) solid var(--buttonColor);
  box-shadow: calc(var(--boxShadowDepth) * 1px) calc(var(--boxShadowDepth) * 1px) 0 #888;
  color: var(--buttonColor);
  cursor: pointer;
  font-size: calc(var(--fontSize) * 1rem);
  font-weight: bold;
  outline: transparent;
  padding: calc(var(--verticalPadding) * 1px) calc(var(--horizontalPadding) * 1px);
  transition: box-shadow 0.15s ease;
}

button:hover {
  box-shadow: calc(var(--boxShadowDepth) / 2 * 1px) calc(var(--boxShadowDepth) / 2 * 1px) 0 #888;
}

button:active {
  box-shadow: 0 0 0 #888;
}

Putting it all together gives us this:

See the Pen


Ghost Button Foundation ?
by Jhey (@jh3y)


on CodePen.

Great! We have a button and a hover effect, but no fill to go with it. Let’s do that next.

Adding a fill

To do this, we create elements that show the filled state of our ghost button. The trick is to clip those elements with clip-path and hide them. We can reveal them when we hover over the button by transitioning the clip-path.

Child element with a 50% clip

They must line up with the parent button. Our CSS variables will help a lot here.

At first thought, we could have reached for pseudo-elements. There won’t be enough pseudo-elements for every direction though. They will also interfere with accessibility… but more on this later.

Let’s start by adding a basic fill from left to right on hover. First, let’s add a div. That div will need the same text content as the button.

Now we need to line our div up with the button. Our CSS variables will do the heavy lifting here.

button div {
  background: var(--buttonColor);
  border: calc(var(--borderWidth) * 1px) solid var(--buttonColor);
  bottom: calc(var(--borderWidth) * -1px);
  color: var(--bg, #fafafa);
  left: calc(var(--borderWidth) * -1px);
  padding: calc(var(--verticalPadding) * 1px) calc(var(--horizontalPadding) * 1px);
  position: absolute;
  right: calc(var(--borderWidth) * -1px);
  top: calc(var(--borderWidth) * -1px);
}

Finally, we clip the div out of view and add a rule that will reveal it on hover by updating the clip. Defining a transition will give it that cherry on top.

button div {
  --clip: inset(0 100% 0 0);
  -webkit-clip-path: var(--clip);
  clip-path: var(--clip);
  transition: clip-path 0.25s ease, -webkit-clip-path 0.25s ease;
  // ...Remaining div styles
}

button:hover div {
  --clip: inset(0 0 0 0);
}

See the Pen


Ghost Button w/ LTR fill ?
by Jhey (@jh3y)


on CodePen.

Adding directional awareness

So, how might we add directional awareness? We need four elements. Each element will be responsible for detecting a hover entry point. With clip-path, we can split the button area into four segments.

Four :hover segments

Let’s add four spans to a button and position them to fill the button.

button span {
  background: var(--bg);
  bottom: calc(var(--borderWidth) * -1px);
  -webkit-clip-path: var(--clip);
  clip-path: var(--clip);
  left: calc(var(--borderWidth) * -1px);
  opacity: 0.5;
  position: absolute;
  right: calc(var(--borderWidth) * -1px);
  top: calc(var(--borderWidth) * -1px);
  z-index: 1;
}

We can target each element and assign a clip and color with CSS variables.

button span:nth-of-type(1) {
  --bg: #00f;
  --clip: polygon(0 0, 100% 0, 50% 50%, 50% 50%);
}
button span:nth-of-type(2) {
  --bg: #f00;
  --clip: polygon(100% 0, 100% 100%, 50% 50%);
}
button span:nth-of-type(3) {
  --bg: #008000;
  --clip: polygon(0 100%, 100% 100%, 50% 50%);
}
button span:nth-of-type(4) {
  --bg: #800080;
  --clip: polygon(0 0, 0 100%, 50% 50%);
}

Cool. To test this, let’s change the opacity on hover.

button span:nth-of-type(1):hover,
button span:nth-of-type(2):hover,
button span:nth-of-type(3):hover,
button span:nth-of-type(4):hover {
  opacity: 1;
}
So close

Uh-oh. There’s an issue here. If we enter and hover one segment but then hover over another, the fill direction would change. That’s going to look off. To fix this, we can set a z-index and clip-path on hover so that a segment fills the space.

button span:nth-of-type(1):hover,
button span:nth-of-type(2):hover,
button span:nth-of-type(3):hover,
button span:nth-of-type(4):hover {
  --clip: polygon(0 0, 100% 0, 100% 100%, 0 100%);
  opacity: 1;
  z-index: 2;
}

See the Pen


Pure CSS Directional Awareness w/ clip-path ?
by Jhey (@jh3y)


on CodePen.

Putting it all together

We know how to create the fill animation, and we know how to detect direction. How can we put the two together? Use the sibling combinator!

Doing so means when we hover a directional segment, we can reveal a particular fill element.

First, let’s update the markup.

Now, we can update the CSS. Referring to our left-to-right fill, we can reuse the div styling. We only need to set a specific clip-path for each div. I’ve approached the ordering the same as some property values. The first child is top, the second is right, and so on.

button div:nth-of-type(1) {
  --clip: inset(0 0 100% 0);
}
button div:nth-of-type(2) {
  --clip: inset(0 0 0 100%);
}
button div:nth-of-type(3) {
  --clip: inset(100% 0 0 0);
}
button div:nth-of-type(4) {
  --clip: inset(0 100% 0 0);
}

The last piece is to update the clip-path for the relevant div when hovering the paired segment.

button span:nth-of-type(1):hover ~ div:nth-of-type(1),
button span:nth-of-type(2):hover ~ div:nth-of-type(2),
button span:nth-of-type(3):hover ~ div:nth-of-type(3),
button span:nth-of-type(4):hover ~ div:nth-of-type(4) {
  --clip: inset(0 0 0 0);
}

Tada! We have a pure CSS ghost button with directional awareness.

See the Pen


Pure CSS Ghost Button w/ Directional Awareness ?
by Jhey (@jh3y)


on CodePen.

Accessibility

In its current state, the button isn’t accessible.

The extra markup is read by VoiceOver.

Those extra elements aren’t helping much as a screen reader will repeat the content four times. We need to hide those elements from a screen reader.

No more repeated content.

See the Pen


Accessible Pure CSS Ghost Button w/ Directional Awareness ?
by Jhey (@jh3y)


on CodePen.

That’s it!

With a little extra markup and some CSS trickery, we can create ghost buttons with directional awareness. Use a preprocessor or put together a component in your app and you won’t need to write out all the HTML, too.

Here’s a demo making use of inline CSS variables to control the button color.

See the Pen


Pure CSS Ghost Buttons w/ Directional Awareness ✨??
by Jhey (@jh3y)


on CodePen.