Ghost

Modern blog and publishing platform. CMS specialized in writing experience and performance.

CMSBlogNode.jsJavaScriptHeadlessMembershipNewsletter
License
MIT
Language
JavaScript (Node.js)
Pricing
オープンソース版無料
Official Site
Visit Official Site

CMS

Ghost

Overview

Ghost is a modern blog and publishing platform specialized in writing experience and performance.

Details

Ghost is an open-source blogging platform designed for professional publishers and writers. Developed in 2013 as an alternative to WordPress, it features a minimal interface focused on writing and fast performance. Built with Node.js, it also operates as a fully headless CMS.

Ghost's main feature is its "writing-first" design philosophy. It offers an intuitive WYSIWYG editor with Markdown support, card-based content blocks, real-time preview, and many features that maximize writer productivity. Membership functionality comes standard, allowing integrated management of paid subscriptions, free member registration, and email distribution.

Technically, it provides RESTful Content API and Admin API, allowing use with any frontend framework. The theme system is Handlebars-based, with SEO optimization, AMP support, and automatic generation of structured data (JSON-LD). The latest 2024 version adds direct upload of video and audio files, multi-language support, and content discovery features through Ghost Explorer.

Pros and Cons

Pros

  • Excellent writing experience: Refined editor with Markdown support
  • High performance: Lightweight and fast with Node.js
  • Integrated membership: Standard paid subscription and newsletter features
  • SEO optimization: Automatic generation of structured data and metadata
  • Headless ready: API-first for flexible implementation
  • 0% fees: No fees for monetization features
  • Open source: Completely free and customizable

Cons

  • Blog-focused: Limited use cases as not a general-purpose CMS
  • Limited plugins: Fewer extensions compared to WordPress
  • Technical hurdle: Self-hosting requires technical knowledge
  • Japanese support: Official documentation is English-centric
  • Customization limits: Theme customization requires Handlebars knowledge

Key Links

Usage Examples

Ghost Installation and Initial Setup

# Install Ghost-CLI
sudo npm install ghost-cli@latest -g

# Create Ghost project directory
sudo mkdir -p /var/www/ghost
sudo chown $USER:$USER /var/www/ghost
sudo chmod 775 /var/www/ghost
cd /var/www/ghost

# Install Ghost (production)
ghost install

# For local development
ghost install local

# Start development server
ghost start

Fetching Posts with Content API

// Initialize Ghost Content API client
const GhostContentAPI = require('@tryghost/content-api');

const api = new GhostContentAPI({
  url: 'https://your-blog.ghost.io',
  key: 'your-content-api-key',
  version: 'v5.0'
});

// Get latest posts
async function getLatestPosts() {
  try {
    const posts = await api.posts
      .browse({
        limit: 10,
        include: 'tags,authors',
        fields: 'id,title,slug,feature_image,published_at,excerpt'
      });
    
    posts.forEach(post => {
      console.log(`${post.title} - ${post.url}`);
    });
  } catch (err) {
    console.error(err);
  }
}

// Get post by slug
async function getPostBySlug(slug) {
  try {
    const post = await api.posts
      .read({slug}, {include: 'tags,authors'});
    
    return post;
  } catch (err) {
    console.error(err);
  }
}

Membership and Newsletter Setup

// Member management with Admin API
const GhostAdminAPI = require('@tryghost/admin-api');

const admin = new GhostAdminAPI({
  url: 'https://your-blog.ghost.io',
  key: 'your-admin-api-key',
  version: 'v5.0'
});

// Add new member
async function addMember(email, name) {
  try {
    const member = await admin.members.add({
      email: email,
      name: name,
      subscribed: true,
      labels: ['newsletter']
    });
    
    console.log(`Member added: ${member.email}`);
  } catch (err) {
    console.error('Member add error:', err);
  }
}

