Customization Guide
Customize your generated 11ty site with new templates, styles, and functionality.
Overview
Unpress generates a minimal, working 11ty site. You can customize nearly everything:
- Layouts - Change HTML structure and design
- Styles - Add CSS, themes, or frameworks
- Templates - Create new page types and components
- Content Types - Add custom WordPress content types
- Frontmatter - Add custom fields and metadata
Work with Copies
Before customizing, copy your site/ folder to preserve the original migration output. This way, you can always re-run migration if needed.
Customizing Templates
Modify Base Template
Edit _includes/layouts/base.njk to change site-wide structure:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }} - My Site</title>
<link rel="stylesheet" href="/assets/styles.css">
<!-- Add custom CSS -->
<link rel="stylesheet" href="/assets/custom.css">
</head>
<body>
<a href="#maincontent" class="skip-link">Skip to main content</a>
<header>
<nav aria-label="Main Navigation">
<a href="/">Home</a>
<a href="/about/">About</a>
<a href="/tags/">Tags</a>
<a href="/categories/">Categories</a>
</nav>
</header>
<main id="maincontent">
{{ content | safe }}
</main>
<footer>
<p>© 2024 My Site. All rights reserved.</p>
</footer>
</body>
</html>Common customizations:
- Add logo or site title in header
- Add sidebar with recent posts or categories
- Add search box or social media links
- Change footer with additional links or copyright
- Add analytics (Google Analytics, Plausible, etc.)
Create New Layouts
Create additional layouts in _includes/layouts/:
Post layout - _includes/layouts/post.njk:
---
layout: base.njk
---
<article class="post">
<header>
<h1>{{ title }}</h1>
<time datetime="{{ date | date('iso') }}">{{ date | date('MMMM D, YYYY') }}</time>
{% if author %}
<p>By {{ author.name }}</p>
{% endif %}
</header>
{{ content | safe }}
{% if tags %}
<footer>
<p>Tags: {% for tag in tags %}<a href="/tags/{{ tag }}/">{{ tag }}</a>{% if not loop.last %}, {% endif %}{% endfor %}</p>
</footer>
{% endif %}
</article>Use layout in post:
---
layout: post.njk
title: "My Post"
---Create Page Templates
Create reusable page templates:
About page template - _includes/templates/about.njk:
---
layout: base.njk
title: "About"
---
<section class="about">
<h1>About {{ site.name }}</h1>
{{ content | safe }}
</section>Use template:
---
layout: ../templates/about.njk
---
This is the about page content.Customizing Styles
Modify Existing CSS
Edit assets/styles.css to change colors, fonts, and layout:
:root {
--color-primary: #3b82f6;
--color-secondary: #1e293b;
--color-text: #334155;
--color-background: #ffffff;
--font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
body {
font-family: var(--font-family);
color: var(--color-text);
background: var(--color-background);
line-height: 1.6;
}
header {
background: var(--color-secondary);
color: white;
padding: 1rem 2rem;
}
nav a {
color: white;
margin-right: 1rem;
text-decoration: none;
}
nav a:hover {
text-decoration: underline;
}
main {
max-width: 800px;
margin: 2rem auto;
padding: 0 1rem;
}
footer {
background: var(--color-secondary);
color: white;
padding: 1rem 2rem;
text-align: center;
}Add Custom CSS
Create assets/custom.css and include it in base template:
<link rel="stylesheet" href="/assets/custom.css">Custom CSS example:
/* Custom button styles */
.btn {
display: inline-block;
padding: 0.75rem 1.5rem;
background: var(--color-primary);
color: white;
text-decoration: none;
border-radius: 0.25rem;
transition: background 0.3s;
}
.btn:hover {
background: #2563eb;
}
/* Sidebar styles */
.sidebar {
background: var(--color-background);
border: 1px solid #e2e8f0;
border-radius: 0.5rem;
padding: 1.5rem;
}
/* Dark mode support */
@media (prefers-color-scheme: dark) {
:root {
--color-text: #e2e8f0;
--color-background: #1e293b;
}
}Use CSS Framework
Add a CSS framework like Tailwind CSS, Bootstrap, or Bulma:
Install Tailwind CSS:
cd site
pnpm add -D tailwindcss postcss autoprefixer
npx tailwindcss init -pCreate assets/tailwind.css:
@tailwind base;
@tailwind components;
@tailwind utilities;Include in base template:
<link rel="stylesheet" href="/assets/tailwind.css">Use Tailwind classes in templates:
<div class="max-w-4xl mx-auto px-4 py-8">
<h1 class="text-4xl font-bold text-blue-600">{{ title }}</h1>
<div class="prose prose-lg mt-6">
{{ content | safe }}
</div>
</div>Customizing Frontmatter
Add Custom Fields
Add custom fields to your post frontmatter:
---
title: "My Post"
date: 2024-01-15
slug: my-post
author:
name: Jane Doe
email: jane@example.com
categories:
- Technology
tags:
- Web Development
featured_image: https://example.com/image.jpg
reading_time: 5 minutes # Custom field
difficulty: Intermediate # Custom field
---
Post content...Display Custom Fields in Templates
In post layout:
<article>
<header>
<h1>{{ title }}</h1>
{% if reading_time %}
<p>Reading time: {{ reading_time }}</p>
{% endif %}
{% if difficulty %}
<span class="badge">{{ difficulty }}</span>
{% endif %}
</header>
{{ content | safe }}
{% if featured_image %}
<img src="{{ featured_image }}" alt="{{ title }}">
{% endif %}
</article>Add Custom Fields to All Posts
Edit migration config (types.yml) to map WordPress custom fields:
- name: post
source: post
slug_field: slug
title_field: title
body_field: content
excerpt_field: excerpt
date_field: date
fields:
- name: author
source: author
- name: featured_image
source: featured_media
- name: reading_time
source: custom_field_reading_time # WordPress custom field
- name: difficulty
source: custom_field_difficulty # WordPress custom fieldUnpress will now include these fields in frontmatter.
Customizing Content Types
Add New Content Type
Add custom WordPress content type to migration:
Edit types.yml:
- name: product # New content type
source: product # WordPress post type slug
slug_field: slug
title_field: title
body_field: content
excerpt_field: excerpt
date_field: date
fields:
- name: price
source: custom_field_price
- name: sku
source: custom_field_skuRun migration:
unpress --config unpress.yml --generate-siteProducts will be created in content/products/ folder.
Create Custom Template for New Type
Create _includes/layouts/product.njk:
---
layout: base.njk
---
<article class="product">
<header>
<h1>{{ title }}</h1>
{% if price %}
<p class="price">${{ price }}</p>
{% endif %}
{% if sku %}
<p class="sku">SKU: {{ sku }}</p>
{% endif %}
</header>
{{ content | safe }}
</article>Add to product frontmatter:
---
layout: product.njk
title: "My Product"
price: 29.99
sku: PROD-001
---Customizing 11ty Configuration
Add Plugins
Edit .eleventy.js to add 11ty plugins:
const pluginRss = require("@11ty/eleventy-plugin-rss");
const pluginSyntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight");
module.exports = function(eleventyConfig) {
// Add RSS feed
eleventyConfig.addPlugin(pluginRss, {
outputFilename: "feed.xml",
});
// Add syntax highlighting for code blocks
eleventyConfig.addPlugin(pluginSyntaxHighlight);
return {
dir: {
input: "content",
output: "_site",
includes: "../_includes",
},
templateFormats: ["md", "njk"],
};
};Add Filters
Create custom 11ty filters:
// In .eleventy.js
module.exports = function(eleventyConfig) {
// Custom filter: capitalize first letter
eleventyConfig.addFilter("capitalize", (str) => {
return str.charAt(0).toUpperCase() + str.slice(1);
});
// Custom filter: reading time estimate
eleventyConfig.addFilter("readingTime", (content) => {
const wordsPerMinute = 200;
const wordCount = content.split(/\s+/).length;
const minutes = Math.ceil(wordCount / wordsPerMinute);
return `${minutes} minute${minutes !== 1 ? 's' : ''}`;
});
return {
// ... config
};
};Use filters in templates:
<h1>{{ title | capitalize }}</h1>
<p>Reading time: {{ content | readingTime }}</p>Add Shortcodes
Create reusable content with shortcodes:
// In .eleventy.js
module.exports = function(eleventyConfig) {
// Shortcode: YouTube embed
eleventyConfig.addShortcode("youtube", (videoId) => {
return `<iframe width="560" height="315" src="https://www.youtube.com/embed/${videoId}" frameborder="0" allowfullscreen></iframe>`;
});
// Shortcode: Warning box
eleventyConfig.addShortcode("warning", (content) => {
return `<div class="warning-box">${content}</div>`;
});
return {
// ... config
};
};Use shortcodes in Markdown:
This is my post.
{% youtube "dQw4w9WgXcQ" %}
{% warning %}This is a warning message.{% endwarning %}Advanced Customization
Add Search
Integrate Meilisearch for site search:
See Meilisearch Guide for complete setup.
Add Comments
Add third-party commenting system:
Disqus:
<div id="disqus_thread"></div>
<script>
var disqus_config = function () {
this.page.url = '{{ page.url | absoluteUrl }}';
this.page.identifier = '{{ page.fileSlug }}';
};
(function() {
var d = document, s = d.createElement('script');
s.src = 'https://your-site.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>Utterances (GitHub comments):
<script src="https://utteranc.es/client.js"
repo="username/repo"
issue-term="title"
theme="github-light"
crossorigin="anonymous"
async>
</script>Add Analytics
Google Analytics:
<script async src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'GA_MEASUREMENT_ID');
</script>Plausible Analytics (privacy-friendly):
<script defer data-domain="your-site.com" src="https://plausible.io/js/script.js"></script>Add Image Optimization
Use 11ty image plugin for responsive images:
// In .eleventy.js
const Image = require("@11ty/eleventy-img");
module.exports = function(eleventyConfig) {
eleventyConfig.addAsyncShortcode("image", async function(src, alt, sizes) {
let metadata = await Image(src, {
widths: [300, 600, 900, 1200],
formats: ["avif", "jpeg"],
outputDir: "./_site/img/",
});
let imageAttributes = {
alt,
sizes,
loading: "lazy",
decoding: "async",
};
return Image.generateHTML(metadata, imageAttributes, {
whitespaceMode: "inline",
});
});
return {
// ... config
};
};Use in templates:
{% image "/assets/image.jpg", "Alt text", "(max-width: 800px) 100vw" %}Customization Workflow
Recommended Workflow
- Copy site folder - Preserve original migration output
- Test changes locally - Use
eleventy --serveto preview - Commit changes - Use Git to track customizations
- Re-run migration - When WordPress site updates
- Apply customizations - Copy custom templates/styles back to new site
Using Git for Customizations
Initialize Git repository for your customizations:
cd site
git init
git add .
git commit -m "Initial migration"
# Customize site
git add .
git commit -m "Add custom layout and styles"Re-run migration:
# Backup customizations
cd ..
cp -r site site-custom
# Re-run migration
unpress --config unpress.yml --generate-site
# Restore customizations
cp -r site-custom/.git site/.git
cd site
git checkout -- .Next Steps
After customizing your site:
- Deployment Guide - Deploy your customized site
- 11ty Documentation - Learn more advanced 11ty features
- Generated Site Guide - Understand site structure better