--- name: wordpress-sage-theme description: '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.' allowed-tools: Read, Write, Bash, Glob, Grep --- # 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')

{{ the_title() }}

{{ the_content() }}
@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 {{ wp_head() }} @yield('content') {{ wp_footer() }} ``` ### 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')

{{ the_title() }}

{{ the_content() }}
@endsection ``` ### Components **Reusable Button Component** (`resources/views/components/button.blade.php`): ```blade @props(['url' => '#', 'text' => 'Click', 'variant' => 'primary']) {{ $text }} ``` **Usage**: ```blade ``` ## ACF Integration ### Displaying ACF Fields **Basic Field**: ```blade @while(the_post())

{{ get_field('hero_title') ?? the_title() }}

{{ get_field('hero_description') }}

@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'))
@while (have_rows('testimonials')) @php the_row() @endphp

{{ get_sub_field('testimonial_text') }}

{{ get_sub_field('author_name') }}
@endwhile
@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

{{ the_title() }}

@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, cards, and other repeated elements - **Keep layouts minimal**: Base layouts should only contain structural HTML; delegate styling to components - **Leverage Blade directives**: Use `@include`, `@each`, and `@component` for better code organization - **Avoid inline PHP**: Use `@php` blocks sparingly; move complex logic to Composers or service classes ### ACF Field Management - **Group related fields**: Use ACF field groups to organize fields logically by content type - **Use field keys for references**: When referencing fields programmatically, use field keys (e.g., `field_12345678`) for reliability - **Implement fallback values**: Always provide default values for optional fields to prevent empty output - **Cache expensive queries**: Use WordPress transients for complex ACF queries on high-traffic pages ### Asset Management - **Use Bud for asset compilation**: Let Bud handle versioning and optimization instead of manual asset management - **Minimize HTTP requests**: Combine CSS/JS files where appropriate using Bud's entry points - **Optimize images**: Use WordPress image sizes and lazy loading; consider WebP conversion - **Cache busting**: Bud automatically handles cache busting via manifest.json ### Code Organization - **Use Composers for data**: Move data retrieval logic from templates to Sage Composers (`app/View/Composers/`) - **Separate concerns**: Keep business logic in service classes, presentation in Blade templates - **Follow WordPress coding standards**: Maintain consistency with WordPress PHP coding standards - **Use type declarations**: PHP 8.0+ allows typed properties and arguments for better code quality ### Security Considerations - **Escape all output**: Use `{{ }}` (Blade auto-escapes) or WordPress functions like `esc_html()`, `esc_url()` - **Validate ACF input**: Sanitize and validate custom field inputs on the backend - **Nonce verification**: Always verify nonces for form submissions - **Capability checks**: Use `current_user_can()` before privileged operations ## Constraints and Warnings ### Version Requirements - **PHP 8.0+ required**: Sage 10 requires PHP 8.0 or higher; earlier versions are not supported - **Node.js 18+ required**: Build tools require modern Node.js; older versions may cause compilation errors - **WordPress 6.0+ recommended**: While Sage works with WordPress 5.x, version 6.0+ is recommended for full feature support - **Composer required**: Dependency management requires Composer; manual installation is not supported ### Build Tool Limitations - **Hot reload limitations**: Bud's hot reload may not work correctly with some WordPress multisite configurations - **Production builds required for testing**: Some features work differently in development vs production; always test with `npm run build` before deployment - **Manifest.json dependency**: Theme relies on `public/manifest.json`; missing this file breaks asset loading ### Common Pitfalls - **Template hierarchy confusion**: Sage uses Blade files but follows WordPress template hierarchy; ensure file names match WordPress expectations - **Direct file access**: Do not access Blade files directly via URL; they must be rendered through WordPress - **Plugin conflicts**: Some caching and security plugins may interfere with Bud's hot reload or asset serving - **Theme updates**: Updating Sage via Composer may overwrite customizations; use child themes for extensive modifications ### Performance Considerations - **ACF Repeater performance**: Large repeater fields can impact page load; consider pagination or alternative storage for large datasets - **Blade compilation overhead**: First load after cache clear compiles all templates; use OPcache in production - **Asset bundle size**: Monitor compiled asset sizes; large bundles affect page load performance - **Database queries**: Use Query Monitor plugin to identify and optimize expensive queries in theme templates ### Deployment Constraints - **Build step required**: Production deployments must run `npm run build`; raw source files cannot be served - **Environment-specific configuration**: Bud configuration may need adjustment for different deployment environments - **File permissions**: Ensure `public/` directory is writable during builds; incorrect permissions cause build failures