This repository has been archived on 2025-08-21. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
hugo-mistergeek/docs/hugo-wordpress-integration.md
2025-08-18 15:31:30 +02:00

400 lines
11 KiB
Markdown

# 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