<![CDATA[Tutorials]]>https://ghost.org/tutorials/https://ghost.org/tutorials/favicon.pngTutorialshttps://ghost.org/tutorials/Ghost 5.59Tue, 22 Aug 2023 13:31:06 GMT60<![CDATA[👩‍🎨 Build with Ghost: The art of the post template]]>https://ghost.org/tutorials/post-time/64de29799de13a0001cdb4a8Tue, 22 Aug 2023 08:31:05 GMT

Welcome to Issue #8! Some of what we have in store:

  • Our new tutorial shows you how to showcase your content by building the perfect post template
  • Updates to CSS that will blow your mind 🤯
  • Taking Ghost headless with Thimira

The art of the post template

👩‍🎨 Build with Ghost: The art of the post template

It's the heart and soul of your theme. It's where authors bring their creative content to life, and where readers immerse themselves in these narratives.

It's the post template, and, in our latest tutorial, we cover everything you need to know to build one. We focus on the following:

  • The basic anatomy of a post template
  • Understanding the data available in the post context
  • Steps to designing a captivating post header
  • Bringing in your content
  • Tips & tricks for creating a beautiful reading experience

Check it out 👉

The art of the post template in Ghost
Creating gorgeous post layouts has never been easier in Ghost. Dive into our step-by-step guide to learn everything you need to know about creating a custom post template.
👩‍🎨 Build with Ghost: The art of the post template

But wait! There's more.

We also released tutorials on using custom settings and building custom sign-up forms.

Custom settings are the ultimate power-up for Ghost themes
Want to elevate your Ghost theme? Dive into custom settings with this complete guide. Choose typefaces, color schemes, and more. Your theme, your rules!
👩‍🎨 Build with Ghost: The art of the post template
🏋️
Pro tip: When adding custom settings to your theme, use the new description key to communicate the setting's purpose to your users
How to build custom sign-up forms in Ghost
Learn to create a custom sign-up form with Ghost. This guide covers all steps, including HTML integration, CSS styling, and user engagement strategies.
👩‍🎨 Build with Ghost: The art of the post template

Did you know we have a YouTube channel? Our most recent video includes a complete guide to using partials in Ghost. Don't forget to like and subscribe 😜

Just shipped 🚢

  • Header cards got a massive upgrade, giving you more power to create beautiful pages and posts. (Header cards are full-width cards perfect for creating a division between sections or making a large call to action.)
  • In the same spirit, it's now possible to hide the title and feature image for pages, making it possible to build radically different landing pages.
🚧
Custom theme developers will need to update their themes to support the new @page helper that makes toggling the title and feature image possible.

Ideas and tools 🛠️

Getting technical with Thimira

Thimira Thenuwara recently relaunched Android Wedakarayo, a Sinhala publication about technology based in Sri Lanka. The relaunch is notable because Thimira shifted to using Ghost headlessly, implementing a Nuxt frontend with Tailwind styling, oAuth sign-in, and Algolia search. We'll explain all of this in a minute, but let's start at the beginning.

👩‍🎨 Build with Ghost: The art of the post template
Android Wedakarayo

By day, Thimira is a Deputy Manager of Finance for a group of companies in Sri Lanka. By night, certified Ghost Expert 🦸

His foray into Ghost development began when Android Wedakarayo transitioned from WordPress to Ghost. At first, the publication used stock Casper (always a good place to start). Here and there, Thimira began customizing it to suit the publication's needs, eventually developing a totally bespoke theme.

Before hacking on his Ghost theme, Thimira didn't know web development at all! He taught himself HTML, CSS, and JS and says, "The platform taught me the ropes of web design." He also had a great support network to help him: another Ghost Expert, Kasun Jayarathna, got him up to speed on Ghost, Srilal Sachintha taught him Linux servers, and his fiancée, Shenaya Hewagama, cheered him on throughout.

Ghost is truly a fantastic gateway to learning web development. The cost of entry is low and the payoff is high: a totally customized, beautiful publication. Just be careful because before you know it, you'll be building a headless Ghost site with Nuxt, Algolia, oAuth, and a handful of other custom features 😏 Let's talk about what all this means.

Running Ghost headlessly means using Ghost's API with a frontend other than Ghost's native theme layer. While it enables advanced functionality, headless is not the way to go for most users. Ghost's theme layer, for example, includes the metadata that optimizes your site for SEO. Going headless means you need to code that functionality yourself.

Using a framework like Nuxt (based on Vue) for your frontend can ease some of the burden by providing plugins and packages to help you rebuild features from Ghost's theme layer.

Algolia is an advanced search-as-a-service. It can be used with any Ghost site, and we use it on our Tutorials site. Learn more about setting up Algolia on Ghost in our docs.

oAuth (open authorization) is a protocol that allows third-party apps to access user data without exposing user credentials. A common example, and the one Thimira implemented, is using Google or Apple to sign into a third-party website.

To see the whole thing in action, go check out Android Wedakarayo. We'd also be remiss if we didn't mention Thimira's Apple-inspired personal site, which has lots of clever animations.

👩‍🎨 Build with Ghost: The art of the post template

Sites featured in the Build with Ghost newsletter are discovered through our creator network, Ghost Explore. It’s a way for creators and readers alike to discover their favorite new publications. Anyone running a Ghost site can add themselves to Explore to be featured throughout the wider Ghost ecosystem. If you’d like to be featured in this newsletter, add your site to Explore and reply to this email.

👩‍🎨 Build with Ghost: The art of the post template

Thanks for building with us.

Have an idea for a Ghost tutorial? Reply to this email and let us know ❤️

Looking for other creators and developers working with Ghost? Join the official Ghost Forum, where we talk about all things Ghost!

]]>
<![CDATA[Build a custom sign-up form]]>https://ghost.org/tutorials/form/64d3ad903bf35a000198a7ccThu, 10 Aug 2023 19:25:49 GMT

For publications with a strong brand identity or those looking to fully optimize their Ghost site, a custom sign-up form is more than just a tool — it's an extension of the brand itself.

Using Of Record, a publication focusing on vinyl collecting and music listening, as our example, we'll delve into:

  • The reasons for going bespoke
  • The anatomy of a custom sign-up form
  • A peek into what makes an engaging sign-up form

Here's a preview of the sign-up form we'll build in this tutorial:

0:00
/0:13

Ready to elevate your sign-up form into a memorable experience? Let's dive in!

It may be simpler than you think

For most publications, Ghost already offers a simple solution that works out of the box and without any custom code.

Embeddable signup forms
Start growing your audience from anywhere on the web, using the new embeddable signup forms. It’s now even easier attract new subscribers from any website, while keeping Ghost as the hub for your memberships. Branded Include your logo, publication name, and description in your signup form, and…
Build a custom sign-up form

Head to SettingsMembership, select a layout, and color, apply your labels, then simply copy the embed code for use anywhere on the web. Here's a live example:



However, for advanced users, Ghost provides tools for creating a completely custom sign-up form that allows you to:

  • Fully align the form with your brand's visual identity.
  • Provide a unique user experience.
  • Optimize performance.

Let's see these tools at work by analyzing Of Record's sign-up form, shown below.

Build a custom sign-up form

Anatomy of a custom sign-up form

The beauty of building a custom sign-up form is that it's exactly the same as building one with standard HTML elements. Integrating it with Ghost is as simple as adding a few custom data attributes. Here's the code for Of Record's sign-up form:

<form data-members-form= >
    <input data-members-label type="hidden" value="Turntable buying guide" />
    <label>
        Name
        <input data-members-name />
    </label>
    <label>
        Email
        <input data-members-email type="email" required />
    </label>
    <button>
        Sign up
    </button>
    <p class="loading">⏲️ Please hold while we check our collection.</p>
    <p class="error">❗Something's gone wrong. Please try again.</p>
    <p class="success">🎸 Success! Check your inbox for our email.</p>
</form>

Putting this form anywhere in your theme or on your site via an HTML card will instantly create a custom sign-up form ✨

Let's talk about the necessary attributes that make it work.

Activate the form

To make Ghost aware of your custom form, add the data-members-form attribute to the form. Note that you can change the language of the email that a new member will receive by adding a value to the attribute:

  • data-members-form="signup": new members receive an email with "sign up" language
  • data-members-form="subscribe" (default): new members receive an email with "subscribe" language

Functionally, both of these options are identical. Opting for one or the other will depend entirely on your publication's identity. See additional options for the data-members-form attribute in the docs.

💡
Use the match helper with the @member object to only show the sign-up form to nonmembers. Learn more.

Get a name

<label>
    Name
    <input data-members-name />
</label>

In Of Record's form, we wrap the input with a label element. This approach is optional, but it's a convenient method to associate the label and input, which makes the form more accessible.

The data-members-name attribute tells Ghost to collect the member's name. However, because required is omitted from the input, this field is optional. A member will be able to sign up without giving their name. To require a name, use the required attribute as seen in the next section.

Get an email

<label>
    Email
    <input data-members-email type="email" required />
</label>

On this input, we include the type="email" and required attributes. These help with validation (the browser checks if the email is valid) and required ensures a value is present before submitting.

The magic comes in with the addition of the data-members-email attribute, which Ghost uses to capture the submitted email.

Add a label

In addition to capturing a name and email, it's also possible to add a label to members who sign up with your custom form. These labels appear on the member's profile in Ghost Admin and are filterable via the Members menu. Also, when sending an email, you can use these labels as recipient groups. This works great if your sign-up form is coupled with particular content, and you want to send an update related to that content. With labels, you already have a list of everyone interested in that content!

Here's what the member profile looks like in Ghost Admin. Note the "Turntable buying guide" label.

Build a custom sign-up form

And, here's the code to add to set a label.

<input data-members-label type="hidden" value="Turntable buying guide" />

It works by adding a hidden input type (meaning it won't appear to the user) along with the data-members-label attribute. Then, set the value to the label you want to add. That's it!

Now, whenever someone signs up with your custom form, this label will be applied automatically.

💡
Bright Themes has an advanced tutorial on letting users choose which labels are associated with their signup. Check out how it's done.

Form states and CSS styling

<p class="loading">⏲️ Please hold while we check our collection.</p>
<p class="error">❗Something's gone wrong. Please try again.</p>
<p class="success">🎸 Success! Check your inbox for our email.</p>

Not only does adding Ghost's custom data attributes ensure your form gets your members signed up, but it also adds relevant classes as the user signs up. These classes, added to the form element, reflect its state: loading, success, and error.

Build a custom sign-up form
Build a custom sign-up form
Build a custom sign-up form

These classes enable you to convey the form's state to your user. How you want to do this is completely up to you, but we'll show you the basic logic to implement in CSS.


/* Form states */
:where(.loading, .success, .error)  {
    display: none;
}

.loading .loading, .success .success, .error .error {
    display: block;
}

We set the default style of the states (like <p class="success">) to display: none. Then, we override these states when Ghost adds the class to the form element. For example, here's what the form HTML looks like when the sign up is loading:

<form data-members-form class="loading">
  ...
</form>

The loading class on the form and the same class on the p element makes the selector .loading .loading match and updates the display property to show the state.

Because it's just CSS controlling whether elements are shown, you can simulate the different states by adding and removing the different classes from the form, rather than having to actually sign up over and over again.

Keeping the user apprised of where they are in the sign-up process is possible with just a few lines of CSS and opens up lots of creative possibilities when creating a custom form.

Designing content for your form

Now that you know how to make a custom sign-up form, you may be faced with the tricky task of what actually to put in it 🤔

With a custom sign-up form, you can take any approach you want:

  • Minimalist: Simple, clean typography focuses on essential values
  • Visual storytelling: Imagery tells a story and connects with the audience
  • All about the benefits: Bullet points or icons convey the value position instantly
  • Interactive experience: Animations, transitions, and interactive elements engage the user and make signing up a blast

These are but a few of the approaches you can take, which makes things difficult. How can you create an effective sign-up form? Don't worry! We've got you covered over on Ghost Resources.

We share evidence-based best practices to support creators, businesses, and publishers. For example, check out this formula for creating powerful copy or these strategies for building a sign-up form that converts.

Summary

Whether you're a publication with a strong brand identity like Of Record or someone looking to fully optimize your Ghost site, a custom sign-up form is a powerful tool to build your audience.

With knowledge of Ghost's custom data attributes and the styles to show and hide form states, you now have everything you need to create gorgeous, custom sign-up forms.

If you create one, don't hesitate to share it with the Ghost community. We like to hang out on the official Forum. It's also a great place to get ideas and learn more about building with Ghost.

Oh, and don't forget to sign up 💌

Build a custom sign-up form

Make your inbox fire

Build a better internet with early access to features, tools, and tutorials.

No spam. Once a month. Unsubscribe any time.

]]>
<![CDATA[Custom settings are the ultimate power-up for themes]]>https://ghost.org/tutorials/custom-settings/64d133e3ea74ed000169d127Mon, 07 Aug 2023 23:04:43 GMT

Custom settings are perfect for developers building themes because users can tailor their theme to match their publication without having to touch a line of code. Even if you’re building a theme for yourself, custom settings give you instant control over aspects like typeface, layout, colors, and much more. The following guide will walk you through everything you need to know to make the most of custom settings in your Ghost theme.

