# Hugo WordPress Integration Guide

This guide provides step-by-step instructions for setting up a Hugo static site that fetches and displays blog articles from a WordPress API.

## Project Overview

Your Hugo project will act as a static site generator that pulls content from a WordPress REST API and generates a fast, SEO-friendly blog. This approach combines the performance benefits of static sites with the content management capabilities of WordPress.

## Prerequisites

- Hugo installed (v0.110.0 or later)
- WordPress site with REST API enabled
- Basic knowledge of Go templates and Hugo
- Node.js (for build scripts)

## Step 1: Configure Hugo for WordPress API Integration

### Update hugo.toml Configuration

Add the following configuration to your [`hugo.toml`](hugo.toml:1) file:

```toml
# Base configuration
baseURL = "https://yourblog.com"
languageCode = "en-us"
title = "Your Blog Title"
theme = "your-theme"

# WordPress API Configuration
[params.wordpress]
  apiUrl = "https://your-wordpress-site.com/wp-json/wp/v2"
  postsPerPage = 10
  featuredImageSize = "large"
  authorEndpoint = "users"
  categoryEndpoint = "categories"
  tagEndpoint = "tags"

# Build configuration
[build]
  writeStats = true
  [[build.cachebusters]]
    source = "assets/.*\\.(js|ts|jsx|ts)$"
    target = "js"
  [[build.cachebusters]]
    source = "assets/.*\\.(css|sass|scss)$"
    target = "css"
```

## Step 2: Create Data Fetching Scripts

### Create API Fetching Script

Create a new file [`scripts/fetch-wordpress.js`](scripts/fetch-wordpress.js:1):

```javascript
const fs = require('fs');
const path = require('path');
const fetch = require('node-fetch');

const WORDPRESS_API = 'https://www.mistergeek.net//wp-json/wp/v2';
const OUTPUT_DIR = path.join(__dirname, '..', 'data', 'wordpress');

async function fetchPosts(page = 1, perPage = 100) {
  const response = await fetch(`${WORDPRESS_API}/posts?page=${page}&per_page=${perPage}&_embed`);
  const posts = await response.json();
  
  if (response.headers.get('x-wp-totalpages') > page) {
    const nextPosts = await fetchPosts(page + 1, perPage);
    return [...posts, ...nextPosts];
  }
  
  return posts;
}

async function fetchCategories() {
  const response = await fetch(`${WORDPRESS_API}/categories?per_page=100`);
  return response.json();
}

async function fetchTags() {
  const response = await fetch(`${WORDPRESS_API}/tags?per_page=100`);
  return response.json();
}

async function fetchAuthors() {
  const response = await fetch(`${WORDPRESS_API}/users?per_page=100`);
  return response.json();
}

async function generateData() {
  // Ensure output directory exists
  if (!fs.existsSync(OUTPUT_DIR)) {
    fs.mkdirSync(OUTPUT_DIR, { recursive: true });
  }

  console.log('Fetching WordPress data...');
  
  const [posts, categories, tags, authors] = await Promise.all([
    fetchPosts(),
    fetchCategories(),
    fetchTags(),
    fetchAuthors()
  ]);

  // Save data as JSON files
  fs.writeFileSync(path.join(OUTPUT_DIR, 'posts.json'), JSON.stringify(posts, null, 2));
  fs.writeFileSync(path.join(OUTPUT_DIR, 'categories.json'), JSON.stringify(categories, null, 2));
  fs.writeFileSync(path.join(OUTPUT_DIR, 'tags.json'), JSON.stringify(tags, null, 2));
  fs.writeFileSync(path.join(OUTPUT_DIR, 'authors.json'), JSON.stringify(authors, null, 2));

  console.log(`✅ Fetched ${posts.length} posts, ${categories.length} categories, ${tags.length} tags, ${authors.length} authors`);
}

generateData().catch(console.error);
```

### Create Package.json for Build Scripts

Create [`package.json`](package.json:1):

