Platform specific output formatting skill

Adapt blog output to each platform's requirements.

by AgriciDaniel·MIT license·★ 2,219 Stars on the repo·GitHub ↗

Use now

Files of Platform specific output formatting

AgriciDaniel/main1 file
platform-guides.md
Show the full text1136 lines
platform-specific-output-formatting/platform-guides.md1136 lines · 32.9 KB
Outline
RawView on GitHub

Platform-Specific Output Formatting

Adapt blog output to each platform's requirements. Detect the platform from project structure (see SKILL.md Platform Detection table) and apply the corresponding format rules below.

Contents


Next.js / MDX

Frontmatter Format
---
title: "How Does AI Search Impact Organic Traffic in 2026?"
description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize for Google rankings and AI citations in 2026."
date: "2026-02-18"
lastUpdated: "2026-02-18"
author: "Author Name"
tags: ["ai-search", "seo", "traffic"]
coverImage: "https://cdn.pixabay.com/photo/2024/01/15/12/00/ai-search.jpg"
coverImageAlt: "Marketing dashboard showing AI search traffic metrics and citation rates"
ogImage: "https://cdn.pixabay.com/photo/2024/01/15/12/00/ai-search.jpg"
---

Supported frontmatter fields: title, description, date, lastUpdated, author, tags, coverImage, coverImageAlt, ogImage. Adapt field names to match the project's existing convention (some use image instead of coverImage).

Image Embedding
![Marketing team analyzing search traffic on a dashboard](https://cdn.pixabay.com/photo/.../image.jpg)

For projects using next/image component:

import Image from 'next/image'

<Image
  src="https://cdn.pixabay.com/photo/.../image.jpg"
  alt="Marketing team analyzing search traffic on a dashboard"
  width={1200}
  height={630}
  priority={false}
/>
next.config.ts Image Domains (Required)
// next.config.ts
const nextConfig = {
  images: {
    remotePatterns: [
      { protocol: 'https', hostname: 'cdn.pixabay.com' },
      { protocol: 'https', hostname: 'images.unsplash.com' },
      { protocol: 'https', hostname: 'images.pexels.com' },
    ],
  },
}

Without these entries, next/image will reject external image URLs at build time.

Chart / SVG Embedding (JSX-Compatible)

All SVG attributes must use camelCase in MDX files. HTML-style attributes cause compilation errors.

<figure className="chart-container" style={{margin: '2.5rem 0', textAlign: 'center', padding: '1.5rem', borderRadius: '12px'}}>
  <svg
    viewBox="0 0 560 380"
    style={{maxWidth: '100%', height: 'auto', fontFamily: "'Inter', system-ui, sans-serif"}}
    role="img"
    aria-label="Chart showing AIO organic CTR rebound from 1.3% to about 2.4%"
  >
    <title>AIO Organic CTR Rebound</title>
    <desc>Bar chart comparing the December 2025 AIO CTR floor to the February 2026 rebound</desc>
    <text x="280" y="30" textAnchor="middle" fontSize="16" fontWeight="700" fill="currentColor">
      AIO Organic CTR Rebound
    </text>
    <rect x="100" y="152" width="160" height="108" rx="6" fill="#f97316" />
    <text x="180" y="212" textAnchor="middle" fontSize="14" fontWeight="800" fill="white">
      1.3%
    </text>
    <rect x="300" y="60" width="160" height="200" rx="6" fill="#38bdf8" />
    <text x="380" y="165" textAnchor="middle" fontSize="14" fontWeight="800" fill="white">
      ~2.4%
    </text>
    <text x="280" y="372" textAnchor="middle" fontSize="10" fill="currentColor" opacity="0.35">
      Source: Seer Interactive (Apr 2026)
    </text>
  </svg>
</figure>

JSX attribute conversion reference:

HTML Attribute JSX Attribute
stroke-width strokeWidth
stroke-dasharray strokeDasharray
stroke-linecap strokeLinecap
text-anchor textAnchor
font-size fontSize
font-weight fontWeight
font-family fontFamily
class className
style="..." style={{...}}
fill-opacity fillOpacity
stop-color stopColor
clip-path clipPath
MDX Component Imports for Custom Charts
import { BarChart } from '@/components/charts/BarChart'
import { FAQSchema } from '@/components/FAQSchema'

<BarChart data={chartData} title="AIO Organic CTR Rebound" />
<FAQSchema faqs={[{ question: "...", answer: "..." }]} />

Check the project's components/ directory for available chart components before inlining SVG. Use project components when they exist.

generateStaticParams for SSG (Critical for AI Crawlers)

AI crawlers (GPTBot, ClaudeBot, PerplexityBot) cannot execute JavaScript. Pages must be statically generated or server-rendered. Never use client-only rendering for blog content.

// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = getAllPosts()
  return posts.map((post) => ({
    slug: post.slug,
  }))
}

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { slug } = await params
  const post = getPostBySlug(slug)
  return {
    title: post.title,
    description: post.description,
    openGraph: {
      title: post.title,
      description: post.description,
      images: [post.ogImage],
      type: 'article',
      publishedTime: post.date,
      modifiedTime: post.lastUpdated,
    },
  }
}
Key Configuration Notes
  • MDX files require @next/mdx or next-mdx-remote package
  • Verify mdx-components.tsx exists at project root for custom element mapping
  • Use export const metadata or generateMetadata for per-page SEO
  • JSON-LD schema should be rendered in the page component, not injected client-side
  • Sitemap: use app/sitemap.ts with MetadataRoute.Sitemap type

Astro

Frontmatter Format
---
title: "How Does AI Search Impact Organic Traffic in 2026?"
description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize."
pubDate: 2026-02-18
updatedDate: 2026-02-18
author: "Author Name"
tags: ["ai-search", "seo", "traffic"]
heroImage: "/images/ai-search-cover.jpg"
heroImageAlt: "Marketing dashboard showing AI search metrics"
---

Astro uses pubDate and updatedDate (Date objects) instead of date and lastUpdated (strings). Adapt to match the project's content schema.

Content Collections (src/content/blog/)

Astro 4+ uses type-safe content collections with Zod schema validation:

// src/content/config.ts
import { defineCollection, z } from 'astro:content'

const blog = defineCollection({
  type: 'content',
  schema: z.object({
    title: z.string(),
    description: z.string(),
    pubDate: z.coerce.date(),
    updatedDate: z.coerce.date().optional(),
    author: z.string().optional(),
    tags: z.array(z.string()).optional(),
    heroImage: z.string().optional(),
    heroImageAlt: z.string().optional(),
  }),
})

export const collections = { blog }

Place blog posts in src/content/blog/ as .md or .mdx files.

Image Embedding
![Marketing team analyzing search data](./images/search-dashboard.jpg)

Using astro:assets for optimization:

---
import { Image } from 'astro:assets'
import searchDashboard from '../assets/search-dashboard.jpg'
---
<Image src={searchDashboard} alt="Marketing team analyzing search data" />

For remote images, configure astro.config.mjs:

export default defineConfig({
  image: {
    domains: ['cdn.pixabay.com', 'images.unsplash.com', 'images.pexels.com'],
  },
})
Chart / SVG Embedding

Standard SVG works directly in .md files. For .astro component wrappers:

---
// src/components/Chart.astro
const { title, ariaLabel } = Astro.props
---
<figure class="chart-container">
  <slot />
  <figcaption>{title}</figcaption>
</figure>

Use standard HTML attributes (not camelCase) in .astro and .md files:

<svg viewBox="0 0 560 380" role="img" aria-label="AIO CTR rebound chart">
  <text x="280" y="30" text-anchor="middle" font-size="16" fill="currentColor">
    Chart Title
  </text>
</svg>
Key Configuration Notes
  • Static output by default (SSG): ideal for AI crawlers without JS execution
  • Markdown files support raw HTML/SVG natively (no unsafe config needed)
  • For MDX support: add @astrojs/mdx integration
  • Sitemap: add @astrojs/sitemap integration with site config
  • RSS: add @astrojs/rss for feed generation
  • View Transitions: built-in via <ViewTransitions /> component

Hugo

Frontmatter Format (YAML)
---
title: "How Does AI Search Impact Organic Traffic in 2026?"
description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize."
date: 2026-02-18
lastmod: 2026-02-18
author: "Author Name"
tags: ["ai-search", "seo", "traffic"]
categories: ["SEO Strategy"]
series: ["AI Search Optimization"]
images:
  - "/images/ai-search-cover.jpg"
draft: false
---
Frontmatter Format (TOML)
+++
title = "How Does AI Search Impact Organic Traffic in 2026?"
description = "AI Overview CTR gap narrowed to about 38%."
date = 2026-02-18
lastmod = 2026-02-18
author = "Author Name"
tags = ["ai-search", "seo", "traffic"]
categories = ["SEO Strategy"]
series = ["AI Search Optimization"]
images = ["/images/ai-search-cover.jpg"]
draft = false
+++

Hugo uses lastmod instead of lastUpdated. Supports both YAML (---) and TOML (+++) frontmatter delimiters.

