wordpress-sage-theme
Provides WordPress theme development patterns using Sage (roots/sage) framework. Use when creating, modifying, or debugging WordPress themes with Sage, including (1): creating new Sage themes from scratch, (2): setting up Blade templates and components, (3): configuring build tools (Vite, Bud), (4): working with WordPress theme templates and hierarchy, (5): implementing ACF fields integration, (6): theme customization and asset management.
What this skill does
# WordPress Sage Theme Development
## Overview
Sage is a WordPress theme framework by Roots that provides modern development practices including Blade templates, dependency management with Composer, and build tools with Vite/Bud.
## When to Use
- Creating new Sage themes from scratch or from composer templates
- Setting up Blade templates, layouts, and reusable components
- Configuring build tools (Bud/Vite) for asset compilation
- Working with WordPress template hierarchy in Blade format
- Integrating Advanced Custom Fields (ACF) with Blade templates
- Debugging theme rendering, asset loading, or build issues
## Instructions
1. **Set up the environment**: Install PHP 8.0+, Node.js 18+, Composer, and create a new Sage theme with `composer create-project roots/sage`
2. **Configure build tools**: Run `npm install && composer install`, then configure `bud.config.js` for asset entries and Tailwind
3. **Create Blade templates**: Place templates in `resources/views/`, using layouts in `layouts/`, components in `components/`
4. **Wire up WordPress templates**: Map WordPress template hierarchy to Blade files (e.g., `page.blade.php` for page templates)
5. **Integrate ACF fields**: Use `get_field()` for basic fields, `have_rows()` loops for repeaters and flexible content
6. **Build and verify**: Run `npm run build`, verify `public/manifest.json` exists, check browser console for asset errors
7. **Deploy**: Ensure the production build step (`npm run build`) runs during deployment; raw source files cannot be served directly
## Examples
**Create a new Sage theme:**
```bash
composer create-project roots/sage my-theme
cd my-theme
npm install && composer install
npm run dev
```
**Blade page template:**
```blade
@extends('layouts.app')
@section('content')
<main class="content">
<h1>{{ the_title() }}</h1>
<div class="entry-content">
{{ the_content() }}
</div>
</main>
@endsection
```
**ACF flexible content in Blade:**
```blade
@if (have_rows('flexible_content'))
@while (have_rows('flexible_content'))
@php the_row() @endphp
@switch(get_row_layout())
@case('hero_section')
@include('components.hero')
@break
@endswitch
@endwhile
@endif
```
## Quick Start
### Creating a New Sage Theme
**Prerequisites**: PHP 8.0+, Node.js 18+, Composer
```bash
# Create new Sage theme
wp scaffold theme-theme my-theme --theme_name="My Theme" --author="Your Name" --activate
# Or install Sage directly via Composer
composer create-project roots/sage my-theme
cd my-theme
# Install dependencies
npm install
composer install
# Build for development
npm run dev
# Build for production
npm run build
```
### Directory Structure
```
resources/
├── views/ # Blade templates
│ ├── layouts/ # Base layouts (app.blade.php)
│ ├── components/ # Reusable components
│ └── partials/ # Template partials
├── styles/ # CSS/SASS files
│ └── main.scss # Main stylesheet
└── scripts/ # JavaScript files
└── main.js # Main JavaScript
```
## Blade Templates
### Layouts
**Base Layout** (`resources/views/layouts/app.blade.php`):
```blade
<!DOCTYPE html>
<html {{ site_html_language_attributes() }}>
<head>
{{ wp_head() }}
</head>
<body {{ body_class() }}>
@yield('content')
{{ wp_footer() }}
</body>
</html>
```
### Template Hierarchy Mapping
| WordPress Template | Sage Blade File |
|-------------------|-----------------|
| front-page.php | `views/front-page.blade.php` |
| single.php | `views/single.blade.php` |
| page.php | `views/page.blade.php` |
| archive.php | `views/archive.blade.php` |
| index.php | `views/index.blade.php` |
**Example Page Template** (`resources/views/page.blade.php`):
```blade
@extends('layouts.app')
@section('content')
<main class="content">
<h1>{{ the_title() }}</h1>
<div class="entry-content">
{{ the_content() }}
</div>
</main>
@endsection
```
### Components
**Reusable Button Component** (`resources/views/components/button.blade.php`):
```blade
@props(['url' => '#', 'text' => 'Click', 'variant' => 'primary'])
<a href="{{ $url }}" class="btn btn-{{ $variant }}">
{{ $text }}
</a>
```
**Usage**:
```blade
<x-button url="/contact" text="Contact Us" variant="secondary" />
```
## ACF Integration
### Displaying ACF Fields
**Basic Field**:
```blade
@while(the_post())
<h1>{{ get_field('hero_title') ?? the_title() }}</h1>
<p>{{ get_field('hero_description') }}</p>
@endwhile
```
**Flexible Content**:
```blade
@if (have_rows('flexible_content'))
@while (have_rows('flexible_content'))
@php the_row() @endphp
@switch(get_row_layout())
@case('hero_section')
@include('components.hero')
@break
@case('features_grid')
@include('components.features-grid')
@break
@endswitch
@endwhile
@endif
```
**Repeater Field**:
```blade
@if (have_rows('testimonials'))
<div class="testimonials">
@while (have_rows('testimonials'))
@php the_row() @endphp
<blockquote>
<p>{{ get_sub_field('testimonial_text') }}</p>
<cite>{{ get_sub_field('author_name') }}</cite>
</blockquote>
@endwhile
</div>
@endif
```
## Build Configuration (Bud)
### Tailwind CSS Setup
**Install Tailwind**:
```bash
npm install -D tailwindcss
npx tailwindcss init -p
```
**Configure** (`bud.config.js`):
```js
export default async (app) => {
app
.entry({
app: ['@/scripts/main.js', '@styles/main.css'],
editor: ['@scripts/editor.js', '@styles/editor.css'],
})
.assets('images', 'fonts')
.tailwind()
.runtime()
};
```
**Tailwind CSS** (`resources/styles/main.css`):
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
.btn {
@apply px-4 py-2 rounded font-semibold transition;
}
.btn-primary {
@apply bg-blue-600 text-white hover:bg-blue-700;
}
}
```
## Advanced Patterns
### Conditional Logic
```blade
@if (is_front_page())
@include('components.hero')
@elseif (is_singular('post'))
@include('components.post-meta')
@endif
```
### Custom Queries
```blade
@php
$args = [
'post_type' => 'service',
'posts_per_page' => 6,
];
$query = new WP_Query($args);
@endphp
@if ($query->have_posts())
@while ($query->have_posts())
@php $query->the_post() @endphp
<article>
<h2>{{ the_title() }}</h2>
</article>
@endwhile
@php wp_reset_postdata() @endphp
@endif
```
### Theme Customization
**functions.php additions**:
```php
// Custom image sizes
add_image_size('hero-lg', 1920, 1080, true);
// Custom post types
add_action('init', function() {
register_post_type('service', [
'label' => 'Services',
'public' => true,
'has_archive' => true,
'supports' => ['title', 'editor', 'thumbnail'],
]);
});
```
## References
- **Sage Documentation**: See [sage.md](references/sage.md) for complete framework reference
- **Blade Templates**: See [blade.md](references/blade.md) for advanced Blade patterns
- **Bud Configuration**: See [bud.md](references/bud.md) for build tool configuration
- **ACF Integration**: See [acf.md](references/acf.md) for ACF field examples
## Troubleshooting
**Build workflow validation** (always run in order):
1. `npm run build` completes without errors
2. Verify `public/manifest.json` exists and contains asset entries
3. Test locally in browser before production push
4. Check browser console for asset 404 errors
**Build issues**:
```bash
# Clear cache
npm run clean
# Rebuild
rm -rf node_modules public
npm install
npm run build
# Validate build output
ls -la public/
cat public/manifest.json | head -20
```
**Blade not compiling**: Check `public/manifest.json` exists after build
**AC fields not showing**: Verify field names match exactly (case-sensitive)
## Best Practices
### Blade Template Organization
- **Use components for reusable UI elements**: Create blade components in `resources/views/components/` for buttons, cardsRelated in Web Dev
generating-lwc-components
IncludedLightning Web Components with PICKLES methodology and 165-point scoring. Use this skill when the user creates or edits LWC components, builds wire service patterns, or writes Jest tests for LWC. TRIGGER when: user creates/edits LWC components, touches lwc/**/*.js, .html, .css, .js-meta.xml files, or asks about wire service, SLDS, or Jest LWC tests. DO NOT TRIGGER when: Apex classes (use generating-apex), Aura components, or Visualforce.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Set up queries with useQuery, mutations with useMutation, configure QueryClient caching strategies, implement optimistic updates, and handle infinite scroll with useInfiniteQuery. Use when: setting up data fetching in React projects, migrating from v4 to v5, or fixing object syntax required errors, query callbacks removed issues, cacheTime renamed to gcTime, isPending vs isLoading confusion, keepPreviousData removed problems.
document-processor-api
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
nutrient-document-processing
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions. Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
accelint-nextjs-best-practices
IncludedNext.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.