```json
{
  "name": "hugo-wordpress-blog",
  "version": "1.0.0",
  "description": "Hugo static site with WordPress content",
  "scripts": {
    "fetch-data": "node scripts/fetch-wordpress.js",
    "build": "npm run fetch-data && hugo --minify",
    "dev": "npm run fetch-data && hugo server -D"
  },
  "dependencies": {
    "node-fetch": "^3.3.2"
  }
}
```

## Step 3: Create Hugo Templates for WordPress Content

### Create Content Layout

Create [`layouts/_default/single.html`](layouts/_default/single.html:1):

```html
{{ define "main" }}
<article class="post">
  <header class="post-header">
    <h1 class="post-title">{{ .Title }}</h1>
    <div class="post-meta">
      <time datetime="{{ .Date.Format "2006-01-02" }}">{{ .Date.Format "January 2, 2006" }}</time>
      {{ if .Params.author }}
        <span class="post-author">{{ .Params.author.name }}</span>
      {{ end }}
      {{ if .Params.categories }}
        <div class="post-categories">
          {{ range .Params.categories }}
            <a href="/categories/{{ .slug }}" class="category">{{ .name }}</a>
          {{ end }}
        </div>
      {{ end }}
    </div>
    {{ if .Params.featured_image }}
      <img src="{{ .Params.featured_image }}" alt="{{ .Title }}" class="featured-image">
    {{ end }}
  </header>

  <div class="post-content">
    {{ .Content }}
  </div>

  {{ if .Params.tags }}
    <div class="post-tags">
      {{ range .Params.tags }}
        <a href="/tags/{{ .slug }}" class="tag">#{{ .name }}</a>
      {{ end }}
    </div>
  {{ end }}
</article>
{{ end }}
```

### Create List Layout

Create [`layouts/_default/list.html`](layouts/_default/list.html:1):

```html
{{ define "main" }}
<div class="posts-list">
  <h1>{{ .Title }}</h1>
  
  {{ range .Pages }}
  <article class="post-preview">
    <h2><a href="{{ .RelPermalink }}">{{ .Title }}</a></h2>
    <div class="post-meta">
      <time>{{ .Date.Format "Jan 2, 2006" }}</time>
      {{ if .Params.author }}
        <span>{{ .Params.author.name }}</span>
      {{ end }}
    </div>
    {{ if .Params.excerpt }}
      <p class="post-excerpt">{{ .Params.excerpt }}</p>
    {{ end }}
    <a href="{{ .RelPermalink }}" class="read-more">Read more →</a>
  </article>
  {{ end }}
</div>
{{ end }}
```

## Step 4: Create Hugo Content from WordPress Data

### Create Content Generator Script

Create [`scripts/generate-content.js`](scripts/generate-content.js:1):

```javascript
const fs = require('fs');
const path = require('path');

const DATA_DIR = path.join(__dirname, '..', 'data', 'wordpress');
const CONTENT_DIR = path.join(__dirname, '..', 'content', 'posts');

function generateContent() {
  const posts = JSON.parse(fs.readFileSync(path.join(DATA_DIR, 'posts.json'), 'utf8'));
  
  // Ensure content directory exists
  if (!fs.existsSync(CONTENT_DIR)) {
    fs.mkdirSync(CONTENT_DIR, { recursive: true });
  }

  posts.forEach(post => {
    const slug = post.slug;
    const date = new Date(post.date);
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    
    const contentDir = path.join(CONTENT_DIR, `${year}-${month}-${slug}`);
    
    if (!fs.existsSync(contentDir)) {
      fs.mkdirSync(contentDir, { recursive: true });
    }

    const frontmatter = {
      title: post.title.rendered,
      date: post.date,
      draft: post.status !== 'publish',
      slug: slug,
      wordpress_id: post.id,
      excerpt: post.excerpt.rendered.replace(/<[^>]*>/g, ''),
      featured_image: post._embedded?.['wp:featuredmedia']?.[0]?.source_url || '',
      author: {
        id: post.author,
        name: post._embedded?.author?.[0]?.name || 'Unknown'
      },
      categories: post._embedded?.['wp:term']?.[0]?.map(cat => ({
        id: cat.id,
        name: cat.name,
        slug: cat.slug
      })) || [],
      tags: post._embedded?.['wp:term']?.[1]?.map(tag => ({
        id: tag.id,
        name: tag.name,
        slug: tag.slug
      })) || []
    };

    const content = `---