Taxonomy Structure

Hugo supports three built-in taxonomies:

  • categories: Broad topic groupings (content pillars)
  • tags: Specific topic labels (keywords)
  • series: Multi-part content sequences

Configure in hugo.toml:

[taxonomies]
  category = "categories"
  tag = "tags"
  series = "series"
Image Embedding
![Marketing team analyzing search data](/images/search-dashboard.jpg)

Hugo processes images from static/images/ or page bundles (content/blog/post-name/images/).

Chart / SVG Embedding via Shortcodes

Create a custom shortcode for trusted, sanitized inline SVG only. Do not pass user-derived or generated text through safeHTML unless it has been sanitized with a strict SVG allowlist.

<!-- layouts/shortcodes/chart.html -->
<figure class="chart-container" style="margin: 2.5rem 0; text-align: center;">
  {{ .Inner | safeHTML }}
  {{ with .Get "caption" }}<figcaption>{{ . }}</figcaption>{{ end }}
</figure>

Usage in markdown:

{{< chart caption="Source: Seer Interactive (Apr 2026)" >}}
<svg viewBox="0 0 560 380" role="img" aria-label="AIO CTR rebound chart">
  <!-- SVG content -->
</svg>
{{< /chart >}}
Goldmark Renderer Config (Required for SVG)

Hugo's default Goldmark renderer escapes raw HTML. Enable unsafe rendering only for trusted authored SVG/HTML after sanitization:

# hugo.toml
[markup.goldmark.renderer]
  unsafe = true

Without this setting, all <svg>, <figure>, and other HTML tags in markdown files will be stripped from the output. If authors or external systems can provide markup, prefer a shortcode that sanitizes SVG and rejects scripts, event-handler attributes, foreignObject, external resources, and unsafe URLs.

Custom Archetypes
<!-- archetypes/blog.md -->
---
title: "{{ replace .Name "-" " " | title }}"
description: ""
date: {{ .Date }}
lastmod: {{ .Date }}
author: ""
tags: []
categories: []
images: []
draft: true
---

## Introduction

[Hook with statistic]

Create new posts with: hugo new blog/my-post-title.md

Key Configuration Notes
  • Posts go in content/blog/ or content/posts/ (check project convention)
  • Page bundles (content/blog/post-name/index.md) co-locate images with content
  • Use {{ .Params.lastmod }} in templates for freshness display
  • JSON-LD schema: add in layouts/partials/schema.html partial
  • Sitemap auto-generated at /sitemap.xml
  • RSS auto-generated at /index.xml

Jekyll

Frontmatter Format (YAML Required)
---
layout: post
title: "How Does AI Search Impact Organic Traffic in 2026?"
description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize."
date: 2026-02-18
last_modified_at: 2026-02-18
author: "Author Name"
categories: [seo-strategy]
tags: [ai-search, seo, traffic]
image: /assets/images/ai-search-cover.jpg
---
Naming Convention (Required)

Posts must follow: _posts/YYYY-MM-DD-title-slug.md Example: _posts/2026-02-18-ai-search-organic-traffic.md

Jekyll will not process files that do not follow this naming pattern.

Image Embedding
![Marketing team analyzing search data](/assets/images/search-dashboard.jpg)

Images live in assets/images/ or images/ depending on project convention.

Chart / SVG Embedding

Jekyll uses the kramdown renderer, which passes through raw HTML:

<figure>
  <svg viewBox="0 0 560 380" role="img" aria-label="AIO CTR rebound chart">
    <!-- SVG content with standard HTML attributes -->
  </svg>
  <figcaption>Source: Seer Interactive (Apr 2026)</figcaption>
</figure>

No special configuration needed: kramdown does not strip HTML by default.

Liquid Templates

Access page variables in layouts:

<h1>{{ page.title }}</h1>
<time datetime="{{ page.date | date_to_xmlschema }}">
  {{ page.date | date: "%B %d, %Y" }}
</time>

{% if page.last_modified_at %}
  <meta property="article:modified_time"
        content="{{ page.last_modified_at | date_to_xmlschema }}">
{% endif %}

Loop through posts:

{% for post in site.posts limit:10 %}
  <article>
    <h2><a href="{{ post.url }}">{{ post.title }}</a></h2>
    <p>{{ post.description }}</p>
  </article>
{% endfor %}
Layout Hierarchy
_layouts/
  default.html    <-- Base layout (HTML shell, head, nav, footer)
  post.html       <-- Blog post layout (extends default)
  page.html       <-- Static page layout (extends default)
Math Support via MathJax
# _config.yml
markdown: kramdown
kramdown:
  math_engine: mathjax

Usage in posts:

The formula is $$ E = mc^2 $$
Key Configuration Notes
  • _config.yml is the central configuration file
  • Collections: define custom collections beyond posts in _config.yml
  • Plugins: jekyll-seo-tag for automatic OG/Twitter meta tags
  • jekyll-sitemap for sitemap generation
  • jekyll-last-modified-at for automatic last_modified_at from git
  • Build with bundle exec jekyll build (produces _site/ directory)
  • JSON-LD: use jekyll-seo-tag or manually include in _includes/head.html

WordPress

Gutenberg Blocks (Modern)

Gutenberg uses block-based editing. Key blocks for blog content:

Block Purpose Notes
Paragraph Body text Each paragraph auto-wraps in <p>
Heading H2-H6 Set level in block toolbar
Image Photos Set alt text, caption, link in sidebar
Custom HTML SVG charts Paste raw SVG in HTML block
List Bullets/numbers For FAQ answers, step lists
Quote Blockquotes For expert quotes with attribution
Table Comparison tables For feature/pricing comparisons
Group Wrappers Group blocks for styling
Classic Editor (HTML)
<h2>How Does AI Search Impact Organic Traffic?</h2>

<p>AIO organic CTR rebounded from 1.3% in December 2025 to about 2.4%
in February 2026 (<a href="https://seerinteractive.com">Seer Interactive</a>,
April 2026). This means brands should optimize for citation, since cited pages
earn 120% more clicks per impression.</p>

<figure>
  <img src="https://cdn.pixabay.com/photo/.../image.jpg"
       alt="Marketing dashboard showing AI search traffic metrics"
       width="1200" height="630" loading="lazy">
  <figcaption>Photo via Pixabay</figcaption>
</figure>
Image Embedding

Upload via Media Library, then insert. Set these fields:

  • Alt text: Descriptive sentence with topic keywords
  • Title: Short descriptive title
  • Caption: Optional, shows below image
  • Featured Image: Set in post sidebar (used as OG image and blog listing)
Chart / SVG Embedding

Use the Custom HTML block:

<figure class="wp-block-html chart-container">
  <svg viewBox="0 0 560 380" role="img" aria-label="Chart description">
    <!-- Standard SVG with HTML attributes -->
  </svg>
</figure>
Yoast SEO / RankMath Integration
Field Where Purpose
Focus keyword SEO panel below editor Primary target keyword
SEO title SEO panel Title tag (if different from H1)
Meta description SEO panel 150-160 chars, fact-dense
Canonical URL SEO panel → Advanced Prevents duplicate content
OG image Social tab in SEO panel Social sharing preview
OG title Social tab Title for social shares
OG description Social tab Description for social shares
Custom Fields for Structured Data

Use ACF (Advanced Custom Fields) or native custom fields:

  • last_updated: for dateModified in schema
  • author_bio: for E-E-A-T author section
  • faq_items: for FAQPage entity markup when visible Q&A exists

Set via the "Featured Image" panel in the post editor sidebar. This image serves as both the blog listing thumbnail and the OG image for social sharing. Recommended size: 1200x630px.

Excerpt Field

The Excerpt field (in post sidebar) generates the meta description if Yoast/ RankMath meta description is empty. Keep it to 150-160 characters, fact-dense, with at least one statistic.

Key Configuration Notes
  • Permalink structure: Settings > Permalinks > Post name (/%postname%/)
  • REST API: wp-json/wp/v2/posts for programmatic publishing
  • Schema: Yoast/RankMath auto-generates BlogPosting schema
  • Caching: use WP Super Cache or W3 Total Cache for TTFB < 200ms
  • Security: keep WordPress, themes, and plugins updated
  • robots.txt: accessible at /robots.txt, configure via Yoast

Ghost

Content Formats

Modern Ghost stores editor content in Lexical JSON and accepts HTML input for HTML cards and Admin API publishing.

Ghost Admin API (Programmatic Publishing)
const GhostAdminAPI = require('@tryghost/admin-api')

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

api.posts.add({
  title: 'How Does AI Search Impact Organic Traffic in 2026?',
  html: '<p>AIO organic CTR rebounded from 1.3% to about 2.4%...</p>',
  status: 'draft',
  tags: [{ name: 'AI Search' }, { name: 'SEO' }],
  meta_title: 'AI Search Impact on Organic Traffic (2026 Data)',
  meta_description: 'AI Overview CTR gap narrowed to about 38%...',
  og_image: 'https://cdn.pixabay.com/photo/.../cover.jpg',
  og_title: 'AI Search Impact on Organic Traffic',
  og_description: 'New data reveals how AI search reshapes organic visibility.',
  canonical_url: 'https://your-blog.com/ai-search-organic-traffic',
  feature_image: 'https://cdn.pixabay.com/photo/.../cover.jpg',
  feature_image_alt: 'Marketing dashboard showing AI search metrics',
})
Image Embedding