An overview of custom settings

Use custom settings to create different possibilities for your theme — possibilities that users can configure right from Ghost Admin. For example, let users choose the tone for their publication by giving the option to have a refined serif typeface or a modern sans serif one.

While we’ll go into the details below, here are the essential points to know about custom settings:

  • Define custom settings in your theme’s package.json file
  • Access the values with the @custom helper
  • You can have up to 15 custom settings

How to configure custom settings

Set up custom settings in the theme’s package.json file, under the config.custom key. Add each setting as a new key, using snake_case. Here’s an example of a custom setting called “typography”:

{
    "config": {
        "custom": {
            "typography": {
                "type": "select",
                "options": ["Modern sans-serif", "Elegant serif"],
                "default": "Modern sans-serif",
  			    "description": "Define your site's typography"
            }
        }
    }
}

The most important option to set for each setting is its type because it determines which other keys are required.

Understanding types

There are five possible types. Let's look at each in detail.

Select

As seen in the example, the select type presents the user with a dropdown of options you define in the required options key. A default key is also required. It must contain a value that matches one of the defined options.

Boolean

The boolean type presents the user with a true/false toggle. When using the boolean type, you must also specify a default value (true or false).

Color

The color type presents the user with a color picker. A default hex color must be provided when using this type.

💡
Remember that Ghost already provides the ability for a user to set an accent color in Design settings that can be accessed via the @site.accent_color helper.

Image

The image type presents the user with an image uploader. The output from this type is either an image URL or a blank string. The image type works great with the img_url helper, which allows you to optimize the uploaded image automatically!

Text

The text type presents the user with a text input. The default value is optional, meaning that it’s possible for the output of this type to be empty.

Find a full overview of these types in the docs.

Add descriptions to share the purpose of custom settings

For each type, it's possible to add an optional description. The value provided for this key appears in Ghost Admin with the custom setting. It's a great way to communicate to users what the custom setting is for.

By giving the setting a name, description, type, and any additional required keys, you've defined a custom setting. Oh, yea! Let's see how to access its user-defined value in the theme.

Access custom settings within the theme

Gain access to the user-defined value with the @custom helper plus the setting name. To access the typography setting above, use @custom.typeface anywhere in the theme.

To then change the typeface for the theme, use the custom setting to modify the CSS class on the body tag in default.hbs.

<body class="{{#match @custom.typeface "Modern sans-serif"}} has-sans-serif-font{{else}} has-serif-font{{/match}}</body>

Use the match helper

We use the match helper above to test the value of the custom setting. Specifically, we’re testing whether the typeface value equals “Modern sans-serif.” (When using the match helper to test equality, the = sign can be omitted.) It’s also possible to test other conditions by using different operators: !=, <, >, >=, and <=. If the custom setting equals "Modern sans-serif," then the has-sans-serif-font class is output. Otherwise, has-serif-font is output.

The only other required action on your part is to include the classes in your CSS:

.has-sans-serif-font {
  font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif;
}

.has-serif-font {
  font-family: Iowan Old Style, Apple Garamond, Baskerville, Times New Roman, Droid Serif, Times, Source Serif Pro, serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;;
}

Now, the user can set their desired typeface right from Ghost Admin (and change it any time if they’re so inclined) 🔠

💡
Remembering the exact value you used to name a custom setting can be a drag, requiring you to jump back into your package.json file. Use our official VS Code extension to autocomplete your custom settings. When in a Handlebars file, type custom, and the extension will autocomplete the property with your settings, even adding the @ sign.

Grouping custom settings

There’s one last bit of configuration possible for custom settings: groups. By default, all custom settings are put in the Site-wide group, meaning that the setting is applicable across the whole publication.

However, specific groups exist for settings that only apply to the homepage or post pages. For example, with Casper, it’s possible to specify three different layouts on the homepage. Here’s how that option is defined in package.json and its group defined:

"feed_layout": {
    "type": "select",
    "options": [
        "Classic",
        "Grid",
        "List"
    ],
    "default": "Classic",
    "group": "homepage"
}

For settings applicable to post pages, set the group to post.

And that’s everything you need to know about custom settings. Here’s a visual to help bring it all together.

Custom settings are the ultimate power-up for themes

Custom settings in the wild

Eager for a few more examples? Let's check out two different ways custom settings are used in Ghost’s default theme, Casper.

Dynamic color scheme

Imagine giving your users the power to switch between light and dark modes, or even automate the color scheme based on OS preferences. Casper does just that!

"color_scheme": {
    "type": "select",
    "options": [
        "Light",
        "Dark",
        "Auto"
    ],
    "default": "Light"
}

The color_scheme custom setting allows users to choose whether they want their site to display in light, dark, or auto mode.

The custom setting is accessed in default.hbs on the html tag:

<html lang="{{@site.locale}}"{{#match @custom.color_scheme "Dark"}} class="dark-mode"{{else match @custom.color_scheme "Auto"}} class="auto-color"{{/match}}>

When the color scheme is set to “Dark,” the dark-mode class is added to the element (and auto-color is added when that option is chosen). Then, in the theme’s CSS, styles are added with classes to reflect these choices. For example, here’s the rule that sets the background to a dark color and the text to a light color:

html.dark-mode body {
    color: rgba(255, 255, 255, 0.75);
    background: var(--color-darkmode);
}

The takeaway? You can dynamically add and remove CSS classes based on user preferences, creating multiple styles within a single theme.

Personalize the sign-up call to action

Custom text for the sign-up CTA (call to action) on Casper’s post page makes the experience more engaging. Here's the setting:

"email_signup_text": {
    "type": "text",
    "default": "Sign up for more like this.",
    "group": "post"
},

Key insights:

  • Fallback text: If the user doesn’t provide their own, a default is provided to ensure the CTA text isn’t blank.
  • Group definition: This setting shows up under the "post" dropdown, making it specific to post pages.

The screenshots below show how this setting appears in Ghost Admin and the default and personalized call-to-actions on the post.

These examples illustrate a few of the many possibilities offered by custom settings. Dive in and explore these features and other custom settings in Casper. Learning from official Ghost themes is a fantastic way to level up your theme-building skills 💪

Summary

With custom settings, you can hand the creative reins to your users, allowing them to make your theme their own. Through this guide, you've learned how to define, access, and leverage various types of custom settings, seen practical examples, and grasped precisely how these settings can transform a user's interaction with your theme.

But your adventure is just beginning.

Visit our official Forum to see what other developers are up to or subscribe to our Build with Ghost Newsletter, the best way to keep up with changes in Ghost and find inspiration for your next gorgeous theme.

]]>
<![CDATA[The art of the post template]]>https://ghost.org/tutorials/post-template/64cab735602c87000170a39cThu, 03 Aug 2023 23:00:48 GMT

The post template is the heart and soul of a theme. It’s where authors bring their creative content to life, and where readers immerse themselves in these narratives. In this comprehensive tutorial, we'll guide you through each stage of creating a stunning post template. By the end of it, you'll be well-equipped to construct your own unique post templates in Ghost.

Using the post template from the fictional music publication, Of Record, as a guide, we'll delve into:

  • The essence of a post template
  • Understanding the data available in the post context
  • Steps to design a captivating post header
  • Bringing in your post content
  • Tips and tricks for creating a beautiful reading experience

Are you ready to create the perfect post template with us? Let's get started! To help you better visualize what we're working on, we've included a short video of the post page we're about to create.

0:00
/0:10

Of Record's post template

What's the post template?

The post template, aptly named post.hbs, is responsible for rendering your post content, that is, anything and everything you write in the editor. The template file must be placed in the root of your theme. (If a theme doesn't have a page.hbs template, Ghost will use the post template to render pages, too.)

.
├── LICENSE
├── README.md
├── assets
├── author.hbs
├── default.hbs
├── error-404.hbs
├── error.hbs
├── gulpfile.js
├── index.hbs
├── package.json
├── page.hbs
├── partials
├── post.hbs # The post template
└── tag.hbs

Theme file structure

Accessing post data

The post template opens with two essential bits of Handlebars code.

{!< default}}