${Object.entries(frontmatter)
  .map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
  .join('\n')}
---

${post.content.rendered}`;

    fs.writeFileSync(path.join(contentDir, 'index.md'), content);
  });

  console.log(`✅ Generated ${posts.length} content files`);
}

generateContent();
```

## Step 5: Update Build Process

### Create Build Script

Update your [`package.json`](package.json:1) build scripts:

```json
{
  "scripts": {
    "fetch-data": "node scripts/fetch-wordpress.js",
    "generate-content": "node scripts/generate-content.js",
    "prebuild": "npm run fetch-data && npm run generate-content",
    "build": "hugo --minify",
    "dev": "npm run fetch-data && npm run generate-content && hugo server -D",
    "clean": "rm -rf data/wordpress content/posts public"
  }
}
```

## Step 6: Configure Netlify for Automated Builds

Create [`netlify.toml`](netlify.toml:1):

```toml
[build]
  command = "npm run build"
  publish = "public"

[build.environment]
  HUGO_VERSION = "0.110.0"
  NODE_VERSION = "18"

[[plugins]]
  package = "@netlify/plugin-sitemap"

[[plugins]]
  package = "netlify-plugin-hugo-cache-resources"
```

## Step 7: Advanced Features

### Add Search Functionality

Create [`layouts/partials/search.html`](layouts/partials/search.html:1):

```html
<div class="search-container">
  <input type="search" id="search" placeholder="Search articles..." aria-label="Search">
  <div id="search-results" class="search-results"></div>
</div>

<script>
// Add client-side search using Fuse.js
</script>
```

### Add RSS Feed

Create [`layouts/index.rss.xml`](layouts/index.rss.xml:1):

```xml
<rss version="2.0">
  <channel>
    <title>{{ .Site.Title }}</title>
    <link>{{ .Site.BaseURL }}</link>
    <description>{{ .Site.Params.description }}</description>
    <language>{{ .Site.LanguageCode }}</language>
    {{ range first 15 .Pages }}
    <item>
      <title>{{ .Title }}</title>
      <link>{{ .Permalink }}</link>
      <description>{{ .Params.excerpt }}</description>
      <pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" }}</pubDate>
      <guid>{{ .Permalink }}</guid>
    </item>
    {{ end }}
  </channel>
</rss>
```

## Deployment Options

### Netlify
1. Connect your GitHub repository
2. Set build command: `npm run build`
3. Set publish directory: `public`

### Vercel
1. Install Vercel CLI: `npm i -g vercel`
2. Run: `vercel --prod`

### GitHub Pages
1. Create `.github/workflows/deploy.yml`
2. Use GitHub Actions for automated deployment

## Performance Optimization

1. **Image Optimization**: Use Hugo's image processing
2. **CDN**: Configure Cloudflare or similar
3. **Caching**: Implement proper cache headers
4. **Minification**: Enable HTML/CSS/JS minification
5. **Preloading**: Add resource hints for critical assets

## Next Steps

1. Run `npm install` to install dependencies
2. Run `npm run dev` to start development server
3. Customize your theme and styling
4. Set up automated deployment
5. Configure SEO meta tags
6. Add analytics (Google Analytics, Plausible, etc.)

## Troubleshooting

- **API Rate Limits**: Implement caching and rate limiting
- **Image Loading**: Ensure WordPress images are accessible
- **CORS Issues**: Configure WordPress CORS headers
- **Build Time**: Consider incremental builds for large sites