In the Ghost editor, use the Image card. For HTML content:

<figure class="kg-card kg-image-card">
  <img class="kg-image"
       src="https://cdn.pixabay.com/photo/.../image.jpg"
       alt="Marketing team analyzing AI search data"
       loading="lazy">
  <figcaption>Photo via Pixabay</figcaption>
</figure>
Chart / SVG Embedding

Use the HTML card in the Ghost editor to paste raw SVG:

<figure class="kg-card kg-html-card">
  <svg viewBox="0 0 560 380" role="img" aria-label="Chart description">
    <!-- Standard SVG -->
  </svg>
</figure>
Built-in SEO Fields
Field Location Purpose
Meta title Post settings > Meta data Title tag override
Meta description Post settings > Meta data 150-160 chars
Canonical URL Post settings > Meta data Duplicate prevention
OG image Post settings > Twitter/Facebook Social preview image
OG title Post settings > Twitter/Facebook Social preview title
Feature image Post header Hero + OG fallback
Feature image alt Post header Accessibility
Excerpt Post settings > Excerpt Newsletter + listing text
Custom Theme Considerations

Ghost themes use Handlebars templates:

{{! post.hbs }}
<article class="post">
  <h1>{{title}}</h1>
  <time datetime="{{date format='YYYY-MM-DD'}}">{{date format="MMMM DD, YYYY"}}</time>
  {{#if updated_at}}
    <time datetime="{{updated_at format='YYYY-MM-DD'}}">
      Updated: {{updated_at format="MMMM DD, YYYY"}}
    </time>
  {{/if}}
  <div class="post-content">{{content}}</div>
</article>
Dynamic Routing

Configure content organization in routes.yaml:

routes:
  /about/: about

collections:
  /blog/:
    permalink: /blog/{slug}/
    filter: tag:-hash-podcast
    template: blog

taxonomies:
  tag: /tag/{slug}/
  author: /author/{slug}/
Key Configuration Notes
  • Ghost themes often output structured data automatically, but custom and headless themes must validate rendered JSON-LD in the final HTML
  • Default output is server-rendered HTML: AI crawlers can access content
  • Newsletters: Ghost has built-in email sending for subscriber lists
  • Membership: tiers and paid content built-in
  • Themes: install via Ghost Admin > Settings > Design
  • Content API: for headless CMS setups (read-only, public content)

11ty (Eleventy)

Frontmatter Format
---
title: "How Does AI Search Impact Organic Traffic in 2026?"
description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize."
date: 2026-02-18
lastUpdated: 2026-02-18
author: "Author Name"
tags:
  - ai-search
  - seo
  - posts
layout: post.njk
coverImage: "/images/ai-search-cover.jpg"
coverImageAlt: "Marketing dashboard showing AI search metrics"
---
Template Languages

11ty supports Nunjucks (.njk), Liquid (.liquid), Handlebars (.hbs), JavaScript (.11ty.js), and more. Nunjucks is the most common choice.

Data Cascade

11ty merges data from multiple sources (highest to lowest priority):

  1. File data: frontmatter in the content file
  2. Directory data: blog.json in the content directory
  3. Global data: files in _data/ directory
// blog/blog.json (applies to all files in blog/)
{
  "layout": "post.njk",
  "tags": ["posts"],
  "permalink": "/blog/{{ page.fileSlug }}/"
}
Image Embedding
![Marketing team analyzing search data](/images/search-dashboard.jpg)

For optimized images, use eleventy-img plugin:

{% image "src/images/search-dashboard.jpg", "Marketing team analyzing search data" %}
Chart / SVG Embedding

Raw HTML/SVG works directly in markdown files. 11ty passes through HTML without stripping.

<figure>
  <svg viewBox="0 0 560 380" role="img" aria-label="AIO CTR rebound chart">
    <!-- SVG content -->
  </svg>
  <figcaption>Source: Seer Interactive (Apr 2026)</figcaption>
</figure>
Computed Data for Dates and URLs
// blog/blog.11tydata.js
module.exports = {
  eleventyComputed: {
    permalink: (data) => `/blog/${data.page.fileSlug}/`,
    lastUpdatedDisplay: (data) => {
      const date = data.lastUpdated || data.page.date
      return new Date(date).toLocaleDateString('en-US', {
        year: 'numeric', month: 'long', day: 'numeric'
      })
    }
  }
}
Passthrough File Copy
// .eleventy.js
module.exports = function(eleventyConfig) {
  eleventyConfig.addPassthroughCopy("src/images")
  eleventyConfig.addPassthroughCopy("src/svg")
  eleventyConfig.addPassthroughCopy({ "src/favicon.ico": "/" })
}
Key Configuration Notes
  • Static output by default: ideal for AI crawlers
  • No build-step JS unless explicitly added (fast pages)
  • Collections: use tags in frontmatter to group content
  • Filters: add custom Nunjucks filters in .eleventy.js for date formatting
  • Pagination: built-in for tag pages and archive pages
  • JSON-LD: inject via layout template using frontmatter data
  • Sitemap: use eleventy-plugin-sitemap or generate manually

Gatsby

Frontmatter Format
---
title: "How Does AI Search Impact Organic Traffic in 2026?"
description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize."
date: "2026-02-18"
lastUpdated: "2026-02-18"
author: "Author Name"
tags: ["ai-search", "seo", "traffic"]
slug: "ai-search-organic-traffic"
featuredImage: "../images/ai-search-cover.jpg"
featuredImageAlt: "Marketing dashboard showing AI search metrics"
---
MDX Support
// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: 'gatsby-plugin-mdx',
      options: {
        extensions: ['.mdx', '.md'],
        gatsbyRemarkPlugins: [
          'gatsby-remark-images',
          'gatsby-remark-prismjs',
        ],
      },
    },
  ],
}
Image Embedding
![Marketing team analyzing search data](../images/search-dashboard.jpg)

Using gatsby-plugin-image:

import { GatsbyImage, getImage } from 'gatsby-plugin-image'

const BlogPost = ({ data }) => {
  const image = getImage(data.mdx.frontmatter.featuredImage)
  return (
    <GatsbyImage
      image={image}
      alt={data.mdx.frontmatter.featuredImageAlt}
    />
  )
}
Chart / SVG Embedding

In MDX files, use JSX-compatible SVG (same camelCase rules as Next.js):

<figure style={{margin: '2.5rem 0', textAlign: 'center'}}>
  <svg viewBox="0 0 560 380" role="img" aria-label="CTR chart">
    <text x="280" y="30" textAnchor="middle" fontSize="16" fill="currentColor">
      Chart Title
    </text>
  </svg>
</figure>
GraphQL Data Layer
query BlogPostBySlug($slug: String!) {
  mdx(frontmatter: { slug: { eq: $slug } }) {
    body
    frontmatter {
      title
      description
      date(formatString: "MMMM DD, YYYY")
      lastUpdated(formatString: "MMMM DD, YYYY")
      tags
      featuredImage {
        childImageSharp {
          gatsbyImageData(width: 1200, placeholder: BLURRED)
        }
      }
    }
  }
}
createPages API for Dynamic Routes
// gatsby-node.js
const path = require('path')
const blogPostTemplate = path.resolve('./src/templates/blog-post.tsx')

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions
  const result = await graphql(`
    query {
      allMdx {
        nodes {
          id
          frontmatter { slug }
          internal { contentFilePath }
        }
      }
    }
  `)

  result.data.allMdx.nodes.forEach((node) => {
    createPage({
      path: `/blog/${node.frontmatter.slug}`,
      component: `${blogPostTemplate}?__contentFilePath=${node.internal.contentFilePath}`,
      context: { id: node.id },
    })
  })
}
Key Configuration Notes
  • Static output at build time: AI crawlers get full HTML
  • Use gatsby-plugin-sitemap for sitemap generation
  • Use gatsby-plugin-robots-txt for robots.txt configuration
  • gatsby-plugin-react-helmet or Gatsby Head API for meta tags
  • JSON-LD: use gatsby-plugin-schema-snapshot or inline in Head component
  • Build can be slow for large sites: consider incremental builds

HTML / Static