// Newsletter configuration
const newsletterConfig = {
  title: 'Weekly Newsletter',
  sender_name: 'Your Blog',
  sender_email: '[email protected]',
  sender_reply_to: '[email protected]',
  status: 'active',
  visibility: 'members',
  subscribe_on_signup: true,
  sort_order: 0,
  header_image: null,
  show_header_icon: true,
  show_header_title: true,
  title_font_category: 'serif',
  title_alignment: 'center'
};

Creating Custom Themes

{{!-- index.hbs - Homepage template --}}
{{!< default}}

<div class="site-content">
  <header class="site-header">
    <h1>{{@site.title}}</h1>
    <p>{{@site.description}}</p>
  </header>

  <main class="post-feed">
    {{#foreach posts}}
      <article class="post-card">
        {{#if feature_image}}
          <a class="post-card-image-link" href="{{url}}">
            <img class="post-card-image" src="{{feature_image}}" alt="{{title}}" />
          </a>
        {{/if}}
        
        <div class="post-card-content">
          <a class="post-card-content-link" href="{{url}}">
            <header class="post-card-header">
              {{#if primary_tag}}
                <span class="post-card-tags">{{primary_tag.name}}</span>
              {{/if}}
              <h2 class="post-card-title">{{title}}</h2>
            </header>
            
            <section class="post-card-excerpt">
              <p>{{excerpt words="33"}}</p>
            </section>
          </a>
          
          <footer class="post-card-meta">
            <span class="post-card-author">{{authors}}</span>
            <span class="post-card-date">{{date published_at format="DD MMM YYYY"}}</span>
          </footer>
        </div>
      </article>
    {{/foreach}}
  </main>

  {{pagination}}
</div>

Next.js Integration

// pages/index.js - Building Ghost blog with Next.js
import GhostContentAPI from '@tryghost/content-api';

const api = new GhostContentAPI({
  url: process.env.GHOST_API_URL,
  key: process.env.GHOST_CONTENT_API_KEY,
  version: 'v5.0'
});

export async function getStaticProps() {
  const posts = await api.posts.browse({
    limit: 'all',
    include: 'tags,authors',
    fields: 'id,title,slug,feature_image,published_at,excerpt,reading_time'
  });

  return {
    props: { posts },
    revalidate: 60 // ISR regenerates every 60 seconds
  };
}

export default function Home({ posts }) {
  return (
    <div className="container">
      <h1>My Ghost Blog</h1>
      
      <div className="posts-grid">
        {posts.map(post => (
          <article key={post.id} className="post-card">
            {post.feature_image && (
              <img src={post.feature_image} alt={post.title} />
            )}
            
            <h2>
              <a href={`/posts/${post.slug}`}>{post.title}</a>
            </h2>
            
            <p>{post.excerpt}</p>
            
            <div className="post-meta">
              <time dateTime={post.published_at}>
                {new Date(post.published_at).toLocaleDateString('en-US')}
              </time>
              <span>{post.reading_time} min read</span>
            </div>
          </article>
        ))}
      </div>
    </div>
  );
}

Webhook and Zapier Integration

// Ghost Webhook configuration example
const webhookConfig = {
  webhooks: [{
    event: 'post.published',
    target_url: 'https://your-app.com/webhooks/ghost/post-published'
  }, {
    event: 'member.added',
    target_url: 'https://your-app.com/webhooks/ghost/member-added'
  }]
};

// Webhook receiving endpoint implementation
app.post('/webhooks/ghost/post-published', async (req, res) => {
  const { post } = req.body;
  
  // Process new post publication
  console.log(`New post published: ${post.current.title}`);
  
  // Auto-post to Twitter
  await postToTwitter({
    text: `New article published!\n\n${post.current.title}\n${post.current.url}`
  });
  
  // Slack notification
  await notifySlack({
    channel: '#blog-updates',
    text: `New post: ${post.current.title}`,
    url: post.current.url
  });
  
  res.status(200).json({ received: true });
});

// Zapier integration automation examples
// 1. Ghost → Zapier → Twitter
// 2. Ghost → Zapier → Email marketing tools
// 3. Ghost → Zapier → Google Sheets (analytics data collection)