{{#post}}

{{!< default}} instructs Ghost to embed the post template into the default layout. If you imagine your webpage as a sandwich, then your default template serves as the slices of bread, while the post template is the filling. For more details, check out our tutorial on the default template.

Moving on to {{#post}}, this command opens the post context, granting you access to post data and helpers. This means you can now tap into crucial data like the post title, feature image, author, and more. As we traverse through Of Record’s post template, we’ll elucidate the data and helpers that are most likely to come in handy. For a comprehensive list of all available data and helpers, visit the post context docs.

Dynamic styling with post_class

Here's the next line of the post template:

<main class="or-post or-container {{post_class}}">

There are two key aspects to focus on in this tag:

  1. Static classes: We use two static classes. or-post defines the max width of the post content, and or-container pads and centers the content.
  2. Dynamic classes with {{post_class}}: This helper dynamically outputs classes based on the post data. Here's how it works:
  • All posts automatically get the post class
  • Featured posts get the featured class
  • Pages get the page class
  • Every tag associated with the post provides a class in the format tag-{slug}.

For the example post, "The Role of Independent Record Stores," which has the "industry" tag, {{post_class}} is rendered as post tag-industry. The screenshot below shows the final output of the post's static and dynamic classes.

The art of the post template
Output of {{post_class}}

These dynamic classes open the door for you to target posts, programmatically changing styles based on a tag or featured status.

Create the post header

The art of the post template

The next part of the template is the post header. It contains all the metadata about your post, including its title, publication date, author(s), tags, feature image, and more.

Above, we've shared a diagram that shows the code underlying each header element. Let's walk through this code to understand it better:

<header class="or-post-header">
    <div class="or-post-header-text">
        {{#match primary_tag}}
            <div class="or-post-header-tag" style="--color: {{primary_tag.accent_color}}">
                <a href="{{primary_tag.url}}">{{primary_tag.name}}</a>
            </div>
        {{/match}}
        
        <h1 class="or-post-header-title">{{title}}</h1>
        
        {{#match custom_excerpt}}<p>{{custom_excerpt}}</p>{{/match}}

        {{#is "post"}}
        <div class="or-post-header-meta or-flex">
            <div>
                <p class="or-post-header-label or-text-light">{{plural authors.length empty="" singular="Author" plural="Authors"}}</p>
                <p class="or-post-header-value">{{authors}}</p>
            </div>
            <div>
                <p class="or-post-header-label or-text-light">Published</p>
                <p class="or-post-header-value">{{date}}</p>
            </div>
            {{#match feature_image_caption}}
            <div>
                <p class="or-post-header-label or-text-light">Image credit</p>
                <p class="or-post-header-value">{{feature_image_caption}}</p>
            </div>
            {{/match}}
        </div>
        {{/is}}
    </div>
...

The primary tag

{{#match primary_tag}} 

Inside the post context, we have access to the primary_tag object, that is, the first tag on a post. The match helper is then employed to check whether a post has a primary tag. If you're unfamiliar with the match helper, think of it as a gatekeeper. It only allows the code within the match tags to run if the post has a primary tag. Otherwise, it instructs the code to skip this block.

When the post has a primary tag, the following code displays the tag's name and provides a link to it:

<div class="or-post-header-tag" style="--color: {{primary_tag.accent_color}}">
    <a href="{{primary_tag.url}}">{{primary_tag.name}}</a>
</div>

There are a few interesting things happening here.

In Ghost Admin, it’s possible to set an accent color for each tag, which is why “Industry” has a red color. By using an inline style tag, we can dynamically define the color with CSS custom properties.

Here's a diagram that walks through the process of how this works:

The art of the post template

We then create a link to the tag page with an anchor link, setting the href via the primary_tag's URL property.

Finally, we display the tag’s name: {{primary_tag.name}}.

This dynamic feature allows you to draw attention to the main topic of the post, providing readers with a clear understanding of the post's theme at first glance.

Post title

<h1 class="or-post-header-title">{{title}}</h1>

The next line of code brings in the post title with the {{title}} helper. This one is about as straightforward as it gets!

Custom excerpt

{{#match custom_excerpt}}<p>{{custom_excerpt}}</p>{{/match}}

The match usage here is identical to the one above: we’re testing for the existence of a custom excerpt, which means an excerpt that’s deliberately set by the author (not automatically generated). If set, we show the custom excerpt. Using the match helper ensures that we don’t have an empty p tag on our rendered page.

Here's our example post with and without a custom excerpt:

Working with post metadata

Adding rich, relevant metadata to your posts can greatly enhance your site's SEO and make your content more discoverable. Thankfully, Ghost provides a convenient way to include post metadata, which encompasses elements such as authors, publication date, and the caption for the featured image.

Let's break down each element:

Authors

<div>
    <p class="or-post-header-label or-text-light">{{plural authors.length empty="" singular="Author" plural="Authors"}}</p>
    <p class="or-post-header-value">{{authors}}</p>
</div>

The metadata element follows a basic structure: a label on top and the value beneath it. For authors, we leverage two handy Handlebars helpers: plural and authors.

The plural helper smartly adjusts the label text based on the number of items (or authors, in this case). When there's just one author, it reads "Author," but for multiple authors, it changes to "Authors."

The authors helper, on the other hand, generates a comma-separated list of authors, each linking to their respective profile pages. This is a great way to acknowledge authors and make it easy for readers to explore more of their work.

Publication date

<div>
    <p class="or-post-header-label or-text-light">Published</p>
    <p class="or-post-header-value">{{date}}</p>
</div>

Next up, we show the publication date with the {{date}} helper. While this helper may seem simple, there’s a lot of power under the hood. Not only can you format the date however you want, but Ghost will also default to outputting the date based on the language you enter in General settings.

The screenshot below shows how the date format changes based on the language set in Ghost Admin.

The art of the post template

Image credit

{{#match feature_image_caption}}
    <div>
        <p class="or-post-header-label or-text-light">Image credit</p>
        <p class="or-post-header-value">{{feature_image_caption}}</p>
    </div>
{{/match}}

Our last bit of metadata is the image credit or caption for the feature image. We use the match helper to check whether this value has been set. If so, we display it.

💡
If you use Ghost’s built-in Unsplash integration (a free library of high-quality images), the photographer’s name and link will be automatically added as the image caption. Not only does this save you from some manual work, but it also helps you give proper credit where it's due!

Feel free to experiment with these helpers and see how you can customize them to suit your site's style and requirements.

Picture perfect with a feature image

The feature image is the first visual your reader encounters, setting the tone for the rest of your post. Let's see how we handle this critical component in Ghost.

{{#match feature_image}}
    <div class="or-post-header-image">
        <picture class="">
            <source 
            srcset="
            {{img_url feature_image size="xxs" format="avif"}} 30w,
            {{img_url feature_image size="xs" format="avif"}} 100w,
            {{img_url feature_image size="s" format="avif"}} 300w,
            {{img_url feature_image size="m" format="avif"}} 600w,
            {{img_url feature_image size="l" format="avif"}} 1200w,
            {{img_url feature_image size="xl" format="avif"}} 2000w"
            sizes="(max-width: 350px) 300px, (max-width: 700px) 600px, (max-width: 800px) 1200px, (max-width: 1200px) 300px, 600px"
            type="image/avif"
            >
            <source 
            srcset="
            {{img_url feature_image size="xxs" format="webp"}} 30w,
            {{img_url feature_image size="xs" format="webp"}} 100w,
            {{img_url feature_image size="s" format="webp"}} 300w,
            {{img_url feature_image size="m" format="webp"}} 600w,
            {{img_url feature_image size="l" format="webp"}} 1200w,
            {{img_url feature_image size="xl" format="webp"}} 2000w"
            sizes="(max-width: 350px) 300px, (max-width: 700px) 600px, (max-width: 800px) 1200px, (max-width: 1200px) 300px, 600px"
            type="image/webp"
            >
            <img
            srcset="
            {{img_url feature_image size="xxs"}} 30w,
            {{img_url feature_image size="xs"}} 100w,
            {{img_url feature_image size="s"}} 300w,
            {{img_url feature_image size="m"}} 600w,
            {{img_url feature_image size="l"}} 1200w,
            {{img_url feature_image size="xl"}} 2000w"
            sizes="(max-width: 350px) 300px, (max-width: 700px) 600px, (max-width: 800px) 1200px, (max-width: 1200px) 300px, 600px"
            src="{{img_url feature_image size="xxs"}}"
            alt="{{#match feature_image_alt}}{{feature_image_alt}}{{else}}{{title}}{{/match}}"
            >
        </picture>
    </div>
{{/match}}

Once more, we make use of the match helper to check if a feature image is set. Without one, this entire block of code is simply skipped. But, if there's an image ready to shine, we employ Ghost's img_url helper.

What's brilliant about the img_url helper is that it automatically constructs optimized, responsive images. This ensures that no matter what device a user is on, they'll receive the appropriately sized image — be it for a smartwatch or a high-definition 4K monitor.

Images can significantly contribute to the load time of a webpage, but this optimization strategy ensures your Ghost site remains blazingly fast 🏎️

If the concept of responsive images sounds a bit daunting, don't worry — it's a complex topic! You can delve into how the picture tag works and the benefits it offers. Our documentation also provides valuable insights on implementing responsive images in Ghost and utilizing the img_url helper.

And if you're looking for a shortcut, Ghost's VS Code extension is your best friend. It can automatically generate this responsive image code for you ✨

Presenting your content

When it comes to your publication, the main content is the star of the show. But it's the side features that complete the experience, providing context, navigation, and engagement opportunities. So let's dive into how we structure the content and these additional components in Ghost.

The diagram below lays out the post content and sidebar, showing the code behind these elements.

The art of the post template

We start with the primary content:

<article class="or-post-content">
    {{content}}
</article>

To help lay out our content, we wrap it in an article tag. Next, the magic of the content helper comes into play. It brings in all the content written in the editor, including text, images, cards, and more.

But a great post isn't only about the main text. Let's turn our attention to the aside section that houses additional features: a table of contents placeholder, share buttons, and a read-next section.

<aside class="or-post-aside">
    <!-- Content for table of contents, share buttons, and read-next section -->
</aside>

This aside tag introduces a sidebar of handy features. Here you can integrate a table of contents for easy navigation, share buttons for spreading the word on social media, and a read-next section to keep your audience hooked with more content.

But you might be wondering how to get these features up and running on your template. Well, you're in luck! We have comprehensive tutorials to guide you:

How to add a table of contents to your Ghost site
Let your readers know what to expect in your posts and give them quick links to navigate content quickly by adding a table of contents with the Tocbot library.
The art of the post template
How to create a read-next section in your Ghost theme
In this tutorial, learn to build a read-next section for your Ghost theme so that your audience always knows what they should be reading next.
The art of the post template

There's also a full download of the post template file at the end of this post.

We don’t have a tutorial on adding share buttons to your template yet. Let us know if you’d like to see it!

How to enable comments

One of the keys to a lively website is engagement and nothing does that better than a robust comments section. This part of your site allows your readers to share their thoughts, engage with other readers, and even provide valuable feedback.

Now, let's take a look at how to incorporate this crucial component into your Ghost site:

The art of the post template
{{comments}}

The simplicity of the comments helper belies its impact. When comments are enabled, this helper outputs the comments user interface (UI) onto your site. What's more, you have the ability to customize certain aspects of the UI to better fit your site's look and feel.

For a deeper dive into the options available to you, check out our docs, which provide extensive guidance on how to customize the comments section.

As a final note, remember to close your post block with the {{/post}} helper. This marks the end of your post and ensures all your code stays neatly organized.

And that's it! You've got a fully-featured Ghost template ready for your posts. Here's the full template for reference and available for download.

Summary

Whew! That's a lot of ground we covered, from understanding the basic structure of the post template to diving into the post context, Handlebars helpers, and the nuances of setting tags and authors. We've looked at how to display post metadata, optimize feature images, and even tackled some advanced aspects, like custom excerpts and adding an aside section for share buttons and a read-next feature. And, of course, we've explored the important task of fostering engagement through a comments section.

The next step is yours. Take what you've learned here and put it into practice. Experiment with the different helpers and design elements to realize your vision. Ghost is a powerful and flexible platform that can help your content really sing.

And remember, you're not alone! If you have questions, need help, or simply want to share the dope Ghost theme you created, come join us on the official Ghost Forum. It's a lively and supportive community full of people who are passionate about Ghost and eager to help each other out. We look forward to seeing you there!

]]>
<![CDATA[🥯 Build with Ghost: A partial guide to everything]]>https://ghost.org/tutorials/partial-guide/6478bb121275730001011c94Tue, 18 Jul 2023 07:00:28 GMT

Welcome to issue #7! Seven is the most popular lucky number in the world, so this issue is packed with a whole lot of good fortune 🥠

Here's what else this issue includes:

  • Build beautiful themes with three new tutorials to help you
  • Grow engagement with new signup cards and embeddable forms
  • Gain insights from Erin Mikail Staples, a renowned developer advocate, tech educator, and comedian, as she shares the secrets behind her vibrant, stylish Ghost site
🏋️

Pro tip: Bring up the card menu in the editor by typing / on a new line. Start typing to filter card types and quickly find the one you want 🎴

Use partials to simplify your theme development

Partials are an essential tool for quick, maintainable theme development. These partial templates encompass bits of code that you can use throughout your theme. Typical use cases include cards, CTAs, headers, navbars, or any other elements you find yourself using repeatedly. (Those links all point to real-world examples in official Ghost themes.)

A complete guide to partials in Ghost
Learn partials in Ghost for better code maintenance and consistency. This tutorial will teach you what a partial is, how it’s used, and some advanced tips and tricks.
🥯 Build with Ghost: A partial guide to everything

Our new tutorial lays out everything you need to know about partials, from the very basics to advanced properties. In particular, we use a partial to create a card for a fictional music publication, Of Record, and walk through every line of code that makes it work.

🥯 Build with Ghost: A partial guide to everything

This tutorial complements two others we just released:

A comprehensive guide to Ghost’s index template
Learn to create and customize your Ghost theme’s index template in this comprehensive tutorial. Understand the index template functionality, the power of the post loop, and bonus theme customization techniques.
🥯 Build with Ghost: A partial guide to everything
A comprehensive guide to Ghost’s default template
Discover the secrets of Ghost’s default.hbs template. Learn how to optimize your site’s common elements and become an efficient theme-creation machine 🤖
🥯 Build with Ghost: A partial guide to everything

Just shipped 🚢

We've recently shipped two related, exciting features: signup cards and embeddable signup forms.

Signup cards, available to users on the beta editor, give you new ways to grow your audience. Add them to a post by selecting the Signup card from the card menu or by typing / on a new line. Customize the card to fit your publication.

🚨

Important note for theme developers. Signup cards require updates to a theme's CSS to display properly. In particular, cards that are full-width or have a split layout with a contained image add a kg-content-wide class that requires styling. Additionally, the container for post content may also need to be updated. See our docs for more info. All official themes have been updated, so they are also a great resource for understanding these changes.

Whereas signup cards are for use across your Ghost publication, embeddable signup forms can be used anywhere on the web. Customize the form and use the provided code to grow your audience on any platform.

Ideas and tools 🛠️

Erin Mikail is here for the rise of the personal blog (again)

🥯 Build with Ghost: A partial guide to everything

As the Sr. Developer Community Advocate at HumanSignal, Erin empowers the open-source community behind the Label Studio project. Working from NYC, Erin creates educational materials like tutorials, speaks at events, runs workshops, and maintains community channels to improve user experience.

While doing all of that, Erin also has a kick-ass Ghost site! It's rocking a slightly modified version of the Groovy theme, which showcases some clever uses of partials and an engaging index template.

Erin has been on Ghost for a while because, as an open-source platform, it provides flexibility and control over content and appearance. Also, the fact that Ghost is a nonprofit aligns with Erin's values. She says, "Ghost.org offers a genuine commitment to the public good rather than focusing on creating profits for shareholders. They reinvest their revenue into their platform, continually improving and upgrading. This has given me the confidence that they truly value their community, not a group of external investors" ❤️

🥯 Build with Ghost: A partial guide to everything
Meet Erin's coding partner, Q

If Erin could pass on one bit of advice when working with Ghost, it's not to be afraid to ask for help. Ghost's Forum and GitHub are open and responsive. They're full of people willing to help. Erin says she has found the answer she needed on the Forum too many times to count.

done > perfect

And, when possible, Erin says to remember that done is better than perfect. Rather than letting posts linger as drafts, "embrace the joy of constantly improving and being a work in progress." Amen!

👉 Follow Erin (and Q) on the web


Sites featured in the Build with Ghost newsletter are discovered through our creator network, Ghost Explore. It’s a way for creators and readers alike to discover their favorite new publications. Anyone running a Ghost site can add themselves to Explore to be featured throughout the wider Ghost ecosystem. If you’d like to be featured in this newsletter, add your site to Explore and reply to this email.

🥯 Build with Ghost: A partial guide to everything

Thanks for building with us.

Have an idea for a Ghost tutorial? Reply to this email and let us know ❤️

Looking for other creators and developers working with Ghost? Join the official Ghost Forum, where we talk about all things Ghost!

]]>
<![CDATA[A complete guide to partials]]>https://ghost.org/tutorials/partials/6499e6926ab27c000136adddTue, 27 Jun 2023 19:09:18 GMT A complete guide to partials

Imagine creating an eye-catching card for your homepage posts, only to realize you need the same card in your post’s read-more section. Copy, paste, and repeat, right? Not so fast! Any change to the card means updating it everywhere you used it—a repetitive and error-prone task.

Enter partials: the solution to your copy-paste woes.

Partials are a helper for reusing chunks of code across your Ghost theme. In this tutorial, we’ll spill the beans on everything you need to know about partials by looking at an example from the fictional publication Of Record. By the end of this tutorial, you’ll know:

  • What a partial is and how to use it
  • Advanced options with props
  • Tips and tricks for excelling with partials

Let’s go 👟

What’s a partial?

A partial is a Handlebars helper for reusing chunks of a template. Think of “partial” as being short for “partial template”—a partial can’t stand alone like a post or index template but is intended to be used as a component of those templates.

Ghost Handlebars Theme Helpers: partials
Create reusable pieces of markup with Handlebars partials. Read more about Ghost themes! 👻
A complete guide to partials

Many theme devs find partials helpful in two situations. First, they’re great for any repeating element like a card or CTA, especially when used in multiple templates. You get a single source of truth for the component that doesn’t need to be kept in sync!

Second, partials are useful for splitting out complex elements (like a header) into more manageable components. Instead of a template file with a 100 lines of code, using a partial can cut the file in half and make it easier to work with.

Common use cases for partials include (but aren’t limited to):

Whenever you ever find yourself copying and pasting a lot or seeing a file become long and messy, a partial is likely the perfect solution.

How to use a partial

We covered what a partial is and some common use cases. But how do we use it?

Partials are individual Handlebars files. The file's name is up to you. For a card partial, you can be creative and call it card.hbs. Crucially, however, all your partials need to be in a folder called partials that’s at the root of your theme.

Here is the folder structure for Casper with the partials folder at the top level.

.
├── LICENSE
├── README.md
├── assets
├── author.hbs
├── default.hbs
├── error-404.hbs
├── error.hbs
├── gulpfile.js
├── index.hbs
├── package.json
├── page.hbs
├── partials
├── post.hbs
└── tag.hbs

And, here are the contents of that partials folder:

partials
├── icons
│   ├── avatar.hbs
│   ├── facebook.hbs
│   ├── fire.hbs
│   ├── loader.hbs
│   ├── lock.hbs
│   ├── rss.hbs
│   ├── search.hbs
│   └── twitter.hbs
└── post-card.hbs

Once you’ve created your partial, it’s time to bring it into your template. Use Handlebars curly brackets with a right angle bracket and the partial name. Or, more simply, like this:

{{> "partial-name"}}

For example, referencing the partials folder from Casper above, here’s how to bring in the search icon:

{{> "icons/search"}}

Wherever you add this bit of code, Ghost will render the SVG search icon.

With the fundamentals under our belt, let’s walk through a partial from Of Record, a publication that focuses on vinyl records.

Create a post card with a partial

A complete guide to partials
A complete guide to partials
single card from of record theme

In the screenshots above, you can see a grid of cards from the publication’s homepage and an individual card in isolation. (See our tutorial on creating an index template for more info about the post loop.)

Here’s the entire code for the partial card:

<article class="or-post-card {{classes}}" style="--accent: {{primary_tag.accent_color}}">
    {{#if feature_image}}
    <a href="{{url}}">
        <picture class="or-post-card-image">
            <source 
                srcset="
                {{img_url feature_image size="xxs" format="avif"}} 30w,
                {{img_url feature_image size="xs" format="avif"}} 100w,
                {{img_url feature_image size="s" format="avif"}} 300w,
                {{img_url feature_image size="m" format="avif"}} 600w,
                {{img_url feature_image size="l" format="avif"}} 1200w,
                {{img_url feature_image size="xl" format="avif"}} 2000w"
                sizes="(min-width: 1200px) 1200px, 100vw" 
                type="image/avif"
            >
            <source 
                srcset="
                {{img_url feature_image size="xxs" format="webp"}} 30w,
                {{img_url feature_image size="xs" format="webp"}} 100w,
                {{img_url feature_image size="s" format="webp"}} 300w,
                {{img_url feature_image size="m" format="webp"}} 600w,
                {{img_url feature_image size="l" format="webp"}} 1200w,
                {{img_url feature_image size="xl" format="webp"}} 2000w"
                sizes="(min-width: 1200px) 1200px, 100vw" 
                type="image/webp"
            >
            <img
                srcset="
                {{img_url feature_image size="xxs"}} 30w,
                {{img_url feature_image size="xs"}} 100w,
                {{img_url feature_image size="s"}} 300w,
                {{img_url feature_image size="m"}} 600w,
                {{img_url feature_image size="l"}} 1200w,
                {{img_url feature_image size="xl"}} 2000w"
                sizes="(min-width: 1200px) 1200px, 100vw" 
                src="{{img_url feature_image size="l"}}"
                alt="{{#if feature_image_alt}}{{feature_image_alt}}{{else}}{{title}}{{/if}}"
            >
        </picture>
    </a>
    {{else}}
    <div class="or-post-card-image or-post-card-image-placeholder">
        <p>{{excerpt}}</p>
    </div>
    {{/if}}

    <div class="or-post-card-content">
        <h2><a href="{{url}}">{{title}}</a></h2>
        <footer class="or-post-card-footer or-text-light">
            <p class="or-text-light">by <strong>{{authors}}</strong></p>
            {{comment_count}}
        </footer>
    </div>
</article>

There’s a lot there, so let’s walk through it line by line.

Using partials with custom properties

<article class="or-post-card {{classes}}" style="--accent: {{primary_tag.accent_color}}">

The card partial opens with an HTML article tag. We include a CSS class to help with styling, but you may have noticed that some Handlebars syntax has snuck into our class name: {{classes}}.

classes refers to a custom property that’s defined on the partial. It’s a way for you to pass additional data to the partial wherever it’s invoked in your theme. In Of Record’s home template, we emphasize certain cards by adding the or-large-text class, which increases the size of the title.

A complete guide to partials

Here’s what that looks like in the home template:

{{! In home.hbs, for a section of posts we want to emphasize }}
{{#foreach posts}}
  {{> "card" classes="or-large-text"}}
{{/foreach}}

The classes property is then available to use within the partial file. When the property is included, it’s added to the class list. Otherwise, the class list only includes or-post-card.

{{> "card" class="or-large-text"}}

{{! outputs }}
<article class="or-post-card or-large-text">
...
</article>
 
{{> "card"}}

{{! outputs }}
<article class="or-post-card">
...
</article>

We also include a style attribute on the article element.

style="--accent: {{primary_tag.accent_color}}"

By defining the CSS custom property --accent via the style attribute, we can dynamically change the color of the title text on hover. {{primary_tag.accent_color}} is a value available on the tag object that provides a hex color defined in Ghost Admin. That’s the reason for the red color in the screenshot above.

Putting this all together, the partial is rendered as follows:

<article class="or-post-card" style="--accent: #349234">...</article>

Let’s now move on to the card image.

Constructing the card image

{{#if feature_image}}
<a href="{{url}}">
    <picture class="or-post-card-image">
        <source 
            srcset="
            {{img_url feature_image size="xxs" format="avif"}} 30w,
            {{img_url feature_image size="xs" format="avif"}} 100w,
            {{img_url feature_image size="s" format="avif"}} 300w,
            {{img_url feature_image size="m" format="avif"}} 600w,
            {{img_url feature_image size="l" format="avif"}} 1200w,
            {{img_url feature_image size="xl" format="avif"}} 2000w"
            sizes="(min-width: 1200px) 1200px, 100vw" 
            type="image/avif"
        >
        <source 
            srcset="
            {{img_url feature_image size="xxs" format="webp"}} 30w,
            {{img_url feature_image size="xs" format="webp"}} 100w,
            {{img_url feature_image size="s" format="webp"}} 300w,
            {{img_url feature_image size="m" format="webp"}} 600w,
            {{img_url feature_image size="l" format="webp"}} 1200w,
            {{img_url feature_image size="xl" format="webp"}} 2000w"
            sizes="(min-width: 1200px) 1200px, 100vw" 
            type="image/webp"
        >
        <img
            srcset="
            {{img_url feature_image size="xxs"}} 30w,
            {{img_url feature_image size="xs"}} 100w,
            {{img_url feature_image size="s"}} 300w,
            {{img_url feature_image size="m"}} 600w,
            {{img_url feature_image size="l"}} 1200w,
            {{img_url feature_image size="xl"}} 2000w"
            sizes="(min-width: 1200px) 1200px, 100vw" 
            src="{{img_url feature_image size="l"}}"
            alt="{{#if feature_image_alt}}{{feature_image_alt}}{{else}}{{title}}{{/if}}"
        >
    </picture>
</a>
{{else}}
<div class="or-post-card-image or-post-card-image-placeholder">
    <p>{{excerpt}}</p>
</div>
{{/if}}

This part of the card begins with a test: does the post in question have a feature image? In the code, we use the Handlebars if helper. This helper tests whether a value exists or is true. If so, then the image code is rendered. Otherwise, the card shows a post excerpt. This ensures that the card always looks great, no matter the situation 💅

In the screenshot below, the card on the left doesn’t have a feature image, so we display the excerpt instead. The other cards all have feature images.

A complete guide to partials

To display the image, we use the img_url helper. While there’s a lot going on with the image code, all that markup is worth the trouble because it's the best way to optimize your site, and, best of all, with our VS Code Extension, you can generate most of it automatically 🤖

<picture class="or-post-card-image">
    <source 
        srcset="
        {{img_url feature_image size="xxs" format="avif"}} 30w,
        {{img_url feature_image size="xs" format="avif"}} 100w,
        {{img_url feature_image size="s" format="avif"}} 300w,
        {{img_url feature_image size="m" format="avif"}} 600w,
        {{img_url feature_image size="l" format="avif"}} 1200w,
        {{img_url feature_image size="xl" format="avif"}} 2000w"
        sizes="(min-width: 1200px) 1200px, 100vw" 
        type="image/avif"
    >
    <source 
        srcset="
        {{img_url feature_image size="xxs" format="webp"}} 30w,
        {{img_url feature_image size="xs" format="webp"}} 100w,
        {{img_url feature_image size="s" format="webp"}} 300w,
        {{img_url feature_image size="m" format="webp"}} 600w,
        {{img_url feature_image size="l" format="webp"}} 1200w,
        {{img_url feature_image size="xl" format="webp"}} 2000w"
        sizes="(min-width: 1200px) 1200px, 100vw" 
        type="image/webp"
    >
    <img
        srcset="
        {{img_url feature_image size="xxs"}} 30w,
        {{img_url feature_image size="xs"}} 100w,
        {{img_url feature_image size="s"}} 300w,
        {{img_url feature_image size="m"}} 600w,
        {{img_url feature_image size="l"}} 1200w,
        {{img_url feature_image size="xl"}} 2000w"
        sizes="(min-width: 1200px) 1200px, 100vw" 
        src="{{img_url feature_image size="l"}}"
        alt="{{#if feature_image_alt}}{{feature_image_alt}}{{else}}{{title}}{{/if}}"
    >
</picture>

We use the standard HTML picture tag. Inside it, there are two source elements and an img element. We use each of these to bring in different sizes and formats of images. Image sizes are defined on a theme-by-theme basis in the package.json file.

The important item to note here is the values for the srcset attribute. The img_url helper is used to generate specific image sizes and formats. The first two formats are defined as AVIF and WEBP, which are high-efficiency image formats. However, some older browsers don’t support these formats, so the img element provides a fallback to whatever format the image was originally uploaded in. The sizes are defined to match your design with the goal of loading the right-sized image depending on the device’s screen. The sizes attribute is a complex media query that lets the browser know which image should be chosen from the set.

💡
Responsive images an entire onto itself. Check out this overview and guide to learn more.

You’re probably thinking, “Why does image loading gotta be so complex?” We hear ya! As mentioned, make things a lot easier for yourself by using the official Ghost VS Code extension to generate a lot of this code for you. And, remember: while optimizing images for the web is a complex process, the payoff is huge: a blazingly fast website.

The last bit of code to cover is the expression used for the alt tag, which provides a textual description of the image for improved accessibility. This code tests whether the author has set an alt tag. If so, that’s rendered. Otherwise, the tag falls back to the post title.

Adding the card text content

<div class="or-post-card-content">
    <h2><a href="{{url}}">{{title}}</a></h2>
    <footer class="or-post-card-footer or-text-light">
        <p class="or-text-light">by <strong>{{authors}}</strong></p>
        {{comment_count}}
    </footer>
</div>

Bringing in the card text content is comparatively simple.

We wrap the h2 tag in an anchor tag so that we can provide a link to the post. {{url}} renders the post’s URL and {{title}} the title.

Next, the post footer includes the post’s byline, with a link to the author. Ghost’s {{authors}} helper automatically renders a list of authors, each linked to their profile page. Finally, comment_count shows the number of comments a post has. If there aren’t any comments yet, nothing is rendered.

This is only a limited example of the data available to render. Some other exciting possibilities include reading time, member access, and featured status. Check out the docs to see what kind of trouble you can get up to 😉

Summary

Partials are now part of your theme development repertoire. You’ve learned what they are, how to use them, and how they benefit code maintainability and consistency. By looking at the use of the card partial in Of Record’s theme, you saw how it operates in the context of a real-world problem along with some tips and tricks for when you create your own.

Speaking of, we have lots more tutorials on nearly every aspect of creating a custom Ghost theme. If you come up against a nut you just can’t crack, hop on over to the official Forum, where an active community is eager to help you build the theme of your dreams and discuss all things Ghost.

]]>
<![CDATA[A comprehensive guide to the index template]]>https://ghost.org/tutorials/index/6490913fed7acb0001470b55Mon, 19 Jun 2023 20:16:40 GMT

It’s your site’s homepage. It brings together all the posts you’ve written into one place. It’s an essential part of all Ghost themes. It’s the index template, a VIP among your theme files.

In this tutorial, we’ll show you how to create your own index template by looking at an example from Of Record, a fictional publication focusing on vinyl records. By the end, you will:

  1. Understand what the index template is and how it functions
  2. Learn how to harness the power of the post loop effectively
  3. Discover bonus techniques to keep your theme on point

Let’s roll up our sleeves and dig in.

What’s the index template?

The primary job of the index template is to elegantly display your posts to your audience, guiding them to their next captivating read.

Technically speaking, the index template is a Handlebars file at the root of your theme with the filename index.hbs. With post.hbs and package.json, it’s one of three required files in a Ghost theme. It acts as the template for your homepage, author, tag, and subsequent pages like yoursite.com/page/2/.

💡
Ghost is supremely customizable, so you can supersede index.hbs by providing specialized templates like author.hbs and tag.hbs. Even with these specialized templates, the concepts discussed here still apply.

But enough with the abstract descriptions! Let’s look at the index template from Of Record’s theme.

A comprehensive guide to the index template

And here’s the code for the entire file. We’ll discuss each line of it below.

{{!< default}}

<main id="#main" class="or-container or-spacing-y">
    <div class="or-post-grid">
        {{!-- Loop through posts 1 to 5 --}}
        {{#foreach posts from="1" to="5"}}
          {{> "card"}}
        {{/foreach}}

        {{!-- If a visitor isn't a member, show a CTA to sign up --}}
        {{^if @member}}
            {{> "cta"}}
        {{/if}}
        
        {{!-- Loop through the rest of the posts--}}
        {{#foreach posts from="6" to="15"}}
          {{> "card"}}
        {{/foreach}}
    </div>

    {{!-- Show the pagination helper when there's more than one page --}}
    {{#match pagination.pages ">" 1}}
       {{pagination}}
    {{/match}}
</main>

What’s up with the default tag?

The top of the file begins with a seemingly strange mix of characters: {{!< default}}. This is one of Ghost’s Handlebars helpers. It tells Ghost to insert the contents of the current file into the default template, which simplifies theme development. You’ll generally find this helper at the top of root templates. We have an entire tutorial that explains how to use the default template.

A comprehensive guide to Ghost’s default template
Discover the secrets of Ghost’s default.hbs template. Learn how to optimize your site’s common elements and become an efficient theme-creation machine 🤖
A comprehensive guide to the index template

The finer points of spacing

Next up is a bit of standard HTML:

<main id="#main" class="or-container or-spacing-y">
    <div class="or-post-grid">

There’s nothing Ghost specific here. The theme uses the main tag to indicate that you’ve reached the main event on the page, generally the content of a page. Using this tag benefits your site’s accessibility and overall structure, but it’s totally optional in terms of Ghost.

On the main tag, we find two CSS classes that help with layout and spacing:

.or-container {
    width: min(100%, var(--max-width)); // --max-width = 80rem (~1280 px)
    padding: var(--gutter); // --gutter = max(2.5rem, 4vmax)
    margin-inline: auto;
}

.or-spacing-y {
    display: grid;
    gap: var(--spacing-large); // --spacing-large = 2rem
}

.or-spacing-y > *:first-child {
    margin-block-start: var(--spacing); // --spacing = 1rem
}

.or-container sets the width of the content. It ensures that the container has some padding, is centered, and is equal to 100% of the viewport and no larger than ~1280 px. .or-spacing-y creates vertical space between the elements.

It’s beyond the scope of the tutorial to discuss this CSS in detail, but the gist of it is to create a nice container for our content to live in.

Let’s see what goes inside.

A comprehensive guide to the index template

Make your inbox fire

Build a better internet with early access to features, tools, and tutorials.

No spam. Once a month. Unsubscribe any time.

The magic of the foreach loop

The purpose of index.hbs is to output a list of posts. How you choose to output that list of posts is entirely up to your imagination. You can use a collection of cards, a list of text, or some combination thereof.

Here are some examples from official Ghost themes.

Of Record outputs the post list with cards and uses CSS grid to achieve its layout.

A comprehensive guide to the index template
A comprehensive guide to the index template
CSS grid layout for index template

Here’s the CSS that controls the grid.

.or-post-grid {
    display: grid;
    grid-template-columns: repeat(6, 1fr); // Make 6 columns that take up the available width
    gap: var(--gap);
}

.or-post-card {
    grid-column: span 6; // On smaller viewports, cards take up the whole width
   
}

@media (--tablet) { // Above tablet viewports, cards span 2 or 3 cols 
    .or-post-card {
        grid-column: span 2;
    }
    
// Target card 1, 2, 5, 6
    .or-post-card:where(:nth-of-type(5n + 1), :nth-of-type(5n + 2)) {
        grid-column: span 3;
    }
}

And, as exciting as the options are for styling this list of posts, it’s important to understand what’s happening in the template to make this possible: the post loop!

The data available to the index template includes a collection of posts (via the posts array). The exact number of posts available per page is set in the theme's package.json file. Of Record sets this number to 15. This means the homepage will have 15 posts, and Ghost will automatically create additional pages, each with 15 posts, as necessary (at page/2, page/3) until the post list is exhausted.

To loop through these posts, use the foreach Handlebars helper. Its most basic usage looks like this:

{{#foreach posts}}
    {{!-- Do something with each post --}}
{{/foreach}}

The foreach helper renders the code between its open and closing tags for each post. If you’re not working with loops every day, this concept might seem a little obscure, so let’s look at a basic example.

Suppose we have a collection of three posts with the following titles:

  1. I’m post #1
  2. I’m post #2
  3. I’m post #3

In our template, then, we create the post loop:

{{#foreach posts}}
  <p>{{title}}</p>
{{/foreach}}

And Ghost renders it to HTML, which is sent to the browser:

<p>I'm post #1</p>
<p>I'm post #2</p>
<p>I'm post #3</p>

Inside the loop, you have access to all post data, including the title, feature image, excerpt, tags, and more. In Of Record’s template, a card partial is used to render this data. Partials or partial templates are bits of code that can be reused across your Ghost theme. Learn more about using partials.

In the loop from Of Record’s theme, the foreach includes additional attributes that enhance its functionality. (See all available attributes in the docs).

Specifically, instead of looping through all the posts, we only loop through the first five. Remember that there are a total of 15 posts on the page, so this only represents a third of the collection.

{{!-- Loop through posts 1 to 5 --}}
{{#foreach posts from="1" to="5"}}
    {{> "card"}}
{{/foreach}}

Why would we want to do this, though? It provides an opportunity to pause the post loop and introduce a call to action (CTA).

Dynamic CTA

A comprehensive guide to the index template

The code to introduce this CTA is included in the index.hbs template.

{{!-- If a visitor isn't a member, show a CTA to sign up --}}
{{^if @member}}
  {{> "cta"}}
{{/if}}

What’s clever is that the CTA only shows for visitors who aren’t logged in. This saves us from being tacky and asking already logged-in members to sign up again 🙃

It’s possible to check for a user’s logged-in status by using Ghost’s if helper in conjunction with the member object. Usually, you use the if helper like this:

{{#if value_to_check}}

Notice that if is preceded by “#.” This is the default way to use the helper, checking if a value is true or not. However, in the index.hbs file, we use {{^if value_to_check}}. That little caret (^) does a lot of work. Instead of saying, “if so and so is true,” it says the opposite, “if so and so is not true.”

It can take a minute to wrap your head around it, but the caret can be used with many Ghost helpers to check for the inverse state of things. Our CTA, {{^if @member}}, is checking whether the current visitor is not a member. If they aren’t, then we show them the CTA, via the cta partial. If they are a member, then we hide it and carry on with the regularly scheduled programming, the remainder of the posts.

{{!-- Loop through the rest of the posts--}}
{{#foreach posts from="6" to="15"}}
    {{> "card"}}
{{/foreach}}

The template then closes up the grid, which leaves us with one remaining element to discuss: pagination.

Pagination

As noted, Of Record is configured to include 15 posts per page. But these are ardent vinyl aficionados. They’re going to have a lot more than 15 posts. So, where do they all go?

Ghost automatically paginates your content, which means that since Of Record has 150 posts total, they’ll have 10 pages of posts. The final part of the index template renders the UI for visitors to get to those pages.

A comprehensive guide to the index template

Here’s the code in the template.

{{!-- Show the pagination helper when there's more than one page --}}
{{#match pagination.pages ">" 1}}
    {{pagination}}
{{/match}}

We first check whether there’s more than one page. No use in showing the pagination element if there’s only one page! This check is done by using the match helper. It’s like the if helper above, except that it’s able to check for more than just true and false values. In this case, we’re checking whether the number of pages is greater than one. The syntax of the match helper takes two values separated by an operator like <, >=, and <=.

If the expression evaluates to true, then the code between the match helper tags is rendered. For Of Record, their total number of pages is greater than 1, so the pagination helper is shown. It provides pagination metadata and links to previous and next pages.

And, speaking of pages, we have just about reached the end of the index.hbs template. The only thing that’s left is to close up the main tag and recap our progress.

Summary

In this tutorial, you've gained a comprehensive understanding of how the index.hbs template works in Ghost. We've explored how it functions to assemble and display your posts, and how to utilize the power of the post loop effectively. We also dipped our toes into some advanced techniques to customize your Ghost theme. You learned how to break up your post loop to insert a dynamic call to action (CTA), style your layout with CSS, and implement pagination to manage your content effectively.

With this newfound knowledge, you are well-equipped to start customizing your own Ghost site 💪 Consider experimenting with different layouts for your posts to find out what works for your publication. If you're in need of some inspiration, subscribe to the monthly Build with Ghost newsletter. In addition to providing tips and tricks for creating custom themes, we always feature a Ghost site of the month and some other gorgeous sites sure to get the creativity flowing.

]]>
<![CDATA[A comprehensive guide to the default template]]>https://ghost.org/tutorials/default/6488f607ed7acb00014709e8Thu, 15 Jun 2023 01:11:06 GMT A comprehensive guide to the default template

When visiting a website, many elements are shared across its different pages, like the navigation bar, footer, meta tags, scripts, and stylesheets. Including these elements individually on every page of your theme is time-consuming, error-prone, and, let’s face it, tedious 🫠 Save yourself time, effort, and errors by utilizing Ghost’s default template. It packs all these common elements of your site into one powerful, reusable base layer.

In this tutorial, you’ll learn everything you need to know about this exceedingly convenient template. The first order of business will be to understand what the default template is and how to use it. Then, the tutorial will cover common elements included in it, based on an example from Of Record, a publication specializing in vinyl records. Let’s dive in!

What’s the default template?

The default template is a special file in a Ghost theme. Using it is simple. Add a file to the theme folder called default.hbs. Doing so makes the Handlebars file the base layer for your theme, meaning that all other content gets inserted into it.

Think of the default template as a picture frame. Although you might change the content inside it, the frame stays the same. Likewise, default.hbs frames all your content, from the homepage to the post page to everything else.

0:00
/0:36

Ghost doesn’t require the default.hbs file for a theme to be valid, but almost all developers include it because it’s fantastically useful.

default.hbs is rendered on every page of your site. That means the template should include those elements that typically appear on every page. In the next section, we’ll look at an example of the default.hbs template and the elements included in it.

What to include in the default template

The default.hbs file below is taken from Of Record’s custom theme. As mentioned, they’re a fictional publication that focuses on vinyl records — listening to them, collecting them, and cursing that collection when they move into a tiny house.

Here’s a screenshot of the site's homepage:

A comprehensive guide to the default template

And here's the code for its default.hbs file:

<!DOCTYPE html>
<html lang="{{@site.locale}}">
    <head>

        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>{{meta_title}}</title>

        <link rel="stylesheet" href="{{asset "built/index.css"}}" />
        <script src="{{asset "built/index.js"}}" defer></script>

        {{ghost_head}}
        {{!-- Outputs important meta data and settings, should always be in <head> --}}

    </head>
    <body class="{{body_class}}">

        <div class="or-viewport">
            {{#is "post,page"}}
                {{> "navbar"}}  
            {{else}}
                {{> "header"}}
            {{/is}}

            {{{body}}}
            {{!-- All content gets inserted here, index.hbs, post.hbs, etc --}}

            <footer class="or-footer">
                <div class="or-flex or-container">
                    <p>{{@site.title}} &copy; {{date format="YYYY"}}</p>
                    {{navigation type="secondary"}}
                    <p>Published with <a href="<https://ghost.org>" target="_blank" rel="noopener">Ghost</a></p>
                </div>
            </footer>
        </div>

        {{ghost_foot}}
        {{!-- Outputs important scripts - should always be included before closing body tag --}}
    </body>
</html>

In the above default.hbs file, the overall structure can be simplified into this:

<!DOCTYPE html>
<html>
  <head></head>
  <body></body>
</html>

Remember that the whole point of the template is to capture elements that are mandatory on every page. From that perspective, the elements included here make sense because, on every page, we need these elements to have valid HTML.

Here's what each of these elements does. <!DOCTYPE html> informs the browser we’re using HTML or, for the longwinded, hypertext markup language.

Next, we open the HTML document with <html lang="{{@site.locale}}">. On this HTML tag, we include the lang attribute, which tells the browser your site’s language. But what’s that {{@site.locale}} doing in there? It’s a Ghost Handlebars helper that dynamically inserts the right language based on what’s entered in Ghost Admin.

Now, let's dissect the head and body and see the guts of this thing.

Inside the head

The head tag is used to include metadata about the page and load assets (styles and scripts) for it. Let’s go through each line of it and explain what’s happening.

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

The first two lines are meta tags, vital for your site's look and feel. The first one, <meta charset="utf-8">, informs the browser of the character encoding used on your page. It ensures your text appears as intended. The second, <meta name="viewport" content="width=device-width, initial-scale=1">, is the cornerstone of responsive design. It controls page dimensions and scaling to ensure your site looks fantastic on any device.

<title>{{meta_title}}</title>

The title tag, powered by Ghost’s meta_title helper, furnishes the page’s title that shows up in browser tabs and search results.

<link rel="stylesheet" href="{{asset "built/index.css"}}" />
<script src="{{asset "built/index.js"}}" defer></script>

The link and script tags are the workhorses that bring your CSS and JS files to life. Ghost requires the use of the asset helper to load them. This ensures your assets are cached (and cache-busted) to boost your site's performance.

{{ghost_head}}

ghost_head, the final element in the head tag, is a special helper Ghost uses to load crucial metadata for SEO and additional scripts and styles.

Using default.hbs means that these elements need not be repeated with every template file, saving you time and a lot of copying and pasting 😰

Into the body

Let’s now hop on the Magic School Bus and get into the body. This is where all the content visible to the user appears.

On the body tag, we find another Ghost helper: <body class="{{body_class}}">. This helper outputs different class names based on the page and context. That means, for example, that when you're on the homepage, the body will have the home-template class. But when on a post page, it’ll have the post-template class. These classes are supremely helpful for targeting different contexts with conditional styles.

Next up is <div class="or-viewport">. This div wraps the page's content and helps with the layout. Note that its inclusion here is dependent on the current theme and totally optional, but let's spell out its purpose for the curious.

A comprehensive guide to the default template
Keep the page from looking like this 🙃

Have you ever visited a website that has a footer that shows up in the middle of the page, like someone who has their pants pulled up way too high? In this theme, <div class="or-viewport"></div> is used to prevent that through the following CSS:

.or-viewport {
    display: flex;
    flex-direction: column;
    justify-content: space-between; // Make the footer stick to the bottom
    min-height: 100vh; // Make the div at least as tall as the viewport
}
💡

Why is the class prefixed with "or-"? Great question! The prefix "or-" is short for "Of Record," the theme’s name. There are two reasons for the convention of prefixing classes like this. First, it ensures that the class doesn’t interfere with any Ghost or user classes. Second, it makes it easy to identify when a class is coming from the theme, rather than from some other source.

{{#is "post,page"}}
  {{> "navbar"}}  
{{else}}
  {{> "header"}}
{{/is}}
A comprehensive guide to the default template
Default navigation on post page
A comprehensive guide to the default template
Full-size hero image with navigation on tag page

We finally come to some content! This block of code introduces the site’s navigation bar. However, because the navigation bar text color needs to change when on a post or page, we use the is helper to conditionally render the output.

Ghost Handlebars Theme Helpers: is
The #is helper allows theme developers to check the context of the current route. Read more about custom Ghost themes! 👻
A comprehensive guide to the default template

{{#is "post,page"}} checks whether the current context is a post or not. If so, it renders the simple navbar with dark text. Otherwise, it renders the header partial.

A comprehensive guide to the default template

Make your inbox fire

Build a better internet with early access to features, tools, and tutorials.

No spam. Once a month. Unsubscribe any time.

Bringing in the body

A concept reiterated in this tutorial is that the default template is a base layer that gets included on every page. This means that the specific content for each of those pages — like an author page or post — needs somewhere to go. The {{{body}}} helper does exactly that: it tells Ghost where to render the template’s content. You can imagine copying the entire code of the post template and pasting it over the {{{body}}} helper, except Ghost does it for you. Everything in the post template will be rendered between the navbar and footer in the default template. This is also why you’ll see {{!< default}} at the top of most templates. It’s telling Ghost to put the template’s contents into the default file.

A comprehensive guide to the default template

The final bit of content for default.hbs is the footer:

<footer class="or-footer">
  <div class="or-flex or-container">
    <p>{{@site.title}} &copy; {{date format="YYYY"}}</p>
    {{navigation type="secondary"}}
    <p>Powered by <a href="<https://ghost.org>" target="_blank" rel="noopener">Ghost</a></p>
  </div>
</footer>

The markup for the footer begins with the footer tag followed by a div. The styling for these elements reduces the font size and text opacity. .or-container is an important class that helps define the max width of the element, provide padding, and center it. Again, its inclusion is dependent on the current theme, but its use illustrates a method of keeping sizing consistent across a theme. Here's the CSS for the class:

.or-container {
    width: min(100%, var(--max-width)); // max-width = 80rem
    padding: var(--gutter); // gutter = max(2.5rem, 4vmax);
    margin-inline: auto; // logical prop for margin-left: auto; margin-right: auto;
}

Inside the footer, there are three items:

  1. The copyright
  2. The secondary navigation
  3. The "Powered by Ghost" tagline

Let's walk through each one.

<p>{{@site.title}} &copy; {{date format="YYYY"}}</p>

The copyright uses a standard paragraph tag. The @site object is used to bring in the site’s title. &copy; is the HTML code for the copyright symbol (©). {{date format="YYYY"}} is Ghost’s date helper. Usually, you use it to output the date an article is published. However, when it’s used without a property (like published_at), then it defaults to the current date. It also accepts a wide variety of formatting options. Here, we opt for the four-digit year. The benefit of using the helper, as opposed to just saying “My Site © 2023” is that it’ll always be current — you won’t have to manually update it every year. One less thing to worry about 😅

Next, we use the navigation helper to output the secondary navigation items, as set in Ghost Admin. While these links can be whatever you want, we see users often opt to use the secondary navigation area for things like their privacy policy, terms and conditions, contact form, and similar pages. The actual markup Ghost uses to output the navigation is listed in the docs but can also be fully customized.

The final element is a “Powered by Ghost” link, set to open in a new tab. There’s nothing special here. It’s just straight HTML.

Then, a few closing tags bring us to the end of the default.hbs file. You made it 🥳

Summary

You now have a comprehensive overview of Ghost’s default template. This base layer is a key building block for any and all theme development. Since it provides the underlying structure for every page, it’s the perfect place for any element that shows up everywhere like meta tags, scripts, stylesheets, navigation bars, and footers. The real reason to use it, though, is its practicality: default.hbs saves you time, minimizes errors, and makes you an efficient theme-creation machine.

And now that you’ve completed this tutorial and have a better understanding of how Ghost themes work, you’re well on your way to becoming that machine. So don’t let the learning stop here 🤖

Explore other tutorials to learn more tips and tricks, sign up for the Build with Ghost newsletter for a monthly dose of inspiration, or connect with a vibrant community of Ghost enthusiasts over on the Forum.

]]>
<![CDATA[🧠 Build with Ghost: Do you know these essential concepts?]]>https://ghost.org/tutorials/3-things/645d0381f995f00001a90cdaTue, 06 Jun 2023 10:34:34 GMT

Welcome to Issue #6! Some highlights from this issue by the numbers:

  • Our new tutorial lays out 3 essential concepts to know when building a Ghost theme
  • Ghost is on its way to supporting 33 different languages
  • 25 examples of jaw-dropping typography
  • Get to know the systems powering our daily lives from the 1 and only Architecture Notes
🏋️

Pro tip: Hopefully, you're already using snippets, Ghost's feature that allows you to reuse content across posts and pages. But did you know you can also turn an entire post or email into a snippet? For example, if you send out a weekly newsletter that always follows the same format, you can create a snippet from the entirety of an existing email to jump-start a new issue. (Additionally, use our new duplicate post feature to achieve this functionality. A bonus here is that tags and authors are retained across copies.)

Essential concepts to know when building a Ghost theme

Our newest tutorial covers three essential concepts to know when building a Ghost theme. Here are the concepts:

  1. What a templating language is and the basics of Ghost's templating language, Handlebars
  2. The three required files — index.hbs, post.hbs, and package.json — that contribute to a theme's structure
  3. How contexts connect your site's data with the right template

These concepts will give you the foundational knowledge you need to build a killer custom theme 💪

Essential concepts to know when building a Ghost theme
In this tutorial, learn to wield the powerful Handlebars templating language, unravel the core structure of a theme, and understand the crucial role contexts play in theme development.
🧠 Build with Ghost: Do you know these essential concepts?

Just shipped 🚢

Ideas and tools 🛠️

On the beautiful site, Architecture Notes, Mahdi Yusuf publishes content about the systems we use every day. As a Senior Staff Engineer at 1Password, former CTO at Gyroscope, and technical researcher, Mahdi is no stranger to system design and software architecture. Recent posts discuss technical debt and database sharding, and there's even a capture-the-flag event that challenges participants to solve a series of encryption-related puzzles.

Architecture Notes — System Design & Software Architectures Explained
Engineering architecture notes about system design and software architectures explained by engineers for engineers.
🧠 Build with Ghost: Do you know these essential concepts?

If you were looking for somewhere to start with Mahdi's content, he recommends two posts in particular: Redis Explainedwhich offers an awesome introduction to the open-source key-value database server — and Relational Databases Explained, which includes this awesome infographic:

🧠 Build with Ghost: Do you know these essential concepts?

Of all the possible systems and platforms out there, we asked Mahdi why he uses Ghost. He says that he's followed Ghost since day one (10 years ago), and when version five dropped, it became his choice for a publication and newsletter service all in one. Also, he says, "The community is incredible and the built in subscription system is a no brainer as my platform of choice."

When working with Ghost, he advises keeping the setup simple, posting consistently, and leveraging snippets (see the tip above) for reusable elements. We agree with all of this and recommend heading over to Architecture Notes to finally learn what database sharding is — turns out it's more than just a funny word 😜


Many sites featured in the Build with Ghost newsletter are discovered through our creator network, Ghost Explore. It’s a way for creators and readers alike to discover their favorite new publications. Anyone running a Ghost site can add themselves to Explore to be featured throughout the wider Ghost ecosystem. If you’d like to be featured in this newsletter, add your site to Explore and reply to this email.

🧠 Build with Ghost: Do you know these essential concepts?

Thanks for building with us.

Have an idea for a Ghost tutorial? Reply to this email and let us know ❤️

Looking for other creators and developers working with Ghost? Join the official Ghost Forum, where we talk about all things Ghost!

]]>
<![CDATA[Essential concepts to know when building a Ghost theme]]>https://ghost.org/tutorials/essential-concepts/6467cfc05e95620001de859fWed, 24 May 2023 18:58:59 GMTEssential concepts to know when building a Ghost theme

Ever get to the end of a project and thought, “I wish I knew this before I started.” Like every time, right? Well, this tutorial will give you that knowledge and insight before you start building a Ghost theme. Specifically, we’ll cover three areas:

  • Ghost’s templating language Handlebars (and what’s a templating language anyways?)
  • The structure of a Ghost theme and the three files essential to it
  • Accessing the right data at the right time with contexts

By learning these three essential concepts, not only will you gain a fantastic overview of how a Ghost theme works, but you'll also be extremely well prepared to start building your very own custom theme.

What’s a templating language anyways?

Let’s first get clear on what a templating language is, and then we can get into Ghost’s specific templating language, Handlebars.

Like a mold for a cake, a template is a mold for your site’s data. You use one template for outputting the homepage and another for a post page. At its core, then, creating a Ghost theme is the creation of a set of templates, and the way you write the templates is with Handlebars, Ghost’s templating language. Handlebars files are easy to spot: they have the extension .hbs.

0:00
/

The basics of Handlebars

When creating a Handlebars template, you’ll write most of it in standard HTML. It’s the familiar markup under the hood of pretty much every website ever made. Handlebars comes into the picture wherever you need to render dynamic data in your theme. Dynamic data refers to the values you enter in Ghost Admin and the editor, everything from your site’s title to navigation items to the content of a post. Here’s a simple example of how to display your site’s title using HTML and Handlebars.

<h1>{{ @site.title }}</h1>

Let’s explain each part of this code.

  • <h1></h1> are the HTML open and closing tags for a top-level heading. Nothing special here.
  • {{ and }} are the opening and closing tags for Handlebars. They tell Ghost that work needs to be done with the data inside. The tags are also the reason the language is called “Handlebars” — because they look like the mustache of the same name. And, just like it’d look pretty strange to have only one side of the mustache {{, you always need to close your Handlebars code with }}.
  • @site.title is a special data object, available when writing a Ghost theme. It renders the template with the actual site title. “Render” is a fancy way of saying replace. If your site is called Delicious Cakes, then Ghost will render the template <h1>{{@site.title}}</h1> with <h1>Delicious Cakes</h1>. The beauty of this workflow is that if you ever change your site’s title, maybe to Delicious Cakes and Cookies, the new title will be rendered automatically, without having to update the template.

Before discussing all the exciting things Handlebars can do, let’s take a step back and summarize what we’ve covered so far.

  1. A Ghost theme is primarily made up of Handlebars templates.
  2. These files are rendered by Ghost with data from your site into HTML that's understandable by the browser.
  3. Your audience knows none of this and just loves your beautiful site.

Here’s another take on the earlier visualization, with a bit more detail based on what you’ve learned.

0:00
/

Happy little helpers

Ghost provides several helpers to — well — help you create your theme. These helpers output data, control flow, translate, paginate, get additional data, and more. To get a sense of everything that’s possible when building a Ghost theme, it’s worthwhile to check out the full list of helpers:

Ghost Handlebars Themes - Functional Helpers
Discover how to work with the full range of functional helpers in a custom Ghost theme. Learn more about Handlebars themes!
Essential concepts to know when building a Ghost theme

Let’s look at an example of a helper in action. Suppose you’re on your post page. Sometimes you add a feature image but sometimes not. The {{#if}} helper lets you account for each case.

{{#if feature_image}}
  Code to display if there is a feature image
{{/if}}

Use the helper by entering #if followed by the value to be checked. If the value is true or exists, then all the markup between the Handlebars tags ({{#if}}{{/if}}) will be rendered. If the value is false or doesn’t exist, then it won't. The idea here is to account for each possibility in the theme, so the content looks good, no matter the situation. Check out a real-world example from Casper.

The if helper is one of many Ghost provides. Using these helpers enables you to build resilient themes and explore creative possibilities. In the next section, we’ll see how these helpers come together in template files that structure a theme.

The structure of a Ghost theme

0:00
/

A real-world Ghost theme will be made up of several different kinds of files, but only three are required for it to work:

  • index.hbs
  • post.hbs
  • package.json

It’s possible to zip these files up, upload the resulting file to Ghost, and have a fully functioning Ghost theme. Therefore, learning what these three files do serves as an essential introduction to the structure of a Ghost theme. Let’s summarize the purpose of each one.

index.hbs is a theme’s front door

We’ll start with index.hbs because it serves as the entry point for your website. By default, this template file outputs your site’s homepage. Like a book’s index that points to the location of different topics, index.hbs points to the location of your posts. By modifying the index.hbs template, you control how the list of posts appears on your Ghost site.

index.hbs is also used for all pages that have a collection of posts. This includes your homepage and subsequent pages, as well as tag and author pages. Ghost is flexible, so it’s also possible (and common) to create unique templates for each of these pages.

Here’s the index.hbs template for Casper.

post.hbs is where the content is

The second required file is post.hbs. It renders all individual posts and pages. By modifying this template, you change how post content appears on your site.

The key difference between a post and a page is that a post always belongs to a collection but a page doesn’t. This means that a post will be included in your homepage’s list of posts but a page won’t. In typical usage, posts include your articles, whereas pages are used for content like about and contact pages.

Here’s the post.hbs template for Casper.

package.json is the brains of the operation

The final required file is package.json. Those familiar with Node.js will recognize this JSON file as providing metadata relevant to the project, that is, the Ghost theme. This metadata includes the theme’s name, version, scripts, dependencies, license, and more.

Ghost also uses package.json to configure aspects of the publication. The three most common properties configured include:

  • Posts per page: This property tells Ghost how many posts to include in a collection. For example, setting this to 15 means that 15 posts will show up on the homepage.
  • Image sizes: Ghost can automatically optimize your theme images, and this property instructs Ghost which image sizes to generate.
  • Custom settings: These extend your theme’s functionality by allowing users to configure different options from Ghost Admin. In Casper, for example, one custom setting allows users to choose whether the body font is serif or sans serif.

These three files form the structure of your theme. The first two are built, as we saw earlier, with HTML and Handlebars. Context is the glue that holds everything together and what we’ll look at next.

Essential concepts to know when building a Ghost theme

Make your inbox fire

Build a better internet with early access to features, tools, and tutorials.

No spam. Once a month. Unsubscribe any time.

Getting the right data to the right template with context

The final concept to understand when working with a Ghost theme is context. Every page in a Ghost theme belongs to a context, which determines the template used and the data available.

This explanation may seem a little abstract, so let’s consider a real-world example. The Delicious Cakes publication from above has an article on chocolate cake (and not just any chocolate cake but the most delicious chocolate cake you’ve ever had). A single post like this belongs to the post context. That means that it’ll be rendered by the post.hbs template and have all the post data available to it, like its title, author, tags, and more.

Here’s an overview of all available pages, contexts, and templates in Ghost. Two things to note about the table:

  • The homepage has more than one index. Likewise, whenever you’re not on the first page of a collection, the paged context is included. On /page/2/ of your site, the context will be paged and index.
  • When a specific template isn’t available (like author.hbs), Ghost will fall back to a template that is guaranteed to be present.
Page Context(s) Template Fallback template Data
Homepage home, index home.hbs index.hbs Collection of posts
Post post post.hbs - Post data
Page page page.hbs post.hbs Page data
Author author author.hbs index.hbs Author data and post collection
Tag tag tag.hbs index.hbs Tag data and post collection

To reiterate, contexts are important to understand because they play a big part in building a Ghost theme. In addition to determining the available data and what template to render, contexts also interact with Handlebars helpers.

For more on contexts and to see what data is available in each one, check out the official docs.

Summary

In this tutorial, you learned three concepts essential to understanding the meaning of life, or, rather, the foundations of a Ghost theme.

  • Handlebars is Ghost's templating language and is used to create templates.
  • Three required files — index.hbs, post.hbs, and package.json — contribute to a theme's structure.
  • Contexts connect your site's data with the right template.

If all of this seems a bit theoretical, like learning to swim by reading a book, a great next step is to jump right in and try building a custom theme or making some simple modifications to an existing one. See our tutorial on installing Ghost locally to help you get started. Our tutorials and docs are also fantastic resources, and our Forum is a welcoming place to come and ask questions.

]]>
<![CDATA[🏗️ Build with Ghost: First steps for creating a custom theme]]>https://ghost.org/tutorials/build-with-ghost-the-first-for-creating-a-custom-theme/64496c3f389337003d128cdcFri, 05 May 2023 00:09:44 GMT

Issue #5 is alive 🤖 Here are the beep boops for this issue:

  • Our new tutorials on installing Node and Ghost locally set you up perfectly to start building a custom theme
  • Up your design game by checking out the graphic design trends for 2023
  • Find out some of the awesome tools for building cool stuff with Data Scientist and YouTuber, Liz Rowe, in our featured site of the month
🏋️
Pro tip: Get swole with bulk actions (recently released). To make bulk actions, select the posts you'd like to edit by holding shift or cmd and clicking to select which posts you'd like to update, then right-click to open the bulk edit menu. Learn more.

Build a strong foundation with these two new tutorials

🏗️ Build with Ghost: First steps for creating a custom theme

It's Node all the way down

Developed in 2009, Node.js is a runtime that allows JavaScript to run independently of the browser. Ghost runs on Node and almost all modern web development uses Node in some way.

That's why, whether you're planning to create a custom Ghost theme or a killer app, Node is essential.*

In our new tutorial, we show you how to install Node on macOS, Windows, and Linux. Once installed, it's a cinch to run Ghost locally or use any of the other 3 million+ packages available.

*Web development is notoriously fluid, and, recently, other runtimes like Deno and Bun have challenged Node's default status. While these other runtimes are important to be aware of and offer significant improvements, Node isn't going anywhere anytime soon.

Install Ghost locally

After installing Node, you'll likely want to do something with it. It'd be like getting new trainers and not going for a run. We've got you covered with our new tutorial on installing Ghost locally.

A local installation of Ghost is ideal for theme development because it offers you instant feedback. Local installation is also a great way to take Ghost for a test run before going live 🏃

How to install Ghost locally
Get ready to harness the power of Ghost right from your local machine! This tutorial guides you through installing Ghost CLI and Ghost, enabling real-time theme changes, idea testing, and bug-fixing.
🏗️ Build with Ghost: First steps for creating a custom theme

Just shipped 🚢

We've been busy.

Ideas and tools 🛠️

It's just Liz

🚀 It’s Just Liz | Liz Rowe
I’m Liz. I’m a Mechanical Engineer and YouTuber. I film videos about engineering in your 20’s - career tips, technical advice, and other techniques!
🏗️ Build with Ghost: First steps for creating a custom theme

If you're looking for a partner on your coding journey, we can't think of anyone more perfect than Liz Rowe, a mechanical engineer and YouTuber on Ghost (of course!). When she's — impressively — not working as a Data Science Manager at Intel, Liz offers guidance on using low-code software to get things done. And, coincidentally, she will soon be releasing her own video on using Node for beginners.

🏗️ Build with Ghost: First steps for creating a custom theme

In Liz's content, the focus on maximizing productivity carries through in her theme choice: the awesome Abi Abdaal theme by Super Themes Co. Reflecting on this choice, Liz has this advice for newcomers to Ghost:

The best advice I could give is to not get hung up on the perfect website, the perfect theme or the perfect brand colors. Make a "good enough" website on Ghost and start showcasing your work right away.

We couldn't agree more. Too often, creators get distracted by their theme, when they should be focusing on creating content. The most beautiful site in the world isn't going to be very impressive if there are only two posts that are three years old.

That being said, Liz is still contemplating building her own custom theme in the future, and thinks it would be a "super fun project." We agree here, too, and can't help but point out a loophole: if you're a creator making content about building Ghost themes, then you can have your cake and eat it, too 😉


Many sites featured in the Build with Ghost newsletter are discovered through our creator network, Ghost Explore. It’s a way for creators and readers alike to discover their favorite new publications. Anyone running a Ghost site can add themselves to Explore to be featured throughout the wider Ghost ecosystem. If you’d like to be featured in this newsletter, add your site to Explore and reply to this email.

🏗️ Build with Ghost: First steps for creating a custom theme

Thanks for building with us.

Have an idea for a Ghost tutorial? Reply to this email and let us know ❤️

Looking for other creators and developers working with Ghost? Join the official Ghost Forum, where we talk about all things Ghost!

]]>
<![CDATA[How to install Ghost locally]]>https://ghost.org/tutorials/local-ghost/6436d48a44957a004d1e01feMon, 01 May 2023 13:46:29 GMTHow to install Ghost locally

In this tutorial, we’ll walk you through the steps of installing Ghost locally on your machine.

Running Ghost locally is essential for custom theme development because it allows you to:

⌚ Make and preview changes to your theme in real-time

🧑‍🔬 Quickly test out new ideas

🤩 Ensure your theme is free of bugs and ready for primetime

⚠️
Installing Ghost locally requires that Node be installed on your machine. See our tutorial for a guide to installing it on Mac OS, Windows, and Linux.

Install Ghost CLI

Ghost CLI (command-line interface) is a tool for installing and configuring Ghost. It assists you in installing Ghost locally. To install the tool, open a terminal and run:

npm install ghost-cli@latest -g

This command tells npm (Node Package Manager) to install the latest version of Ghost CLI. The -g flag means “globally” and ensures that you’re able to access the tool anywhere on your machine.

Confirm that Ghost CLI is installed correctly by running ghost help in the terminal. The tool will output a list of all available commands. It’s a handy way to see everything the Ghost CLI can do!

How to install Ghost locally

Make your inbox fire

Build a better internet with early access to features, tools, and tutorials.

No spam. Once a month. Unsubscribe any time.

Install Ghost locally

You’re now ready to install Ghost. In the terminal, navigate to an empty directory. The directory can have any name you want.

Run the install command:

ghost install local

This command uses the Ghost CLI tool installed in the previous step. The local argument means that you’re going to run Ghost locally, that is, on your computer and not exposed to the internet. This local installation of Ghost makes testing and development easier.

Once the installation finishes, the CLI tool will output the URL for your Ghost site. By default, it’ll be http://localhost:2368.

Open the link in your browser to go through Ghost’s onboarding flow. Access Ghost Admin at any time via http://localhost:2368/ghost.

0:00
/

That’s it. You’re done! Your local Ghost site is ready for use 🖥️

5 Ghost CLI commands to know

Ghost runs in a separate background process and remains running until you stop it or restart your computer. So you may find these commands useful for taming it:

ghost stop

Run this command from your installation directory. It will stop the currently running Ghost instance.

ghost start

Run this command from your installation directory to start your local instance of Ghost. It’s necessary to run ghost start after you restart your computer.

ghost ls

Run this command from anywhere on your machine to list your Ghost installs. It shows where you installed them, whether they’re running, and their URL. You can install multiple Ghost publications on your machine, which is helpful if you want to test out different content, debug something without messing with your current setup, or develop several themes at once.

ghost update

Run this command from your installation directory to update Ghost.

ghost help

Run this command from anywhere to show all available commands. Also, find a deep dive and full explanation of all Ghost CLI commands in the docs.

Summary

In this tutorial, you learned how to install Ghost locally. You began by installing the Ghost CLI globally. Now, you can run ghost install local in any empty directory to launch a full-fledged Ghost publication on your computer!

You’re now in the perfect place to start creating a custom Ghost theme. Jump into our developer theme documentation to learn how to get started or visit us on the official Ghost forum, where we talk about all things Ghost.

]]>
<![CDATA[Install Node on macOS, Windows, and Linux]]>https://ghost.org/tutorials/node/6282f1279514a4003d52f9ccMon, 01 May 2023 13:40:20 GMTInstall Node on macOS, Windows, and Linux

As the saying goes, "Every journey begins with a single step." In the world of web development, that first step is often Node. This tutorial explains what Node is and how to install it on your system. Once installed, you’ll be ready to run Ghost locally and begin your journey of creating a custom Ghost theme.

What’s Node?

Usually, JavaScript runs in your browser, but in 2009, Ryan Dahl had the idea to create a runtime — Node — so that JavaScript could run independently of it. Today, nearly all modern web development uses Node in some way. Ghost runs entirely on Node, and, fun fact, when Ghost first came out in 2013, it ran on Node v0.10. Not even version 1!

Node Package Manager (NPM) is included with every installation of Node. It’s a command-line tool for installing, managing, and sharing JavaScript code. For example, use NPM to install Ghost or any of these other 3 million-plus packages.

Install Node on macOS

To install Node on macOS, open up a browser and navigate to the official Node website.

Click on the LTS version on the left and download the installer.

Install Node on macOS, Windows, and Linux

Run the installer, choosing the default options.

Install Node on macOS, Windows, and Linux

After the installer completes, confirm Node is installed by opening a terminal and running node -v. The terminal will output the current version of Node that’s installed.

Install Node on macOS, Windows, and Linux

That’s all there is to it. You’re now ready to start using Node 🥳

🏋️
If you’re looking for more control over your Node installation or foresee wanting to switch Node versions, check out the instructions for using nvm in the Linux section below.

Install Node on Windows

Go to Node’s official page. Click on the LTS version on the left and download the installer.

Install Node on macOS, Windows, and Linux

Follow the installer prompts. It’s recommended to check “Yes” on the Tools for Native Modules screen to ensure you don’t run into potential compatibility issues in the future. Checking this box runs an additional installation script.

Install Node on macOS, Windows, and Linux

After installation, confirm that Node is installed correctly by opening your terminal and running node -v. The command will output Node’s version number to the console.

Install Node on macOS, Windows, and Linux

You’re now ready to start using Node 🥳

Install Node on macOS, Windows, and Linux

Make your inbox fire

Build a better internet with early access to features, tools, and tutorials.

No spam. Once a month. Unsubscribe any time.

Install Node on WSL

Windows users have another option for installing Node: Windows Subsystem for Linux or WSL. WSL allows you to run a Linux environment on your Windows machine. Because most web development happens in Linux environments, the benefits of using WSL are that you’ll have fewer problems, an easier time following tutorials, and more tools at your disposal. The downside is that it takes a few additional steps to configure and install.

Open a terminal as an administrator by right-clicking on the application and choosing “Run as administrator.”

Install Node on macOS, Windows, and Linux

In the terminal, run:

wsl --install

Windows will install WSL. After installation is complete, restart your machine. Open your terminal and select Ubuntu, the WSL distribution installed by default.

Install Node on macOS, Windows, and Linux

You’re now on Linux on Windows. Pretty cool! To install Node, follow the instructions in the next section.

Install Node on Linux

The best way to install Node on Linux is to use Node version manager (nvm). It’s a script that makes it easy to install up-to-date Node versions and switch between them.

Open a terminal and run:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash

Close your terminal and reopen it. Check that nvm is installed correctly by running command -v nvm. This command should output nvm.

Finally, check which version of Node Ghost currently supports. Install it with the following command:

nvm install 18

Once installation is complete, close and reopen your terminal. Check that Node is installed correctly with node -v.  If it returns the current version installed, then you’re in business and ready to start using Node 🥳

⚠️
nvm works great when using Ghost locally, but it's not recommended for production. See our FAQ for more info.

Summary

It’s hard to overstate how omnipresent Node is in the current web development ecosystem. Name a website or app and somewhere along the line, they’re probably using Node. Installing it on your system is the first step in creating an amazing app or a super sick custom Ghost theme.

Your next step is to install Ghost locally, which should be a breeze now that Node is installed 😉

How to install Ghost locally on Mac, PC or Linux
A detailed local install guide for how to install the Ghost publishing platform on your computer running Mac, PC or Linux. Ideal for Ghost theme development.
Install Node on macOS, Windows, and Linux

And we have lots more resources to help you build a custom theme:

 

]]>
<![CDATA[💻 Build with Ghost: Themes made easy]]>https://ghost.org/tutorials/themes-made-easy/64221c4fb3a3f4003d694c8fThu, 30 Mar 2023 23:15:18 GMT

Issue #4 of the Build with Ghost newsletter has sprung. Welcome back!

In this month’s issue:

  • Speed up your theme development process with the latest updates to the Starter theme.
  • A peek inside the latest features and developer tools in the Ghost ecosystem.
  • Explore the world of generative art with this week’s featured publication, Gorilla Sun.
🏋️
Pro tip: Navigate Ghost Admin more quickly with cmd/ctrl + [ and cmd/ctrl + ].
💻 Build with Ghost: Themes made easy

Building a custom theme just got easier

If you’ve been thinking about creating a custom Ghost theme, now is a great time, as we’ve just made the process a little bit easier and a whole lot more fun by updating the Starter theme.

The fundamental idea behind the Starter theme is to accelerate your theme development by taking care of the basics, offering some guidance, and providing the under-the-hood machinery. We’ve taken care of the mise en place, so you can get right to cooking the meal. Here’s an overview of everything that’s new:

🧑‍🏫 A master class in itself
Learn the syntax and structure of a theme from the theme itself. Annotations throughout the code explain what each part of the theme is doing. Paired with our VS Code extension, you can learn everything almost all you need to know without ever leaving your editor.

🔁 Live reloading
Out of the box, you can make changes to your CSS, JS, and Handlebars files and see your changes reflected on your local site in real time. Having continuous feedback while you build out your Ghost theme makes the development process much quicker and makes testing a breeze.

🚀 Modern syntax
The Starter theme makes it possible to use cutting-edge JS and CSS syntax and features. Under the hood, Rollup, Babel, and PostCSS transpile your code so it runs everywhere. Long story short, coding your theme is a lot more convenient without sacrificing compatibility.

👟 Fast everywhere
Rollup builds your assets quickly so your development flow is never interrupted. Once your theme is shipped, your visitors will benefit from fast site speeds, because your CSS and JS are optimized and minified automatically.

Extensible
The theme build process is powered by Rollup and PostCSS. This means that you can easily add any of the plugins from their rich ecosystem into your theme. Lookout Tailwind, Three.js, and Chart.js.

👻 Tuned for Ghost
All of the tools you need are included, like using gscan to test your theme’s compatibility and Ghost’s GitHub Deploy Action to automatically update your site with new versions of your theme.

GitHub - TryGhost/Starter: A development starter theme for Ghost
A development starter theme for Ghost. Contribute to TryGhost/Starter development by creating an account on GitHub.
💻 Build with Ghost: Themes made easy

Just shipped 🚢

Ideas and tools 🛠️

  • Keen to start building your custom theme? Brush up on your CSS with some excellent videos by Kevin Powell
  • Glyphy is a great resource when you’re looking for that obscure symbol  𓆱 or cͦͮr̲a̓̕z̪̍y̎ f̵̉o̷̘̼nt̸ͬ͘
  • A whole host of new features around color just dropped. Adam Argyle walks through some of the highlights in the “High Definition CSS Color Guide

Exploring the possibilities of code-based art

💻 Build with Ghost: Themes made easy

Gorilla Sun is a publication run by Ahmad Moussa featuring deep dives into creative coding and generative art. Ahmad showcases, teaches, and shares how to use interesting algorithms to create art. It seems the artist isn’t safe from learning math after all!

Having recently migrated to Ghost from a static-site generator, Ahmad shares some details about the decision to switch to Ghost and what the migration entailed:

Goodbye Jekyll
I’ve been thinking about moving away from Jekyll for a while now. Don’t get me wrong, I love the static site generator, I really do, it’s served me well for over two years, but certain aspects of my workflow have become very clunky, and overall I haven’t been able to be as efficient…
💻 Build with Ghost: Themes made easy

One of Ahmad’s most popular articles, “An Algorithm for Polygon Intersections”, details the method for determining the intersection between polygons for the purpose of generative art.

An Algorithm for Polygon Intersections
In this post we’ll work our way towards an algorithm that can compute convex polygon intersections. We’ll also a method for intersections between axis-aligned rectangles, a function that can determine the intersection of two line segments, as well as a point in polygon test.
💻 Build with Ghost: Themes made easy

Gorilla Sun’s publication is beautifully designed and graphically lush. The artworks keep you glued to the screen. Here are two of Ahmad’s faves:


Sites featured in the Build with Ghost newsletter are discovered through our creator network, Ghost Explore. It’s a way for creators and readers alike to discover their favorite new publications. Anyone running a Ghost site can add themselves to Explore to be featured throughout the wider Ghost ecosystem. If you’d like to be featured in this newsletter, add your site to Explore and reply to this email.

💻 Build with Ghost: Themes made easy

Thanks for building with us

Have an idea for a Ghost tutorial? Reply to this email and let us know ❤️

Looking for other creators and developers working with Ghost? Join the official Ghost Forum, where we talk about all things Ghost!

]]>
<![CDATA[📖 4 ways to build a read-next section in Ghost]]>https://ghost.org/tutorials/how-to-build-a-read-more-section/63f7b340faea3b004de71c3aTue, 07 Mar 2023 08:00:35 GMT

Welcome to issue #3 of the Build with Ghost newsletter! Your monthly roundup of the latest news, tips, and tricks for creators and coders who are interested in making Ghost their own.

🏋️
Power-user tip: Use ⌘ + p/ctrl + p while in the editor to preview your post. (Hit esc to exit.)

While all good things must come to an end, they also all need to have a beginning. That's the idea behind a read-next section: keep your readers engaged by suggesting their next favorite read.

In our latest tutorial, learn four ways to build a read-next section that suggests:

  1. The latest posts
  2. The latest posts by the same author
  3. Posts related by tag
  4. Posts based on member status

By the end of the tutorial, you'll know how to build each of these read-next sections or create your own version.

How to create a read-more section in your Ghost theme
In this tutorial, learn to build a read-more section for your Ghost theme so that your audience always knows what they should be reading next.
📖 4 ways to build a read-next section in Ghost

What's new in Ghost

  • Email is technology from 1971 — wildly useful, but with some persistent quirks. Ghost now helps your subscribers troubleshoot email issues without needing to contact support, by providing helpful dynamic tips directly in their accounts. See the changelog for more details.
  • Debugging your code can be frustrating, to say the least. To give you a head start, we published a new tutorial explaining how to debug your Ghost theme, complete with a video to make it even easier to learn the material 📼

From the web

The State of CSS 2022: Features
The 2022 edition of the annual survey about the latest trends in the CSS ecosystem.
📖 4 ways to build a read-next section in Ghost

The State of CSS is an annual survey designed to "identify upcoming trends in the web development ecosystem in order to help developers make technological choices." Apart from its main goal, the site's also a beautiful example of data visualization and a convenient place to learn about new features in CSS.

From explore

Have you seen our creator network, Ghost Explore? It’s a way for creators and readers alike to discover their favorite new publications. Anyone running a Ghost site can add themselves to Explore to be featured prominently on Ghost.org and throughout the wider Ghost ecosystem.

Explore — Browse publications & featured writers
Discover new publishers who are writing about Art & Culture, Business, Education, Technology and more on Ghost Explore. Submit your own Ghost site here 👉
📖 4 ways to build a read-next section in Ghost

One publication that always keeps us reading is Maker Stations. A genius concept with a gorgeous theme and content that is consistently spot-on. Anyone who spends their working hours at a desk is bound to find something to like 👇

📖 4 ways to build a read-next section in Ghost

Every Sunday, Maker Stations shares an "in-depth workspace tour from a random corner of the world." That is, they interview a maker somewhere in the world and show you what their desk setup looks like. A typical interview includes a maker's bio, specs on their equipment, preferred apps and tools, and tips and tricks for other makers. Recently, Mathieu B., a French graphic designer, shared their maker station that featured a gorgeous illustration and a small crab holding a digital pencil.

📖 4 ways to build a read-next section in Ghost
📖 4 ways to build a read-next section in Ghost

At the end of every Maker Stations post, two things happen. First, you'll have some new ideas about how you want to change up your own home office. And, second, you'll want to read another post. Maker Stations have got you covered:

📖 4 ways to build a read-next section in Ghost

Thanks for building with us.

Have an idea for a Ghost tutorial? Reply to this email and let us know ❤️

Looking for other creators and developers working with Ghost? Join the official Ghost Forum, where we talk about all things Ghost!

]]>