Semantic HTML5 Structure
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>How Does AI Search Impact Organic Traffic in 2026?</title>
  <meta name="description" content="AI Overview CTR gap narrowed to about 38%. Here's how to optimize for Google rankings and AI citations in 2026.">

  <!-- Open Graph -->
  <meta property="og:type" content="article">
  <meta property="og:title" content="How Does AI Search Impact Organic Traffic in 2026?">
  <meta property="og:description" content="AI Overview CTR gap narrowed to about 38%.">
  <meta property="og:image" content="https://cdn.pixabay.com/photo/.../cover.jpg">
  <meta property="og:url" content="https://yourblog.com/ai-search-organic-traffic">
  <meta property="article:published_time" content="2026-02-18T00:00:00Z">
  <meta property="article:modified_time" content="2026-02-18T00:00:00Z">

  <!-- Twitter Card -->
  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:title" content="How Does AI Search Impact Organic Traffic in 2026?">
  <meta name="twitter:description" content="AI Overview CTR gap narrowed to about 38%.">
  <meta name="twitter:image" content="https://cdn.pixabay.com/photo/.../cover.jpg">

  <!-- JSON-LD Structured Data -->
  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    "headline": "How Does AI Search Impact Organic Traffic in 2026?",
    "description": "AI Overview CTR gap narrowed to about 38%.",
    "image": "https://cdn.pixabay.com/photo/.../cover.jpg",
    "datePublished": "2026-02-18",
    "dateModified": "2026-02-18",
    "author": {
      "@type": "Person",
      "name": "Author Name",
      "url": "https://yourblog.com/about"
    },
    "publisher": {
      "@type": "Organization",
      "name": "Blog Name",
      "logo": {
        "@type": "ImageObject",
        "url": "https://yourblog.com/logo.png"
      }
    },
    "mainEntityOfPage": {
      "@type": "WebPage",
      "@id": "https://yourblog.com/ai-search-organic-traffic"
    }
  }
  </script>
</head>
<body>
  <nav aria-label="Main navigation">
    <!-- Navigation -->
  </nav>

  <article>
    <header>
      <h1>How Does AI Search Impact Organic Traffic in 2026?</h1>
      <time datetime="2026-02-18">February 18, 2026</time>
    </header>

    <section>
      <h2>What Is the Impact of AI Overviews on Click-Through Rates?</h2>
      <p>AIO organic CTR rebounded from 1.3% in December 2025 to about 2.4%
      in February 2026 (<a href="https://seerinteractive.com">Seer Interactive</a>,
      April 2026). Cited pages now earn 120% more clicks per impression than
      uncited pages.</p>

      <figure>
        <img src="https://cdn.pixabay.com/photo/.../image.jpg"
             alt="Marketing dashboard showing AI search CTR metrics"
             width="1200" height="630" loading="lazy">
        <figcaption>Photo via Pixabay</figcaption>
      </figure>
    </section>

    <aside aria-label="Frequently Asked Questions">
      <h2>Frequently Asked Questions</h2>
      <!-- FAQ content -->
    </aside>
  </article>

  <footer>
    <!-- Footer -->
  </footer>
</body>
</html>
Image Embedding
<figure>
  <img src="https://cdn.pixabay.com/photo/.../image.jpg"
       alt="Descriptive sentence including topic keywords naturally"
       width="1200" height="630"
       loading="lazy"
       decoding="async">
  <figcaption>Photo via Pixabay</figcaption>
</figure>
Chart / SVG Embedding
<figure>
  <svg viewBox="0 0 560 380"
       style="max-width: 100%; height: auto; font-family: 'Inter', system-ui, sans-serif"
       role="img"
       aria-label="Chart showing AIO organic CTR rebound from 1.3% to about 2.4%">
    <title>AIO Organic CTR Rebound</title>
    <desc>Bar chart comparing the December 2025 AIO CTR floor to the February 2026 rebound</desc>
    <!-- SVG content with standard HTML attributes -->
  </svg>
  <figcaption>Source: Seer Interactive (Apr 2026)</figcaption>
</figure>
Inline JSON-LD Schema

Place in <head> for BlogPosting:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "Title",
  "datePublished": "2026-02-18",
  "dateModified": "2026-02-18",
  "author": { "@type": "Person", "name": "Author" }
}
</script>

Place in <head> for FAQPage only when visible Q&A exists. It is entity support for AI citation, not a Google rich result:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "What is the question?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "The visible answer text with a specific statistic and source."
      }
    }
  ]
}
</script>
Key Configuration Notes
  • No framework dependency: works with any hosting
  • AI crawlers can read static HTML without JS execution
  • Manually manage OG/Twitter meta tags in <head>
  • Use loading="lazy" and decoding="async" on images for performance
  • Schema must be in HTML source, not injected via JavaScript
  • Generate sitemap.xml manually or with a build script
  • Use <link rel="canonical" href="..."> to prevent duplicate content
  • Place CSS in <head> (inline critical CSS for fast TTFB)

Platform Selection Quick Reference

Priority Criterion Recommendation
AI crawlers JS execution required? Use SSG/SSR (Next.js, Astro, Hugo, 11ty, Gatsby)
Speed TTFB < 200ms Hugo (fastest builds), 11ty, Astro, static HTML
MDX/React Component-driven content Next.js, Gatsby
Simplicity Minimal tooling Hugo, Jekyll, 11ty, static HTML
Non-technical users Visual editor WordPress, Ghost
Headless CMS API-first Ghost (Content API), WordPress (REST API)
Universal Requirements (All Platforms)
  1. Static or server-rendered HTML: AI crawlers cannot execute JavaScript
  2. TTFB under 200ms: AI crawlers timeout at 3-5 seconds
  3. Schema in HTML source: not injected via client-side JS
  4. robots.txt allowing AI crawlers: GPTBot, ClaudeBot, PerplexityBot
  5. Sitemap at /sitemap.xml: helps all crawlers discover content
  6. OG meta tags: required for social sharing previews
  7. dateModified in schema: critical for freshness signals
