Skip to content

sredevopsorg/sredevopsorg-ghost-theme

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

84 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

SREDevOps.org Ghost Theme

Ghost v6 Theme for SREDevOps.org β€” Multi-locale, Tailwind CSS v3, responsive, dark-mode first, with SVG icons, sidebar navigation, and tag-based language filtering.

License: MIT Ghost Compatibility Node Engine


🌐 Multi-Locale Architecture

This theme implements a template inheritance + tag-based routing strategy to serve distinct content per locale without requiring separate Ghost instances. This approach aligns with community workarounds discussed in the Ghost Forum.

Template Inheritance Pattern

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ routes.yaml                          β”‚
β”‚ β€’ /en/* β†’ home-en.hbs               β”‚
β”‚ β€’ /es/* β†’ home-es.hbs               β”‚
β”‚ β€’ /br/* β†’ home-br.hbs               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
          β”‚
          β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ home-*.hbs (collection template)    β”‚
β”‚ β€’ Defines collection query/filter   β”‚
β”‚ β€’ Renders post list via partials    β”‚
β”‚ β€’ {{!< default-*.hbs}} inheritance  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
          β”‚
          β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ custom-*.hbs (post/page template)   β”‚
β”‚ β€’ Locale-specific post layout       β”‚
β”‚ β€’ Localized metadata, TOC, comments β”‚
β”‚ β€’ {{!< default-*.hbs}} inheritance  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
          β”‚
          β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ default-*.hbs (layout shell)        β”‚
β”‚ β€’ <html lang="*"> attribute         β”‚
β”‚ β€’ Common <head>, assets, footer     β”‚
β”‚ β€’ {{{body}}} injection point        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ’‘ Key Insight: Each locale uses its own default-*.hbs layout shell to ensure proper lang attributes, meta tags, and localized UI strings. The {{{body}}} Handlebars placeholder in default-*.hbs receives the rendered output from custom-*.hbs or home-*.hbs.

Language Routing & Tag Filtering

Locale URL Pattern Required Tags Exclusion Tags Layout Shell
English (default) / or /en/{slug}/ en, hash-en -es, -br default.hbs
Spanish /es/{slug}/ es, hash-es -en, -br default-es.hbs
Portuguese (BR) /br/{slug}/ br, hash-br -en, -es default-br.hbs

⚠️ Critical: The default locale (English) is configured in Ghost Admin β†’ Settings β†’ General β†’ Publication language. All root-level routes (/, /page/2/, etc.) serve English content unless explicitly routed otherwise.

routes.yaml Core Configuration

collections:
  /es/:
    template: home-es
    permalink: /es/{slug}/
    filter: tag:es+tag:-en+tag:-br
    data: tag.es

  /en/:
    template: home-en
    permalink: /en/{slug}/
    filter: tag:en+tag:-es+tag:-br
    data: tag.en

  /br/:
    template: home-br
    permalink: /br/{slug}/
    filter: tag:br+tag:-es+tag:-en
    data: tag.br

# Fallback: English as default locale (configured in Ghost Admin)
taxonomies:
  tag: /tag/{slug}/
  author: /author/{slug}/

βœ… Why this works: Ghost's filter syntax supports boolean logic (+ for AND, - for NOT), enabling precise content segregation per locale while maintaining a single content database. The template directive ensures each collection uses its locale-specific layout chain.


πŸ“‹ Table of Contents


πŸ”§ Prerequisites

Dependency Version Purpose
Node.js >=22 Runtime for build tooling
Yarn >=1.22 Package management (preferred over npm)
Ghost >=6.0 Local development server
Docker (optional) Latest Run Ghost via official container

🐳 Ghost Local Setup: Follow the official Docker guide for a reproducible dev environment.


πŸš€ Installation

1. Clone & Install

# Clone the repository
git clone https://github.com/sredevopsorg/sredevopsorg-ghost-theme.git
cd sredevopsorg-ghost-theme

# Install dependencies (Yarn required)
yarn install

2. Configure Ghost

  1. Start your local Ghost instance:

    # If using Docker Compose (recommended)
    docker compose up -d
    
    # Or via Ghost-CLI
    ghost start
  2. Upload routes.yaml to Ghost Admin β†’ Settings β†’ Routing

  3. Upload the theme:

    • Via Admin: Settings β†’ Design β†’ Upload theme

    • Or symlink for development:

      ln -s /path/to/sredevopsorg-ghost-theme \
        /path/to/ghost/content/themes/sredevopsorg-ghost-theme
  4. Critical: Set your default locale in Ghost Admin β†’ Settings β†’ General β†’ Publication language (e.g., en for English). This determines which templates serve root-level routes.

  5. Activate the theme in Ghost Admin β†’ Design

3. Start Development Server

yarn dev

This triggers:

  • Tailwind CSS compilation with @tailwindcss/forms and @tailwindcss/typography
  • Asset bundling via Gulp
  • LiveReload for template/CSS changes

πŸ” Hot reload is enabled for .hbs, .css, and .js files. Browser refreshes automatically on save.


✍️ Locale Content Authoring

Tagging Posts for Language Filtering

When creating content in Ghost Admin or via Markdown import:

---
title: "My Post Title"
slug: "my-post-slug"
tags:
  - en          # Primary language slug (required)
  - hash-en     # Required for filter consistency
  - Kubernetes  # Topic tags
  - SRE
---

⚠️ Critical: Omitting either en/es/br or its hash-* counterpart will cause the post to not appear in locale-specific collections due to the filter logic in routes.yaml.

Template Resolution Flow

graph LR
    A[Request: /es/my-post/] --> B[routes.yaml filter]
    B --> C{tag:es AND NOT en/br?}
    C -->|Yes| D[home-es.hbs]
    D --> E[Inherits default-es.hbs]
    E --> F[Render html lang='es']
    F --> G[Inject body from custom-es.hbs]
Loading

Creating Locale-Specific Templates

  1. Copy the base template:

    cp default.hbs default-es.hbs
    cp custom.hbs custom-es.hbs
    cp home.hbs home-es.hbs
  2. Update the layout shell (default-es.hbs):

    <!DOCTYPE html>
    <html lang="es"> {{!-- Critical for SEO/accessibility --}}
    <head>
      <meta charset="utf-8">
      <title>{{meta_title}}</title>
      {{!-- Spanish-specific OG tags --}}
      <meta property="og:locale" content="es_CL">
      {{ghost_head}}
    </head>
    <body class="{{body_class}}">
      {{>"components/nav-es"}} {{!-- Optional: localized nav --}}
      {{{body}}} {{!-- Injects custom-es.hbs content --}}
      {{>"components/footer"}}
    </body>
    </html>
  3. Customize content templates (custom-es.hbs):

    • Localize UI strings ("Autor", "Publicado", "Índice")
    • Adjust date formats ({{date published_at format="DD MMM YYYY"}})
    • Conditionally render locale-specific components

πŸ—οΈ Template Architecture Reference

File Role Inheritance Locale Scope
default.hbs Base HTML shell for English None (root) English (default)
default-es.hbs Base HTML shell for Spanish None (root) Spanish
default-br.hbs Base HTML shell for Portuguese None (root) Portuguese (BR)
custom.hbs Post/page content layout {{!< default}} English
custom-es.hbs Post/page content layout {{!< default-es}} Spanish
home.hbs Collection/listing template {{!< default}} English
home-es.hbs Collection/listing template {{!< default-es}} Spanish
post-card-es.hbs Post preview partial Standalone Spanish

πŸ”„ Inheritance Syntax: {{!< filename}} at the top of a template tells Ghost: "Render this file's content inside the {{{body}}} placeholder of filename".


βš™οΈ Theme Configuration

Customize behavior via Ghost Admin β†’ Settings β†’ Theme:

Option Type Default Description
background_color Color #0f172a Base background for dark theme
lazy_images Boolean false Enable native lazy-loading on homepage
share_buttons Boolean true Show social share UI on posts
show_langs Boolean false Display language switcher in sidebar
show_sso Boolean false Show SSO login option in sidebar

Image Size Presets

Configured in package.json β†’ config.image_sizes:

"image_sizes": {
  "xs": { "width": 100 },
  "s":  { "width": 220 },
  "m":  { "width": 300 },
  "l":  { "width": 600 },
  "xl": { "width": 900 }
}

Use in templates: {{img_url feature_image size="l"}}


πŸ§ͺ Testing & Validation

Local Testing

# Build production assets
yarn build

# Validate theme against Ghost spec
yarn test:dev    # Verbose output
yarn test:ci     # Fail on warnings (for CI)

Locale-Specific Validation

# Test Spanish routing locally
curl -I http://localhost:2368/es/ | grep "lang"
# Expected: <html lang="es">

Lighthouse Audits

The theme targets:

  • βœ… Performance β‰₯ 90 (with lazy loading enabled)
  • βœ… Accessibility β‰₯ 95 (proper lang attributes per locale)
  • βœ… SEO β‰₯ 100 (with localized meta tags and hreflang)

Run via Chrome DevTools


🚒 Deployment

Option 1: Ghost Admin Upload

  1. Build assets:

    yarn build
  2. Zip the theme:

    zip -r sredevopsorg-ghost-theme.zip . \
      -x "*.git*" "node_modules/*" ".github/*"
  3. Upload via Ghost Admin β†’ Design β†’ Upload theme

Option 2: GitHub Actions (Recommended)

This repo includes a Deploy Ghost Theme Action that:

  • Builds assets on push to main
  • Deploys via Ghost Admin API
  • Supports environment-specific config (staging/prod)

Configure secrets:

  • GHOST_ADMIN_API_URL
  • GHOST_ADMIN_API_KEY

🀝 Contributing

We welcome contributions aligned with our Code of Conduct.

Development Guidelines

  • Branching: Use feature branches (feat/locale-switcher, fix/og-tags-es)
  • Commits: Follow Conventional Commits
  • PRs: Include screenshots for UI changes; update README if behavior changes
  • Testing: Run yarn test:ci before submitting

Adding a New Locale (e.g., pt for Portugal)

  1. Create layout shell:

    cp default.hbs default-pt.hbs
    # Edit: <html lang="pt">, OG locale, localized strings
  2. Create content templates:

    cp custom.hbs custom-pt.hbs
    cp home.hbs home-pt.hbs
    # Localize UI text, date formats, component partials
  3. Update routes.yaml:

    /pt/:
      template: home-pt
      permalink: /pt/{slug}/
      filter: tag:pt+tag:-en+tag:-es+tag:-br
      data: tag.pt
  4. Update documentation:

  5. Test thoroughly:

    • Verify lang="pt" in rendered HTML
    • Confirm tag filtering excludes other locales
    • Validate SEO meta tags with og:locale="pt_PT"

πŸ“œ License

  • Code: MIT License β€” use, modify, distribute freely
  • Content: CC BY 4.0 (for SREDevOps.org editorial content)
  • Third-party assets: Respect upstream licenses (Tailwind CSS: MIT, Ghost: MIT)

πŸ™ Credits


🌎 LatAm Note: This theme was built with LatAm infrastructure constraints in mind β€” minimal external dependencies, optimized asset delivery, and community-driven localization patterns. For questions about deploying in Chile/Argentina/Brazil contexts, open an issue or reach out via SREDevOps.org.

Last updated: May 2026 | Ghost v6 compatible

About

A Ghost v6 Theme made for SREDevOps.org based on Tailwind CSS with sidebar navigation and dark theme by default.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors