first commit
This commit is contained in:
149
skills/wordpress-theme-to-emdash/phases/1-discovery.md
Normal file
149
skills/wordpress-theme-to-emdash/phases/1-discovery.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# Phase 1: Discovery & Reference Capture
|
||||
|
||||
Before writing any code, gather comprehensive reference materials from the demo site.
|
||||
|
||||
## 1.0 Create Discovery Folder
|
||||
|
||||
Create a `discovery/` folder in your theme directory to store all reference materials:
|
||||
|
||||
```
|
||||
discovery/
|
||||
├── screenshots/ # Reference screenshots from demo site
|
||||
│ ├── homepage.png
|
||||
│ ├── single-post.png
|
||||
│ ├── archive.png
|
||||
│ ├── category.png
|
||||
│ ├── page.png
|
||||
│ └── 404.png
|
||||
├── images/ # Sample images downloaded for seed content
|
||||
│ ├── featured-1.jpg
|
||||
│ ├── featured-2.jpg
|
||||
│ └── hero.jpg
|
||||
└── notes.md # Design decisions and observations
|
||||
```
|
||||
|
||||
The `notes.md` file should capture:
|
||||
|
||||
- Color values extracted from the demo
|
||||
- Font families and sizes observed
|
||||
- Layout patterns (header style, sidebar position, footer columns)
|
||||
- Special components or interactions to recreate
|
||||
- Anything that might be forgotten between sessions
|
||||
|
||||
## 1.1 Identify All Page Types
|
||||
|
||||
Identify the URL of the demo site for the WordPress theme you are converting. For wordpress.org themes, this is usually wp-themes.com/theme-name/. For other themes, use the "Live Preview" link. This may show it inside a frame; if so, ignore the frame and focus on the theme's actual content.
|
||||
|
||||
Use the agent-browser to explore the demo site to find every distinct page type:
|
||||
|
||||
- **Homepage** - Often has unique layout (hero, featured posts, etc.)
|
||||
- **Blog/Archive** - Post listing page
|
||||
- **Single Post** - Individual blog post with content
|
||||
- **Page** - Static page (About, Contact, etc.)
|
||||
- **Category/Tag Archive** - Taxonomy listing pages
|
||||
- **Search Results** - If the theme has custom search styling
|
||||
- **404 Page** - Error page styling
|
||||
|
||||
Use agent-browser to navigate the demo and discover pages:
|
||||
|
||||
```bash
|
||||
agent-browser open https://demo-site.com
|
||||
# Click around to find different page types
|
||||
# Check the navigation menu for page links
|
||||
# Look for "View all posts" or category links
|
||||
```
|
||||
|
||||
## 1.2 Screenshot All Page Types
|
||||
|
||||
Capture full-page screenshots of each page type to `discovery/screenshots/`:
|
||||
|
||||
```bash
|
||||
# Homepage
|
||||
agent-browser open https://demo-site.com
|
||||
agent-browser screenshot discovery/screenshots/homepage.png --full
|
||||
|
||||
# Single post (find a post with featured image and good content)
|
||||
agent-browser open https://demo-site.com/sample-post/
|
||||
agent-browser screenshot discovery/screenshots/single-post.png --full
|
||||
|
||||
# Blog archive
|
||||
agent-browser open https://demo-site.com/blog/
|
||||
agent-browser screenshot discovery/screenshots/archive.png --full
|
||||
|
||||
# Category page
|
||||
agent-browser open https://demo-site.com/category/news/
|
||||
agent-browser screenshot discovery/screenshots/category.png --full
|
||||
|
||||
# Static page
|
||||
agent-browser open https://demo-site.com/about/
|
||||
agent-browser screenshot discovery/screenshots/page.png --full
|
||||
|
||||
# 404 page
|
||||
agent-browser open https://demo-site.com/nonexistent-page-xyz/
|
||||
agent-browser screenshot discovery/screenshots/404.png --full
|
||||
```
|
||||
|
||||
## 1.3 Download Sample Images
|
||||
|
||||
If the theme is open source (GPL), download sample images from the demo to `discovery/images/`. This ensures visual consistency when comparing.
|
||||
|
||||
```bash
|
||||
# Find featured images in demo posts
|
||||
agent-browser eval "Array.from(document.querySelectorAll('article img')).map(i => i.src)"
|
||||
|
||||
# Download images for seed content
|
||||
curl -o discovery/images/featured-1.jpg "https://demo-site.com/wp-content/uploads/photo1.jpg"
|
||||
curl -o discovery/images/featured-2.jpg "https://demo-site.com/wp-content/uploads/photo2.jpg"
|
||||
```
|
||||
|
||||
For premium themes or when images aren't freely available, use Unsplash images that match the demo's visual style (same aspect ratios, similar subjects).
|
||||
|
||||
## 1.4 Document Page Structure
|
||||
|
||||
For each page type, document observations in `discovery/notes.md`:
|
||||
|
||||
- Header style (sticky? transparent? logo position?)
|
||||
- Sidebar presence and position
|
||||
- Footer layout (columns? widgets?)
|
||||
- Special components (hero sections, CTAs, etc.)
|
||||
- Color values (use browser DevTools color picker)
|
||||
- Font families and sizes
|
||||
- Spacing patterns
|
||||
|
||||
This inventory guides which templates and components you need to build, and preserves details that might be forgotten between sessions.
|
||||
|
||||
## Theme Source Discovery
|
||||
|
||||
### WordPress.org Themes
|
||||
|
||||
For themes on wordpress.org (e.g., `https://wordpress.org/themes/theme-name/`):
|
||||
|
||||
1. **Demo/Preview**: Click "Preview" button or visit `https://wp-themes.com/theme-name/`
|
||||
2. **Source Download**: The "Download" button provides a ZIP, or use:
|
||||
```bash
|
||||
curl -O https://downloads.wordpress.org/theme/theme-name.zip
|
||||
unzip theme-name.zip
|
||||
```
|
||||
3. **Theme Info**: The page includes author, version, tags, and description
|
||||
|
||||
### GitHub-Hosted Themes
|
||||
|
||||
1. **Source**: Clone or download the repository
|
||||
2. **Demo**: Check README for demo URL, or look for `Demo:` in theme description
|
||||
3. **Documentation**: Usually in README or `/docs` folder
|
||||
|
||||
### ThemeForest / Premium Themes
|
||||
|
||||
1. **Demo**: Use the "Live Preview" button on the product page
|
||||
2. **Source**: Requires purchase - ask the user to provide the unzipped theme files
|
||||
3. **Documentation**: Usually included in the download or linked from the product page
|
||||
|
||||
### Auto-Discovery
|
||||
|
||||
When given only a theme URL or name, derive URLs yourself:
|
||||
|
||||
1. Fetch the listing page to extract demo URL, download URL, and theme info
|
||||
2. Download the source (if freely available)
|
||||
3. Open the demo in agent-browser
|
||||
|
||||
Don't ask the user for URLs you can derive yourself.
|
||||
122
skills/wordpress-theme-to-emdash/phases/2-design.md
Normal file
122
skills/wordpress-theme-to-emdash/phases/2-design.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# Phase 2: Design Extraction
|
||||
|
||||
Extract design tokens from the WordPress theme source and live demo.
|
||||
|
||||
## 2.1 Analyze the Live Site
|
||||
|
||||
Use `agent-browser` to extract computed styles:
|
||||
|
||||
```bash
|
||||
agent-browser eval "(() => {
|
||||
const body = getComputedStyle(document.body);
|
||||
const header = document.querySelector('header, .site-header');
|
||||
return JSON.stringify({
|
||||
body: {
|
||||
fontFamily: body.fontFamily,
|
||||
fontSize: body.fontSize,
|
||||
color: body.color,
|
||||
background: body.backgroundColor,
|
||||
},
|
||||
header: header ? {
|
||||
background: getComputedStyle(header).backgroundColor,
|
||||
height: getComputedStyle(header).height,
|
||||
} : null,
|
||||
}, null, 2);
|
||||
})()"
|
||||
```
|
||||
|
||||
## 2.2 Extract Design Tokens
|
||||
|
||||
Read the theme's CSS files. Look for:
|
||||
|
||||
```
|
||||
style.css # Main stylesheet (has theme header)
|
||||
assets/css/ # Additional stylesheets
|
||||
theme.json # Block themes (WP 5.9+) - structured design tokens
|
||||
```
|
||||
|
||||
### CSS Variable Mapping
|
||||
|
||||
| WP Pattern | EmDash Variable |
|
||||
| ---------------- | ------------------ |
|
||||
| Body font family | `--font-body` |
|
||||
| Heading font | `--font-heading` |
|
||||
| Primary color | `--color-primary` |
|
||||
| Background | `--color-base` |
|
||||
| Text color | `--color-contrast` |
|
||||
| Content width | `--content-width` |
|
||||
|
||||
### Block Theme (theme.json)
|
||||
|
||||
Block themes store design tokens in `theme.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"settings": {
|
||||
"color": {
|
||||
"palette": [{ "slug": "primary", "color": "#0073aa", "name": "Primary" }]
|
||||
},
|
||||
"typography": {
|
||||
"fontFamilies": [{ "fontFamily": "'Open Sans', sans-serif", "slug": "body" }]
|
||||
},
|
||||
"layout": {
|
||||
"contentSize": "650px",
|
||||
"wideSize": "1200px"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 2.3 Create Base Layout
|
||||
|
||||
Create `src/layouts/Base.astro` with:
|
||||
|
||||
- Extracted CSS variables in `:root`
|
||||
- Header/footer structure matching WP theme
|
||||
- Font loading (Google Fonts or local)
|
||||
- Responsive breakpoints
|
||||
|
||||
### CSS Variables Template
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* Colors */
|
||||
--color-base: #ffffff;
|
||||
--color-contrast: #1a1a1a;
|
||||
--color-primary: #0073aa;
|
||||
--color-accent: #ff6b35;
|
||||
--color-muted: #6b7280;
|
||||
--color-border: #e5e7eb;
|
||||
|
||||
/* Typography */
|
||||
--font-body: system-ui, sans-serif;
|
||||
--font-heading: Georgia, serif;
|
||||
|
||||
/* Font sizes */
|
||||
--text-sm: 0.875rem;
|
||||
--text-base: 1rem;
|
||||
--text-lg: 1.125rem;
|
||||
--text-xl: 1.25rem;
|
||||
--text-2xl: 1.5rem;
|
||||
--text-3xl: 1.875rem;
|
||||
--text-4xl: 2.25rem;
|
||||
--text-5xl: clamp(2.5rem, 5vw, 3rem);
|
||||
|
||||
/* Spacing */
|
||||
--space-1: 0.25rem;
|
||||
--space-2: 0.5rem;
|
||||
--space-4: 1rem;
|
||||
--space-6: 1.5rem;
|
||||
--space-8: 2rem;
|
||||
--space-12: 3rem;
|
||||
--space-16: 4rem;
|
||||
--space-24: 6rem;
|
||||
|
||||
/* Layout */
|
||||
--content-width: 720px;
|
||||
--wide-width: 1200px;
|
||||
--header-height: 80px;
|
||||
}
|
||||
```
|
||||
|
||||
See `references/design-extraction.md` for detailed extraction techniques.
|
||||
114
skills/wordpress-theme-to-emdash/phases/3-templates.md
Normal file
114
skills/wordpress-theme-to-emdash/phases/3-templates.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# Phase 3: Template Conversion
|
||||
|
||||
Convert WordPress PHP templates to Astro components.
|
||||
|
||||
## 3.1 Analyze Theme Structure
|
||||
|
||||
Read `functions.php` to identify:
|
||||
|
||||
- `register_nav_menu()` → EmDash menus
|
||||
- `register_sidebar()` → EmDash widget areas
|
||||
- `add_theme_support()` → Features (thumbnails, formats, etc.)
|
||||
- `register_post_type()` → Collections
|
||||
- `register_taxonomy()` → EmDash taxonomy defs
|
||||
- `add_shortcode()` → Portable Text blocks
|
||||
|
||||
## 3.2 Template Mapping
|
||||
|
||||
| WP Template | Astro Route |
|
||||
| -------------- | ----------------------------------- |
|
||||
| `index.php` | `src/pages/index.astro` |
|
||||
| `single.php` | `src/pages/posts/[slug].astro` |
|
||||
| `page.php` | `src/pages/pages/[slug].astro` |
|
||||
| `archive.php` | `src/pages/posts/index.astro` |
|
||||
| `category.php` | `src/pages/categories/[slug].astro` |
|
||||
| `tag.php` | `src/pages/tags/[slug].astro` |
|
||||
| `search.php` | `src/pages/search.astro` |
|
||||
| `404.php` | `src/pages/404.astro` |
|
||||
| `header.php` | Component in layout |
|
||||
| `footer.php` | Component in layout |
|
||||
|
||||
## 3.3 Convert Templates
|
||||
|
||||
### The Loop → getEmDashCollection
|
||||
|
||||
```php
|
||||
// WordPress
|
||||
<?php while (have_posts()) : the_post(); ?>
|
||||
<h2><?php the_title(); ?></h2>
|
||||
<?php endwhile; ?>
|
||||
```
|
||||
|
||||
```astro
|
||||
---
|
||||
// Astro/EmDash
|
||||
import { getEmDashCollection } from "emdash";
|
||||
const { entries: posts } = await getEmDashCollection("posts");
|
||||
---
|
||||
{posts.map(post => <h2>{post.data.title}</h2>)}
|
||||
```
|
||||
|
||||
### Single Post → getEmDashEntry
|
||||
|
||||
```php
|
||||
// WordPress
|
||||
<?php the_content(); ?>
|
||||
```
|
||||
|
||||
```astro
|
||||
---
|
||||
// Astro/EmDash
|
||||
import { getEmDashEntry } from "emdash";
|
||||
import { PortableText } from "emdash/ui";
|
||||
const { entry: post } = await getEmDashEntry("posts", Astro.params.slug);
|
||||
---
|
||||
{post && <PortableText value={post.data.content} />}
|
||||
```
|
||||
|
||||
## 3.4 Page Templates
|
||||
|
||||
WordPress themes often register page templates (Full Width, Sidebar, Landing Page, etc.). In EmDash, this is a `select` field on the pages collection:
|
||||
|
||||
1. Add a `template` select field to the pages collection with the theme's template names as options (e.g. "Default", "Full Width", "Landing Page")
|
||||
2. Create an Astro layout component for each template in `src/layouts/`
|
||||
3. Map the field value to a layout component in the page route:
|
||||
|
||||
```astro
|
||||
---
|
||||
// src/pages/pages/[slug].astro
|
||||
import { getEmDashEntry } from "emdash";
|
||||
import PageDefault from "../../layouts/PageDefault.astro";
|
||||
import PageFullWidth from "../../layouts/PageFullWidth.astro";
|
||||
|
||||
const { slug } = Astro.params;
|
||||
const { entry: page } = await getEmDashEntry("pages", slug!);
|
||||
if (!page) return Astro.redirect("/404");
|
||||
|
||||
const layouts = {
|
||||
"Default": PageDefault,
|
||||
"Full Width": PageFullWidth,
|
||||
};
|
||||
const Layout = layouts[page.data.template as keyof typeof layouts] ?? PageDefault;
|
||||
---
|
||||
<Layout page={page} />
|
||||
```
|
||||
|
||||
Use human-readable option names (matching what the WP theme displayed) since these appear in the admin dropdown.
|
||||
|
||||
## Important: Server-Rendered Pages
|
||||
|
||||
**Never use `getStaticPaths()` or `export const prerender = true` for EmDash content pages.** Content changes at runtime, so pages must be server-rendered.
|
||||
|
||||
```astro
|
||||
---
|
||||
// CORRECT - server-rendered
|
||||
const { slug } = Astro.params;
|
||||
const { entry: post } = await getEmDashEntry("posts", slug!);
|
||||
|
||||
if (!post) {
|
||||
return Astro.redirect("/404");
|
||||
}
|
||||
---
|
||||
```
|
||||
|
||||
See `references/template-patterns.md` for more conversion patterns.
|
||||
147
skills/wordpress-theme-to-emdash/phases/4-dynamic.md
Normal file
147
skills/wordpress-theme-to-emdash/phases/4-dynamic.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# Phase 4: Dynamic Features
|
||||
|
||||
Implement CMS-driven features: site settings, menus, taxonomies, and widgets.
|
||||
|
||||
## 4.1 Site Settings
|
||||
|
||||
Map WordPress customizer values to EmDash site settings:
|
||||
|
||||
| WP Customizer Setting | EmDash Site Setting |
|
||||
| --------------------- | --------------------- |
|
||||
| Site Title | `title` |
|
||||
| Tagline | `tagline` |
|
||||
| Site Icon | `favicon` |
|
||||
| Custom Logo | `logo` |
|
||||
| Posts per page | `postsPerPage` |
|
||||
| Date format | `dateFormat` |
|
||||
|
||||
```astro
|
||||
---
|
||||
import { getSiteSettings } from "emdash";
|
||||
const settings = await getSiteSettings();
|
||||
---
|
||||
<header>
|
||||
{settings.logo ? (
|
||||
<img src={settings.logo.url} alt={settings.title} />
|
||||
) : (
|
||||
<span class="site-title">{settings.title}</span>
|
||||
)}
|
||||
{settings.tagline && <p class="tagline">{settings.tagline}</p>}
|
||||
</header>
|
||||
```
|
||||
|
||||
## 4.2 Navigation Menus
|
||||
|
||||
Identify menus in `functions.php`:
|
||||
|
||||
```php
|
||||
register_nav_menus([
|
||||
'primary' => 'Primary Navigation',
|
||||
'footer' => 'Footer Links',
|
||||
]);
|
||||
```
|
||||
|
||||
Use in templates:
|
||||
|
||||
```astro
|
||||
---
|
||||
import { getMenu } from "emdash";
|
||||
const primaryNav = await getMenu("primary");
|
||||
---
|
||||
<nav class="primary-nav">
|
||||
{primaryNav && (
|
||||
<ul>
|
||||
{primaryNav.items.map(item => (
|
||||
<li>
|
||||
<a href={item.url} aria-current={Astro.url.pathname === item.url ? 'page' : undefined}>
|
||||
{item.label}
|
||||
</a>
|
||||
{item.children.length > 0 && (
|
||||
<ul class="submenu">
|
||||
{item.children.map(child => (
|
||||
<li><a href={child.url}>{child.label}</a></li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</nav>
|
||||
```
|
||||
|
||||
## 4.3 Taxonomies
|
||||
|
||||
Identify taxonomies in theme:
|
||||
|
||||
```php
|
||||
register_taxonomy('genre', 'book', [
|
||||
'label' => 'Genres',
|
||||
'hierarchical' => true,
|
||||
]);
|
||||
```
|
||||
|
||||
Use in templates:
|
||||
|
||||
```astro
|
||||
---
|
||||
import { getTaxonomyTerms, getEntryTerms, getEntriesByTerm } from "emdash";
|
||||
|
||||
// Get all terms
|
||||
const genres = await getTaxonomyTerms("genre");
|
||||
|
||||
// Get terms for a specific entry
|
||||
const bookGenres = await getEntryTerms("books", book.id, "genre");
|
||||
|
||||
// Get entries by term
|
||||
const fictionBooks = await getEntriesByTerm("books", "genre", "fiction");
|
||||
---
|
||||
```
|
||||
|
||||
## 4.4 Widget Areas
|
||||
|
||||
Identify sidebars in theme:
|
||||
|
||||
```php
|
||||
register_sidebar([
|
||||
'name' => 'Main Sidebar',
|
||||
'id' => 'sidebar-1',
|
||||
]);
|
||||
```
|
||||
|
||||
Use in templates:
|
||||
|
||||
```astro
|
||||
---
|
||||
import { getWidgetArea } from "emdash";
|
||||
import { PortableText } from "emdash/ui";
|
||||
|
||||
const sidebar = await getWidgetArea("sidebar");
|
||||
---
|
||||
{sidebar && sidebar.widgets.length > 0 && (
|
||||
<aside class="sidebar">
|
||||
{sidebar.widgets.map(widget => (
|
||||
<div class="widget">
|
||||
{widget.title && <h3>{widget.title}</h3>}
|
||||
{widget.type === "content" && <PortableText value={widget.content} />}
|
||||
</div>
|
||||
))}
|
||||
</aside>
|
||||
)}
|
||||
```
|
||||
|
||||
## 4.5 Widget Components
|
||||
|
||||
Map WP widgets to Astro components:
|
||||
|
||||
| WP Widget | EmDash Component |
|
||||
| ---------------- | ------------------- |
|
||||
| Recent Posts | `core:recent-posts` |
|
||||
| Categories | `core:categories` |
|
||||
| Tag Cloud | `core:tags` |
|
||||
| Search | `core:search` |
|
||||
| Archives | `core:archives` |
|
||||
| Text/Custom HTML | `type: 'content'` |
|
||||
| Navigation Menu | `type: 'menu'` |
|
||||
|
||||
See `references/emdash-api.md` for full API reference.
|
||||
206
skills/wordpress-theme-to-emdash/phases/5-seed.md
Normal file
206
skills/wordpress-theme-to-emdash/phases/5-seed.md
Normal file
@@ -0,0 +1,206 @@
|
||||
# Phase 5: Create Seed File
|
||||
|
||||
Combine all theme features into a seed file with sample content.
|
||||
|
||||
## 5.1 Image Strategy
|
||||
|
||||
**Use the same images you downloaded in Phase 1** for visual consistency.
|
||||
|
||||
1. **Open source themes (GPL)**: Use exact images from the demo
|
||||
2. **Premium themes**: Use Unsplash images matching the demo's style
|
||||
3. **Local images**: Reference with `file:./` prefix:
|
||||
```json
|
||||
"featured_image": {
|
||||
"$media": {
|
||||
"url": "file:./discovery/images/hero.jpg",
|
||||
"alt": "Hero image"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5.2 Validate Before Applying
|
||||
|
||||
```bash
|
||||
# Validate without applying
|
||||
emdash seed --validate
|
||||
```
|
||||
|
||||
The validator catches common mistakes:
|
||||
|
||||
| Check | Error |
|
||||
| ---------------------------- | ------------------------- |
|
||||
| Image using raw URL | "must use $media syntax" |
|
||||
| Reference using raw ID | "must use $ref:id syntax" |
|
||||
| PortableText not an array | "expected array" |
|
||||
| PortableText missing `_type` | "missing required \_type" |
|
||||
|
||||
### Common Fixes
|
||||
|
||||
```json
|
||||
// WRONG - raw URL
|
||||
"featured_image": "https://example.com/photo.jpg"
|
||||
|
||||
// CORRECT - $media syntax
|
||||
"featured_image": {
|
||||
"$media": {
|
||||
"url": "https://example.com/photo.jpg",
|
||||
"alt": "Description"
|
||||
}
|
||||
}
|
||||
|
||||
// WRONG - unknown byline reference
|
||||
"bylines": [{ "byline": "author-1" }]
|
||||
|
||||
// CORRECT - define root bylines[] and reference byline IDs
|
||||
"bylines": [{ "byline": "byline-author-1" }]
|
||||
```
|
||||
|
||||
## 5.3 Seed File Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://emdashcms.com/seed.schema.json",
|
||||
"version": "1",
|
||||
"meta": {
|
||||
"name": "Theme Name",
|
||||
"description": "Ported from WordPress theme"
|
||||
},
|
||||
|
||||
"settings": {
|
||||
"title": "Site Title",
|
||||
"tagline": "Site tagline"
|
||||
},
|
||||
|
||||
"collections": [
|
||||
{
|
||||
"slug": "posts",
|
||||
"label": "Posts",
|
||||
"fields": [
|
||||
{ "slug": "title", "type": "string", "required": true },
|
||||
{ "slug": "content", "type": "portableText" },
|
||||
{ "slug": "featured_image", "type": "image" }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
"taxonomies": [
|
||||
{
|
||||
"name": "categories",
|
||||
"label": "Categories",
|
||||
"hierarchical": true,
|
||||
"collections": ["posts"],
|
||||
"terms": [{ "slug": "news", "label": "News" }]
|
||||
}
|
||||
],
|
||||
|
||||
"bylines": [
|
||||
{
|
||||
"id": "byline-author-1",
|
||||
"slug": "theme-author",
|
||||
"displayName": "Theme Author"
|
||||
}
|
||||
],
|
||||
|
||||
"menus": [
|
||||
{
|
||||
"name": "primary",
|
||||
"label": "Primary Navigation",
|
||||
"items": [
|
||||
{ "type": "custom", "label": "Home", "url": "/" },
|
||||
{ "type": "custom", "label": "Blog", "url": "/posts" }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
"content": {
|
||||
"posts": [
|
||||
{
|
||||
"id": "post-1",
|
||||
"slug": "hello-world",
|
||||
"status": "published",
|
||||
"bylines": [{ "byline": "byline-author-1" }],
|
||||
"data": {
|
||||
"title": "Hello World",
|
||||
"content": [{ "_type": "block", "children": [{ "text": "Welcome!" }] }],
|
||||
"featured_image": {
|
||||
"$media": {
|
||||
"url": "file:./discovery/images/featured-1.jpg",
|
||||
"alt": "Featured image"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5.4 Adding Sections (Reusable Blocks)
|
||||
|
||||
If the theme has reusable block patterns, add them as sections:
|
||||
|
||||
```json
|
||||
{
|
||||
"sections": [
|
||||
{
|
||||
"slug": "hero-centered",
|
||||
"title": "Centered Hero",
|
||||
"description": "Full-width hero with centered heading and CTA button",
|
||||
"keywords": ["hero", "banner", "header", "landing"],
|
||||
"content": [
|
||||
{
|
||||
"_type": "block",
|
||||
"style": "h1",
|
||||
"children": [{ "_type": "span", "text": "Welcome to Our Site" }]
|
||||
},
|
||||
{
|
||||
"_type": "block",
|
||||
"children": [{ "_type": "span", "text": "Your compelling tagline goes here." }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "newsletter-cta",
|
||||
"title": "Newsletter Signup",
|
||||
"keywords": ["newsletter", "subscribe", "email", "signup"],
|
||||
"content": [
|
||||
{
|
||||
"_type": "block",
|
||||
"style": "h3",
|
||||
"children": [{ "_type": "span", "text": "Subscribe to our newsletter" }]
|
||||
},
|
||||
{
|
||||
"_type": "block",
|
||||
"children": [
|
||||
{ "_type": "span", "text": "Get the latest updates delivered to your inbox." }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Editors can insert these sections using the `/section` slash command in the rich text editor.
|
||||
|
||||
## 5.5 Add Redirects for Legacy WordPress URLs
|
||||
|
||||
Include redirects in the seed when the WordPress theme used different URL structures.
|
||||
|
||||
```json
|
||||
{
|
||||
"redirects": [
|
||||
{ "source": "/?p=123", "destination": "/hello-world" },
|
||||
{ "source": "/2024/01/hello-world", "destination": "/hello-world", "type": 301 },
|
||||
{ "source": "/category/news", "destination": "/categories/news" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- `source` and `destination` must be local paths (start with `/`)
|
||||
- Supported `type` values are `301`, `302`, `307`, `308`
|
||||
- Redirects are idempotent during seeding (existing `source` entries are skipped)
|
||||
|
||||
See `references/emdash-api.md` for full seed file schema.
|
||||
97
skills/wordpress-theme-to-emdash/phases/6-verify.md
Normal file
97
skills/wordpress-theme-to-emdash/phases/6-verify.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Phase 6: Verify & Iterate
|
||||
|
||||
Seed content, run the dev server, compare screenshots, and iterate until pages match.
|
||||
|
||||
## 6.1 Apply the Seed
|
||||
|
||||
```bash
|
||||
# Validate first
|
||||
emdash seed --validate
|
||||
|
||||
# Apply seed with content
|
||||
emdash seed
|
||||
```
|
||||
|
||||
## 6.2 Start Dev Server
|
||||
|
||||
Kill any existing server first:
|
||||
|
||||
```bash
|
||||
lsof -ti:4321 | xargs kill -9 2>/dev/null || true
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## 6.3 Screenshot Each Page Type
|
||||
|
||||
Screenshot every page type you captured in Phase 1:
|
||||
|
||||
```bash
|
||||
# Homepage
|
||||
agent-browser open http://localhost:4321
|
||||
agent-browser screenshot output/homepage.png --full
|
||||
|
||||
# Single post
|
||||
agent-browser open http://localhost:4321/posts/hello-world
|
||||
agent-browser screenshot output/single-post.png --full
|
||||
|
||||
# Blog archive
|
||||
agent-browser open http://localhost:4321/posts
|
||||
agent-browser screenshot output/archive.png --full
|
||||
|
||||
# Category page
|
||||
agent-browser open http://localhost:4321/categories/news
|
||||
agent-browser screenshot output/category.png --full
|
||||
|
||||
# Static page
|
||||
agent-browser open http://localhost:4321/pages/about
|
||||
agent-browser screenshot output/page.png --full
|
||||
|
||||
# 404 page
|
||||
agent-browser open http://localhost:4321/nonexistent
|
||||
agent-browser screenshot output/404.png --full
|
||||
```
|
||||
|
||||
## 6.4 Compare & Iterate
|
||||
|
||||
Compare each screenshot pair:
|
||||
|
||||
| Page Type | Reference | Output |
|
||||
| ----------- | --------------------------------------- | ------------------------ |
|
||||
| Homepage | `discovery/screenshots/homepage.png` | `output/homepage.png` |
|
||||
| Single Post | `discovery/screenshots/single-post.png` | `output/single-post.png` |
|
||||
| Archive | `discovery/screenshots/archive.png` | `output/archive.png` |
|
||||
| Category | `discovery/screenshots/category.png` | `output/category.png` |
|
||||
| Page | `discovery/screenshots/page.png` | `output/page.png` |
|
||||
| 404 | `discovery/screenshots/404.png` | `output/404.png` |
|
||||
|
||||
For each page, identify differences and fix:
|
||||
|
||||
1. **Layout** - CSS grid/flexbox, content width, spacing
|
||||
2. **Typography** - Font family, sizes, line height
|
||||
3. **Colors** - Background, text, links, borders
|
||||
4. **Components** - Headers, footers, cards, buttons
|
||||
5. **Responsive** - Check mobile viewport too
|
||||
|
||||
Re-screenshot after each round of fixes.
|
||||
|
||||
**Don't aim for pixel-perfect** - aim for "same design language."
|
||||
|
||||
## 6.5 Final Build Test
|
||||
|
||||
```bash
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
## License Compliance
|
||||
|
||||
WordPress themes are GPL-licensed. Every ported theme needs:
|
||||
|
||||
1. **LICENSE** - GPL-2.0 text (download with curl, don't output directly):
|
||||
|
||||
```bash
|
||||
curl -o LICENSE https://raw.githubusercontent.com/spdx/license-list-data/main/text/GPL-2.0-or-later.txt
|
||||
```
|
||||
|
||||
2. **README.md** - Credits to original theme
|
||||
|
||||
3. **package.json** - `"license": "GPL-2.0-or-later"`
|
||||
Reference in New Issue
Block a user