1# Platform-Specific Output Formatting
2 
3Adapt blog output to each platform's requirements. Detect the platform
4from project structure (see `SKILL.md` Platform Detection table) and apply
5the corresponding format rules below.
6 
7## Contents
8 
9- [Next.js / MDX](#nextjs--mdx)
10- [Astro](#astro)
11- [Hugo](#hugo)
12- [Jekyll](#jekyll)
13- [WordPress](#wordpress)
14- [Ghost](#ghost)
15- [11ty (Eleventy)](#11ty-eleventy)
16- [Gatsby](#gatsby)
17- [HTML / Static](#html--static)
18- [Platform Selection Quick Reference](#platform-selection-quick-reference)
19 
20---
21 
22## Next.js / MDX
23 
24### Frontmatter Format
25```yaml
26---
27title: "How Does AI Search Impact Organic Traffic in 2026?"
28description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize for Google rankings and AI citations in 2026."
29date: "2026-02-18"
30lastUpdated: "2026-02-18"
31author: "Author Name"
32tags: ["ai-search", "seo", "traffic"]
33coverImage: "https://cdn.pixabay.com/photo/2024/01/15/12/00/ai-search.jpg"
34coverImageAlt: "Marketing dashboard showing AI search traffic metrics and citation rates"
35ogImage: "https://cdn.pixabay.com/photo/2024/01/15/12/00/ai-search.jpg"
36---
37```
38 
39**Supported frontmatter fields**: title, description, date, lastUpdated, author,
40tags, coverImage, coverImageAlt, ogImage. Adapt field names to match the
41project's existing convention (some use `image` instead of `coverImage`).
42 
43### Image Embedding
44```mdx
45![Marketing team analyzing search traffic on a dashboard](https://cdn.pixabay.com/photo/.../image.jpg)
46```
47 
48For projects using `next/image` component:
49```tsx
50import Image from 'next/image'
51 
52<Image
53 src="https://cdn.pixabay.com/photo/.../image.jpg"
54 alt="Marketing team analyzing search traffic on a dashboard"
55 width={1200}
56 height={630}
57 priority={false}
58/>
59```
60 
61### next.config.ts Image Domains (Required)
62```typescript
63// next.config.ts
64const nextConfig = {
65 images: {
66 remotePatterns: [
67 { protocol: 'https', hostname: 'cdn.pixabay.com' },
68 { protocol: 'https', hostname: 'images.unsplash.com' },
69 { protocol: 'https', hostname: 'images.pexels.com' },
70 ],
71 },
72}
73```
74 
75Without these entries, `next/image` will reject external image URLs at build time.
76 
77### Chart / SVG Embedding (JSX-Compatible)
78 
79All SVG attributes must use camelCase in MDX files. HTML-style attributes
80cause compilation errors.
81 
82```mdx
83<figure className="chart-container" style={{margin: '2.5rem 0', textAlign: 'center', padding: '1.5rem', borderRadius: '12px'}}>
84 <svg
85 viewBox="0 0 560 380"
86 style={{maxWidth: '100%', height: 'auto', fontFamily: "'Inter', system-ui, sans-serif"}}
87 role="img"
88 aria-label="Chart showing AIO organic CTR rebound from 1.3% to about 2.4%"
89 >
90 <title>AIO Organic CTR Rebound</title>
91 <desc>Bar chart comparing the December 2025 AIO CTR floor to the February 2026 rebound</desc>
92 <text x="280" y="30" textAnchor="middle" fontSize="16" fontWeight="700" fill="currentColor">
93 AIO Organic CTR Rebound
94 </text>
95 <rect x="100" y="152" width="160" height="108" rx="6" fill="#f97316" />
96 <text x="180" y="212" textAnchor="middle" fontSize="14" fontWeight="800" fill="white">
97 1.3%
98 </text>
99 <rect x="300" y="60" width="160" height="200" rx="6" fill="#38bdf8" />
100 <text x="380" y="165" textAnchor="middle" fontSize="14" fontWeight="800" fill="white">
101 ~2.4%
102 </text>
103 <text x="280" y="372" textAnchor="middle" fontSize="10" fill="currentColor" opacity="0.35">
104 Source: Seer Interactive (Apr 2026)
105 </text>
106 </svg>
107</figure>
108```
109 
110**JSX attribute conversion reference:**
111 
112| HTML Attribute | JSX Attribute |
113|----------------|---------------|
114| `stroke-width` | `strokeWidth` |
115| `stroke-dasharray` | `strokeDasharray` |
116| `stroke-linecap` | `strokeLinecap` |
117| `text-anchor` | `textAnchor` |
118| `font-size` | `fontSize` |
119| `font-weight` | `fontWeight` |
120| `font-family` | `fontFamily` |
121| `class` | `className` |
122| `style="..."` | `style={{...}}` |
123| `fill-opacity` | `fillOpacity` |
124| `stop-color` | `stopColor` |
125| `clip-path` | `clipPath` |
126 
127### MDX Component Imports for Custom Charts
128```mdx
129import { BarChart } from '@/components/charts/BarChart'
130import { FAQSchema } from '@/components/FAQSchema'
131 
132<BarChart data={chartData} title="AIO Organic CTR Rebound" />
133<FAQSchema faqs={[{ question: "...", answer: "..." }]} />
134```
135 
136Check the project's `components/` directory for available chart components
137before inlining SVG. Use project components when they exist.
138 
139### generateStaticParams for SSG (Critical for AI Crawlers)
140 
141AI crawlers (GPTBot, ClaudeBot, PerplexityBot) cannot execute JavaScript.
142Pages must be statically generated or server-rendered. Never use client-only
143rendering for blog content.
144 
145```typescript
146// app/blog/[slug]/page.tsx
147export async function generateStaticParams() {
148 const posts = getAllPosts()
149 return posts.map((post) => ({
150 slug: post.slug,
151 }))
152}
153 
154export async function generateMetadata({ params }: Props): Promise<Metadata> {
155 const { slug } = await params
156 const post = getPostBySlug(slug)
157 return {
158 title: post.title,
159 description: post.description,
160 openGraph: {
161 title: post.title,
162 description: post.description,
163 images: [post.ogImage],
164 type: 'article',
165 publishedTime: post.date,
166 modifiedTime: post.lastUpdated,
167 },
168 }
169}
170```
171 
172### Key Configuration Notes
173- MDX files require `@next/mdx` or `next-mdx-remote` package
174- Verify `mdx-components.tsx` exists at project root for custom element mapping
175- Use `export const metadata` or `generateMetadata` for per-page SEO
176- JSON-LD schema should be rendered in the page component, not injected client-side
177- Sitemap: use `app/sitemap.ts` with `MetadataRoute.Sitemap` type
178 
179---
180 
181## Astro
182 
183### Frontmatter Format
184```yaml
185---
186title: "How Does AI Search Impact Organic Traffic in 2026?"
187description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize."
188pubDate: 2026-02-18
189updatedDate: 2026-02-18
190author: "Author Name"
191tags: ["ai-search", "seo", "traffic"]
192heroImage: "/images/ai-search-cover.jpg"
193heroImageAlt: "Marketing dashboard showing AI search metrics"
194---
195```
196 
197Astro uses `pubDate` and `updatedDate` (Date objects) instead of `date`
198and `lastUpdated` (strings). Adapt to match the project's content schema.
199 
200### Content Collections (src/content/blog/)
201 
202Astro 4+ uses type-safe content collections with Zod schema validation:
203 
204```typescript
205// src/content/config.ts
206import { defineCollection, z } from 'astro:content'
207 
208const blog = defineCollection({
209 type: 'content',
210 schema: z.object({
211 title: z.string(),
212 description: z.string(),
213 pubDate: z.coerce.date(),
214 updatedDate: z.coerce.date().optional(),
215 author: z.string().optional(),
216 tags: z.array(z.string()).optional(),
217 heroImage: z.string().optional(),
218 heroImageAlt: z.string().optional(),
219 }),
220})
221 
222export const collections = { blog }
223```
224 
225Place blog posts in `src/content/blog/` as `.md` or `.mdx` files.
226 
227### Image Embedding
228```markdown
229![Marketing team analyzing search data](./images/search-dashboard.jpg)
230```
231 
232Using `astro:assets` for optimization:
233```astro
234---
235import { Image } from 'astro:assets'
236import searchDashboard from '../assets/search-dashboard.jpg'
237---
238<Image src={searchDashboard} alt="Marketing team analyzing search data" />
239```
240 
241For remote images, configure `astro.config.mjs`:
242```javascript
243export default defineConfig({
244 image: {
245 domains: ['cdn.pixabay.com', 'images.unsplash.com', 'images.pexels.com'],
246 },
247})
248```
249 
250### Chart / SVG Embedding
251 
252Standard SVG works directly in `.md` files. For `.astro` component wrappers:
253 
254```astro
255---
256// src/components/Chart.astro
257const { title, ariaLabel } = Astro.props
258---
259<figure class="chart-container">
260 <slot />
261 <figcaption>{title}</figcaption>
262</figure>
263```
264 
265Use standard HTML attributes (not camelCase) in `.astro` and `.md` files:
266```html
267<svg viewBox="0 0 560 380" role="img" aria-label="AIO CTR rebound chart">
268 <text x="280" y="30" text-anchor="middle" font-size="16" fill="currentColor">
269 Chart Title
270 </text>
271</svg>
272```
273 
274### Key Configuration Notes
275- Static output by default (SSG): ideal for AI crawlers without JS execution
276- Markdown files support raw HTML/SVG natively (no unsafe config needed)
277- For MDX support: add `@astrojs/mdx` integration
278- Sitemap: add `@astrojs/sitemap` integration with `site` config
279- RSS: add `@astrojs/rss` for feed generation
280- View Transitions: built-in via `<ViewTransitions />` component
281 
282---
283 
284## Hugo
285 
286### Frontmatter Format (YAML)
287```yaml
288---
289title: "How Does AI Search Impact Organic Traffic in 2026?"
290description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize."
291date: 2026-02-18
292lastmod: 2026-02-18
293author: "Author Name"
294tags: ["ai-search", "seo", "traffic"]
295categories: ["SEO Strategy"]
296series: ["AI Search Optimization"]
297images:
298 - "/images/ai-search-cover.jpg"
299draft: false
300---
301```
302 
303### Frontmatter Format (TOML)
304```toml
305+++
306title = "How Does AI Search Impact Organic Traffic in 2026?"
307description = "AI Overview CTR gap narrowed to about 38%."
308date = 2026-02-18
309lastmod = 2026-02-18
310author = "Author Name"
311tags = ["ai-search", "seo", "traffic"]
312categories = ["SEO Strategy"]
313series = ["AI Search Optimization"]
314images = ["/images/ai-search-cover.jpg"]
315draft = false
316+++
317```
318 
319Hugo uses `lastmod` instead of `lastUpdated`. Supports both YAML (`---`)
320and TOML (`+++`) frontmatter delimiters.
321 
322### Taxonomy Structure
323Hugo supports three built-in taxonomies:
324- **categories**: Broad topic groupings (content pillars)
325- **tags**: Specific topic labels (keywords)
326- **series**: Multi-part content sequences
327 
328Configure in `hugo.toml`:
329```toml
330[taxonomies]
331 category = "categories"
332 tag = "tags"
333 series = "series"
334```
335 
336### Image Embedding
337```markdown
338![Marketing team analyzing search data](/images/search-dashboard.jpg)
339```
340 
341Hugo processes images from `static/images/` or page bundles (`content/blog/post-name/images/`).
342 
343### Chart / SVG Embedding via Shortcodes
344 
345Create a custom shortcode for trusted, sanitized inline SVG only. Do not pass
346user-derived or generated text through `safeHTML` unless it has been sanitized
347with a strict SVG allowlist.
348 
349```html
350<!-- layouts/shortcodes/chart.html -->
351<figure class="chart-container" style="margin: 2.5rem 0; text-align: center;">
352 {{ .Inner | safeHTML }}
353 {{ with .Get "caption" }}<figcaption>{{ . }}</figcaption>{{ end }}
354</figure>
355```
356 
357Usage in markdown:
358```markdown
359{{< chart caption="Source: Seer Interactive (Apr 2026)" >}}
360<svg viewBox="0 0 560 380" role="img" aria-label="AIO CTR rebound chart">
361 <!-- SVG content -->
362</svg>
363{{< /chart >}}
364```
365 
366### Goldmark Renderer Config (Required for SVG)
367 
368Hugo's default Goldmark renderer escapes raw HTML. Enable unsafe rendering only
369for trusted authored SVG/HTML after sanitization:
370 
371```toml
372# hugo.toml
373[markup.goldmark.renderer]
374 unsafe = true
375```
376 
377Without this setting, all `<svg>`, `<figure>`, and other HTML tags in markdown
378files will be stripped from the output. If authors or external systems can
379provide markup, prefer a shortcode that sanitizes SVG and rejects scripts,
380event-handler attributes, foreignObject, external resources, and unsafe URLs.
381 
382### Custom Archetypes
383```markdown
384<!-- archetypes/blog.md -->
385---
386title: "{{ replace .Name "-" " " | title }}"
387description: ""
388date: {{ .Date }}
389lastmod: {{ .Date }}
390author: ""
391tags: []
392categories: []
393images: []
394draft: true
395---
396 
397## Introduction
398 
399[Hook with statistic]
400```
401 
402Create new posts with: `hugo new blog/my-post-title.md`
403 
404### Key Configuration Notes
405- Posts go in `content/blog/` or `content/posts/` (check project convention)
406- Page bundles (`content/blog/post-name/index.md`) co-locate images with content
407- Use `{{ .Params.lastmod }}` in templates for freshness display
408- JSON-LD schema: add in `layouts/partials/schema.html` partial
409- Sitemap auto-generated at `/sitemap.xml`
410- RSS auto-generated at `/index.xml`
411 
412---
413 
414## Jekyll
415 
416### Frontmatter Format (YAML Required)
417```yaml
418---
419layout: post
420title: "How Does AI Search Impact Organic Traffic in 2026?"
421description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize."
422date: 2026-02-18
423last_modified_at: 2026-02-18
424author: "Author Name"
425categories: [seo-strategy]
426tags: [ai-search, seo, traffic]
427image: /assets/images/ai-search-cover.jpg
428---
429```
430 
431### Naming Convention (Required)
432Posts must follow: `_posts/YYYY-MM-DD-title-slug.md`
433Example: `_posts/2026-02-18-ai-search-organic-traffic.md`
434 
435Jekyll will not process files that do not follow this naming pattern.
436 
437### Image Embedding
438```markdown
439![Marketing team analyzing search data](/assets/images/search-dashboard.jpg)
440```
441 
442Images live in `assets/images/` or `images/` depending on project convention.
443 
444### Chart / SVG Embedding
445 
446Jekyll uses the kramdown renderer, which passes through raw HTML:
447 
448```markdown
449<figure>
450 <svg viewBox="0 0 560 380" role="img" aria-label="AIO CTR rebound chart">
451 <!-- SVG content with standard HTML attributes -->
452 </svg>
453 <figcaption>Source: Seer Interactive (Apr 2026)</figcaption>
454</figure>
455```
456 
457No special configuration needed: kramdown does not strip HTML by default.
458 
459### Liquid Templates
460 
461Access page variables in layouts:
462```liquid
463<h1>{{ page.title }}</h1>
464<time datetime="{{ page.date | date_to_xmlschema }}">
465 {{ page.date | date: "%B %d, %Y" }}
466</time>
467 
468{% if page.last_modified_at %}
469 <meta property="article:modified_time"
470 content="{{ page.last_modified_at | date_to_xmlschema }}">
471{% endif %}
472```
473 
474Loop through posts:
475```liquid
476{% for post in site.posts limit:10 %}
477 <article>
478 <h2><a href="{{ post.url }}">{{ post.title }}</a></h2>
479 <p>{{ post.description }}</p>
480 </article>
481{% endfor %}
482```
483 
484### Layout Hierarchy
485```
486_layouts/
487 default.html <-- Base layout (HTML shell, head, nav, footer)
488 post.html <-- Blog post layout (extends default)
489 page.html <-- Static page layout (extends default)
490```
491 
492### Math Support via MathJax
493```yaml
494# _config.yml
495markdown: kramdown
496kramdown:
497 math_engine: mathjax
498```
499 
500Usage in posts:
501```markdown
502The formula is $$ E = mc^2 $$
503```
504 
505### Key Configuration Notes
506- `_config.yml` is the central configuration file
507- Collections: define custom collections beyond posts in `_config.yml`
508- Plugins: `jekyll-seo-tag` for automatic OG/Twitter meta tags
509- `jekyll-sitemap` for sitemap generation
510- `jekyll-last-modified-at` for automatic `last_modified_at` from git
511- Build with `bundle exec jekyll build` (produces `_site/` directory)
512- JSON-LD: use `jekyll-seo-tag` or manually include in `_includes/head.html`
513 
514---
515 
516## WordPress
517 
518### Gutenberg Blocks (Modern)
519 
520Gutenberg uses block-based editing. Key blocks for blog content:
521 
522| Block | Purpose | Notes |
523|-------|---------|-------|
524| Paragraph | Body text | Each paragraph auto-wraps in `<p>` |
525| Heading | H2-H6 | Set level in block toolbar |
526| Image | Photos | Set alt text, caption, link in sidebar |
527| Custom HTML | SVG charts | Paste raw SVG in HTML block |
528| List | Bullets/numbers | For FAQ answers, step lists |
529| Quote | Blockquotes | For expert quotes with attribution |
530| Table | Comparison tables | For feature/pricing comparisons |
531| Group | Wrappers | Group blocks for styling |
532 
533### Classic Editor (HTML)
534```html
535<h2>How Does AI Search Impact Organic Traffic?</h2>
536 
537<p>AIO organic CTR rebounded from 1.3% in December 2025 to about 2.4%
538in February 2026 (<a href="https://seerinteractive.com">Seer Interactive</a>,
539April 2026). This means brands should optimize for citation, since cited pages
540earn 120% more clicks per impression.</p>
541 
542<figure>
543 <img src="https://cdn.pixabay.com/photo/.../image.jpg"
544 alt="Marketing dashboard showing AI search traffic metrics"
545 width="1200" height="630" loading="lazy">
546 <figcaption>Photo via Pixabay</figcaption>
547</figure>
548```
549 
550### Image Embedding
551Upload via Media Library, then insert. Set these fields:
552- **Alt text**: Descriptive sentence with topic keywords
553- **Title**: Short descriptive title
554- **Caption**: Optional, shows below image
555- **Featured Image**: Set in post sidebar (used as OG image and blog listing)
556 
557### Chart / SVG Embedding
558Use the Custom HTML block:
559```html
560<figure class="wp-block-html chart-container">
561 <svg viewBox="0 0 560 380" role="img" aria-label="Chart description">
562 <!-- Standard SVG with HTML attributes -->
563 </svg>
564</figure>
565```
566 
567### Yoast SEO / RankMath Integration
568 
569| Field | Where | Purpose |
570|-------|-------|---------|
571| Focus keyword | SEO panel below editor | Primary target keyword |
572| SEO title | SEO panel | Title tag (if different from H1) |
573| Meta description | SEO panel | 150-160 chars, fact-dense |
574| Canonical URL | SEO panel → Advanced | Prevents duplicate content |
575| OG image | Social tab in SEO panel | Social sharing preview |
576| OG title | Social tab | Title for social shares |
577| OG description | Social tab | Description for social shares |
578 
579### Custom Fields for Structured Data
580Use ACF (Advanced Custom Fields) or native custom fields:
581- `last_updated`: for dateModified in schema
582- `author_bio`: for E-E-A-T author section
583- `faq_items`: for FAQPage entity markup when visible Q&A exists
584 
585### Featured Image
586Set via the "Featured Image" panel in the post editor sidebar. This image
587serves as both the blog listing thumbnail and the OG image for social sharing.
588Recommended size: 1200x630px.
589 
590### Excerpt Field
591The Excerpt field (in post sidebar) generates the meta description if Yoast/
592RankMath meta description is empty. Keep it to 150-160 characters, fact-dense,
593with at least one statistic.
594 
595### Key Configuration Notes
596- Permalink structure: Settings > Permalinks > Post name (`/%postname%/`)
597- REST API: `wp-json/wp/v2/posts` for programmatic publishing
598- Schema: Yoast/RankMath auto-generates BlogPosting schema
599- Caching: use WP Super Cache or W3 Total Cache for TTFB < 200ms
600- Security: keep WordPress, themes, and plugins updated
601- robots.txt: accessible at `/robots.txt`, configure via Yoast
602 
603---
604 
605## Ghost
606 
607### Content Formats
608Modern Ghost stores editor content in Lexical JSON and accepts HTML input for
609HTML cards and Admin API publishing.
610 
611### Ghost Admin API (Programmatic Publishing)
612```javascript
613const GhostAdminAPI = require('@tryghost/admin-api')
614 
615const api = new GhostAdminAPI({
616 url: 'https://your-blog.ghost.io',
617 key: 'ADMIN_API_KEY',
618 version: 'v5.0'
619})
620 
621api.posts.add({
622 title: 'How Does AI Search Impact Organic Traffic in 2026?',
623 html: '<p>AIO organic CTR rebounded from 1.3% to about 2.4%...</p>',
624 status: 'draft',
625 tags: [{ name: 'AI Search' }, { name: 'SEO' }],
626 meta_title: 'AI Search Impact on Organic Traffic (2026 Data)',
627 meta_description: 'AI Overview CTR gap narrowed to about 38%...',
628 og_image: 'https://cdn.pixabay.com/photo/.../cover.jpg',
629 og_title: 'AI Search Impact on Organic Traffic',
630 og_description: 'New data reveals how AI search reshapes organic visibility.',
631 canonical_url: 'https://your-blog.com/ai-search-organic-traffic',
632 feature_image: 'https://cdn.pixabay.com/photo/.../cover.jpg',
633 feature_image_alt: 'Marketing dashboard showing AI search metrics',
634})
635```
636 
637### Image Embedding
638In the Ghost editor, use the Image card. For HTML content:
639```html
640<figure class="kg-card kg-image-card">
641 <img class="kg-image"
642 src="https://cdn.pixabay.com/photo/.../image.jpg"
643 alt="Marketing team analyzing AI search data"
644 loading="lazy">
645 <figcaption>Photo via Pixabay</figcaption>
646</figure>
647```
648 
649### Chart / SVG Embedding
650Use the HTML card in the Ghost editor to paste raw SVG:
651```html
652<figure class="kg-card kg-html-card">
653 <svg viewBox="0 0 560 380" role="img" aria-label="Chart description">
654 <!-- Standard SVG -->
655 </svg>
656</figure>
657```
658 
659### Built-in SEO Fields
660 
661| Field | Location | Purpose |
662|-------|----------|---------|
663| Meta title | Post settings > Meta data | Title tag override |
664| Meta description | Post settings > Meta data | 150-160 chars |
665| Canonical URL | Post settings > Meta data | Duplicate prevention |
666| OG image | Post settings > Twitter/Facebook | Social preview image |
667| OG title | Post settings > Twitter/Facebook | Social preview title |
668| Feature image | Post header | Hero + OG fallback |
669| Feature image alt | Post header | Accessibility |
670| Excerpt | Post settings > Excerpt | Newsletter + listing text |
671 
672### Custom Theme Considerations
673Ghost themes use Handlebars templates:
674```handlebars
675{{! post.hbs }}
676<article class="post">
677 <h1>{{title}}</h1>
678 <time datetime="{{date format='YYYY-MM-DD'}}">{{date format="MMMM DD, YYYY"}}</time>
679 {{#if updated_at}}
680 <time datetime="{{updated_at format='YYYY-MM-DD'}}">
681 Updated: {{updated_at format="MMMM DD, YYYY"}}
682 </time>
683 {{/if}}
684 <div class="post-content">{{content}}</div>
685</article>
686```
687 
688### Dynamic Routing
689Configure content organization in `routes.yaml`:
690```yaml
691routes:
692 /about/: about
693 
694collections:
695 /blog/:
696 permalink: /blog/{slug}/
697 filter: tag:-hash-podcast
698 template: blog
699 
700taxonomies:
701 tag: /tag/{slug}/
702 author: /author/{slug}/
703```
704 
705### Key Configuration Notes
706- Ghost themes often output structured data automatically, but custom and
707 headless themes must validate rendered JSON-LD in the final HTML
708- Default output is server-rendered HTML: AI crawlers can access content
709- Newsletters: Ghost has built-in email sending for subscriber lists
710- Membership: tiers and paid content built-in
711- Themes: install via Ghost Admin > Settings > Design
712- Content API: for headless CMS setups (read-only, public content)
713 
714---
715 
716## 11ty (Eleventy)
717 
718### Frontmatter Format
719```yaml
720---
721title: "How Does AI Search Impact Organic Traffic in 2026?"
722description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize."
723date: 2026-02-18
724lastUpdated: 2026-02-18
725author: "Author Name"
726tags:
727 - ai-search
728 - seo
729 - posts
730layout: post.njk
731coverImage: "/images/ai-search-cover.jpg"
732coverImageAlt: "Marketing dashboard showing AI search metrics"
733---
734```
735 
736### Template Languages
73711ty supports Nunjucks (`.njk`), Liquid (`.liquid`), Handlebars (`.hbs`),
738JavaScript (`.11ty.js`), and more. Nunjucks is the most common choice.
739 
740### Data Cascade
74111ty merges data from multiple sources (highest to lowest priority):
7421. **File data**: frontmatter in the content file
7432. **Directory data**: `blog.json` in the content directory
7443. **Global data**: files in `_data/` directory
745 
746```json
747// blog/blog.json (applies to all files in blog/)
748{
749 "layout": "post.njk",
750 "tags": ["posts"],
751 "permalink": "/blog/{{ page.fileSlug }}/"
752}
753```
754 
755### Image Embedding
756```markdown
757![Marketing team analyzing search data](/images/search-dashboard.jpg)
758```
759 
760For optimized images, use `eleventy-img` plugin:
761```njk
762{% image "src/images/search-dashboard.jpg", "Marketing team analyzing search data" %}
763```
764 
765### Chart / SVG Embedding
766Raw HTML/SVG works directly in markdown files. 11ty passes through HTML
767without stripping.
768 
769```markdown
770<figure>
771 <svg viewBox="0 0 560 380" role="img" aria-label="AIO CTR rebound chart">
772 <!-- SVG content -->
773 </svg>
774 <figcaption>Source: Seer Interactive (Apr 2026)</figcaption>
775</figure>
776```
777 
778### Computed Data for Dates and URLs
779```javascript
780// blog/blog.11tydata.js
781module.exports = {
782 eleventyComputed: {
783 permalink: (data) => `/blog/${data.page.fileSlug}/`,
784 lastUpdatedDisplay: (data) => {
785 const date = data.lastUpdated || data.page.date
786 return new Date(date).toLocaleDateString('en-US', {
787 year: 'numeric', month: 'long', day: 'numeric'
788 })
789 }
790 }
791}
792```
793 
794### Passthrough File Copy
795```javascript
796// .eleventy.js
797module.exports = function(eleventyConfig) {
798 eleventyConfig.addPassthroughCopy("src/images")
799 eleventyConfig.addPassthroughCopy("src/svg")
800 eleventyConfig.addPassthroughCopy({ "src/favicon.ico": "/" })
801}
802```
803 
804### Key Configuration Notes
805- Static output by default: ideal for AI crawlers
806- No build-step JS unless explicitly added (fast pages)
807- Collections: use `tags` in frontmatter to group content
808- Filters: add custom Nunjucks filters in `.eleventy.js` for date formatting
809- Pagination: built-in for tag pages and archive pages
810- JSON-LD: inject via layout template using frontmatter data
811- Sitemap: use `eleventy-plugin-sitemap` or generate manually
812 
813---
814 
815## Gatsby
816 
817### Frontmatter Format
818```yaml
819---
820title: "How Does AI Search Impact Organic Traffic in 2026?"
821description: "AI Overview CTR gap narrowed to about 38%. Here's how to optimize."
822date: "2026-02-18"
823lastUpdated: "2026-02-18"
824author: "Author Name"
825tags: ["ai-search", "seo", "traffic"]
826slug: "ai-search-organic-traffic"
827featuredImage: "../images/ai-search-cover.jpg"
828featuredImageAlt: "Marketing dashboard showing AI search metrics"
829---
830```
831 
832### MDX Support
833```javascript
834// gatsby-config.js
835module.exports = {
836 plugins: [
837 {
838 resolve: 'gatsby-plugin-mdx',
839 options: {
840 extensions: ['.mdx', '.md'],
841 gatsbyRemarkPlugins: [
842 'gatsby-remark-images',
843 'gatsby-remark-prismjs',
844 ],
845 },
846 },
847 ],
848}
849```
850 
851### Image Embedding
852```mdx
853![Marketing team analyzing search data](../images/search-dashboard.jpg)
854```
855 
856Using `gatsby-plugin-image`:
857```jsx
858import { GatsbyImage, getImage } from 'gatsby-plugin-image'
859 
860const BlogPost = ({ data }) => {
861 const image = getImage(data.mdx.frontmatter.featuredImage)
862 return (
863 <GatsbyImage
864 image={image}
865 alt={data.mdx.frontmatter.featuredImageAlt}
866 />
867 )
868}
869```
870 
871### Chart / SVG Embedding
872In MDX files, use JSX-compatible SVG (same camelCase rules as Next.js):
873```mdx
874<figure style={{margin: '2.5rem 0', textAlign: 'center'}}>
875 <svg viewBox="0 0 560 380" role="img" aria-label="CTR chart">
876 <text x="280" y="30" textAnchor="middle" fontSize="16" fill="currentColor">
877 Chart Title
878 </text>
879 </svg>
880</figure>
881```
882 
883### GraphQL Data Layer
884```graphql
885query BlogPostBySlug($slug: String!) {
886 mdx(frontmatter: { slug: { eq: $slug } }) {
887 body
888 frontmatter {
889 title
890 description
891 date(formatString: "MMMM DD, YYYY")
892 lastUpdated(formatString: "MMMM DD, YYYY")
893 tags
894 featuredImage {
895 childImageSharp {
896 gatsbyImageData(width: 1200, placeholder: BLURRED)
897 }
898 }
899 }
900 }
901}
902```
903 
904### createPages API for Dynamic Routes
905```javascript
906// gatsby-node.js
907const path = require('path')
908const blogPostTemplate = path.resolve('./src/templates/blog-post.tsx')
909 
910exports.createPages = async ({ graphql, actions }) => {
911 const { createPage } = actions
912 const result = await graphql(`
913 query {
914 allMdx {
915 nodes {
916 id
917 frontmatter { slug }
918 internal { contentFilePath }
919 }
920 }
921 }
922 `)
923 
924 result.data.allMdx.nodes.forEach((node) => {
925 createPage({
926 path: `/blog/${node.frontmatter.slug}`,
927 component: `${blogPostTemplate}?__contentFilePath=${node.internal.contentFilePath}`,
928 context: { id: node.id },
929 })
930 })
931}
932```
933 
934### Key Configuration Notes
935- Static output at build time: AI crawlers get full HTML
936- Use `gatsby-plugin-sitemap` for sitemap generation
937- Use `gatsby-plugin-robots-txt` for robots.txt configuration
938- `gatsby-plugin-react-helmet` or Gatsby Head API for meta tags
939- JSON-LD: use `gatsby-plugin-schema-snapshot` or inline in Head component
940- Build can be slow for large sites: consider incremental builds
941 
942---
943 
944## HTML / Static
945 
946### Semantic HTML5 Structure
947```html
948<!DOCTYPE html>
949<html lang="en">
950<head>
951 <meta charset="utf-8">
952 <meta name="viewport" content="width=device-width, initial-scale=1">
953 <title>How Does AI Search Impact Organic Traffic in 2026?</title>
954 <meta name="description" content="AI Overview CTR gap narrowed to about 38%. Here's how to optimize for Google rankings and AI citations in 2026.">
955 
956 <!-- Open Graph -->
957 <meta property="og:type" content="article">
958 <meta property="og:title" content="How Does AI Search Impact Organic Traffic in 2026?">
959 <meta property="og:description" content="AI Overview CTR gap narrowed to about 38%.">
960 <meta property="og:image" content="https://cdn.pixabay.com/photo/.../cover.jpg">
961 <meta property="og:url" content="https://yourblog.com/ai-search-organic-traffic">
962 <meta property="article:published_time" content="2026-02-18T00:00:00Z">
963 <meta property="article:modified_time" content="2026-02-18T00:00:00Z">
964 
965 <!-- Twitter Card -->
966 <meta name="twitter:card" content="summary_large_image">
967 <meta name="twitter:title" content="How Does AI Search Impact Organic Traffic in 2026?">
968 <meta name="twitter:description" content="AI Overview CTR gap narrowed to about 38%.">
969 <meta name="twitter:image" content="https://cdn.pixabay.com/photo/.../cover.jpg">
970 
971 <!-- JSON-LD Structured Data -->
972 <script type="application/ld+json">
973 {
974 "@context": "https://schema.org",
975 "@type": "BlogPosting",
976 "headline": "How Does AI Search Impact Organic Traffic in 2026?",
977 "description": "AI Overview CTR gap narrowed to about 38%.",
978 "image": "https://cdn.pixabay.com/photo/.../cover.jpg",
979 "datePublished": "2026-02-18",
980 "dateModified": "2026-02-18",
981 "author": {
982 "@type": "Person",
983 "name": "Author Name",
984 "url": "https://yourblog.com/about"
985 },
986 "publisher": {
987 "@type": "Organization",
988 "name": "Blog Name",
989 "logo": {
990 "@type": "ImageObject",
991 "url": "https://yourblog.com/logo.png"
992 }
993 },
994 "mainEntityOfPage": {
995 "@type": "WebPage",
996 "@id": "https://yourblog.com/ai-search-organic-traffic"
997 }
998 }
999 </script>
1000</head>
1001<body>
1002 <nav aria-label="Main navigation">
1003 <!-- Navigation -->
1004 </nav>
1005 
1006 <article>
1007 <header>
1008 <h1>How Does AI Search Impact Organic Traffic in 2026?</h1>
1009 <time datetime="2026-02-18">February 18, 2026</time>
1010 </header>
1011 
1012 <section>
1013 <h2>What Is the Impact of AI Overviews on Click-Through Rates?</h2>
1014 <p>AIO organic CTR rebounded from 1.3% in December 2025 to about 2.4%
1015 in February 2026 (<a href="https://seerinteractive.com">Seer Interactive</a>,
1016 April 2026). Cited pages now earn 120% more clicks per impression than
1017 uncited pages.</p>
1018 
1019 <figure>
1020 <img src="https://cdn.pixabay.com/photo/.../image.jpg"
1021 alt="Marketing dashboard showing AI search CTR metrics"
1022 width="1200" height="630" loading="lazy">
1023 <figcaption>Photo via Pixabay</figcaption>
1024 </figure>
1025 </section>
1026 
1027 <aside aria-label="Frequently Asked Questions">
1028 <h2>Frequently Asked Questions</h2>
1029 <!-- FAQ content -->
1030 </aside>
1031 </article>
1032 
1033 <footer>
1034 <!-- Footer -->
1035 </footer>
1036</body>
1037</html>
1038```
1039 
1040### Image Embedding
1041```html
1042<figure>
1043 <img src="https://cdn.pixabay.com/photo/.../image.jpg"
1044 alt="Descriptive sentence including topic keywords naturally"
1045 width="1200" height="630"
1046 loading="lazy"
1047 decoding="async">
1048 <figcaption>Photo via Pixabay</figcaption>
1049</figure>
1050```
1051 
1052### Chart / SVG Embedding
1053```html
1054<figure>
1055 <svg viewBox="0 0 560 380"
1056 style="max-width: 100%; height: auto; font-family: 'Inter', system-ui, sans-serif"
1057 role="img"
1058 aria-label="Chart showing AIO organic CTR rebound from 1.3% to about 2.4%">
1059 <title>AIO Organic CTR Rebound</title>
1060 <desc>Bar chart comparing the December 2025 AIO CTR floor to the February 2026 rebound</desc>
1061 <!-- SVG content with standard HTML attributes -->
1062 </svg>
1063 <figcaption>Source: Seer Interactive (Apr 2026)</figcaption>
1064</figure>
1065```
1066 
1067### Inline JSON-LD Schema
1068 
1069Place in `<head>` for BlogPosting:
1070```html
1071<script type="application/ld+json">
1072{
1073 "@context": "https://schema.org",
1074 "@type": "BlogPosting",
1075 "headline": "Title",
1076 "datePublished": "2026-02-18",
1077 "dateModified": "2026-02-18",
1078 "author": { "@type": "Person", "name": "Author" }
1079}
1080</script>
1081```
1082 
1083Place in `<head>` for FAQPage only when visible Q&A exists. It is entity
1084support for AI citation, not a Google rich result:
1085```html
1086<script type="application/ld+json">
1087{
1088 "@context": "https://schema.org",
1089 "@type": "FAQPage",
1090 "mainEntity": [
1091 {
1092 "@type": "Question",
1093 "name": "What is the question?",
1094 "acceptedAnswer": {
1095 "@type": "Answer",
1096 "text": "The visible answer text with a specific statistic and source."
1097 }
1098 }
1099 ]
1100}
1101</script>
1102```
1103 
1104### Key Configuration Notes
1105- No framework dependency: works with any hosting
1106- AI crawlers can read static HTML without JS execution
1107- Manually manage OG/Twitter meta tags in `<head>`
1108- Use `loading="lazy"` and `decoding="async"` on images for performance
1109- Schema must be in HTML source, not injected via JavaScript
1110- Generate sitemap.xml manually or with a build script
1111- Use `<link rel="canonical" href="...">` to prevent duplicate content
1112- Place CSS in `<head>` (inline critical CSS for fast TTFB)
1113 
1114---
1115 
1116## Platform Selection Quick Reference
1117 
1118| Priority | Criterion | Recommendation |
1119|----------|-----------|---------------|
1120| AI crawlers | JS execution required? | Use SSG/SSR (Next.js, Astro, Hugo, 11ty, Gatsby) |
1121| Speed | TTFB < 200ms | Hugo (fastest builds), 11ty, Astro, static HTML |
1122| MDX/React | Component-driven content | Next.js, Gatsby |
1123| Simplicity | Minimal tooling | Hugo, Jekyll, 11ty, static HTML |
1124| Non-technical users | Visual editor | WordPress, Ghost |
1125| Headless CMS | API-first | Ghost (Content API), WordPress (REST API) |
1126 
1127### Universal Requirements (All Platforms)
1128 
11291. **Static or server-rendered HTML**: AI crawlers cannot execute JavaScript
11302. **TTFB under 200ms**: AI crawlers timeout at 3-5 seconds
11313. **Schema in HTML source**: not injected via client-side JS
11324. **robots.txt allowing AI crawlers**: GPTBot, ClaudeBot, PerplexityBot
11335. **Sitemap at /sitemap.xml**: helps all crawlers discover content
11346. **OG meta tags**: required for social sharing previews
11357. **dateModified in schema**: critical for freshness signals
1136 

Discussion

Alternatives