From superpowers-sage
Implements Livewire v3 in WordPress Sage themes via Acorn for reactive components, real-time UI updates, forms with validation, pagination, and file uploads without JavaScript.
npx claudepluginhub codigodoleo/superpowers-sage --plugin superpowers-sageThis skill uses the workspace's default tool permissions.
| Approach | Best for |
Manages Roots Sage WordPress themes with Acorn and Lando: environment setup, ACF blocks/fields, Blade components/composers, Tailwind v4/Vite frontend, service providers, CPTs, and generators.
Develops WordPress themes using Sage framework: create from scratch, set up Blade templates/components, configure Vite/Bud builds, handle template hierarchy, integrate ACF fields, manage assets.
Builds reactive server-rendered Twig components in Symfony PHP that re-render via AJAX on user interactions for live search, dynamic forms, real-time validation, and polling without JavaScript.
Share bugs, ideas, or general feedback.
| Approach | Best for |
|---|---|
| Livewire | Interactive server-driven UI, forms with validation, real-time filtering, pagination, file uploads |
| Blade Component | Static display, no interactivity |
| Alpine.js | Client-only UI (dropdowns, modals, tabs) — no server needed |
| REST API + JS | High-frequency updates (> 1/sec), large datasets, offline support |
| ACF Block | Editor-managed Gutenberg content |
roots/acorn-livewire and livewire/livewire installedlando theme-composer require roots/acorn-livewire livewire/livewire
lando acorn vendor:publish --tag=livewire:config
Add to resources/views/layouts/app.blade.php:
<head>
@livewireStyles
...
</head>
<body>
...
@livewireScripts
</body>
# Check installed versions
bash skills/acorn-livewire/scripts/check-versions.sh
# Create a component (validates PascalCase, checks lando availability)
bash skills/acorn-livewire/scripts/create-component.sh ContactForm
# → app/Livewire/ContactForm.php
# → resources/views/livewire/contact-form.blade.php
Use the component in any Blade template:
<livewire:contact-form />
<livewire:contact-form :post-type="$postType" />
class PostSearch extends Component
{
public string $query = '';
public function mount(string $postType = 'post'): void
{
// wp_set_current_user(get_current_user_id()); // if WP user context needed
$this->postType = $postType;
}
#[Computed]
public function posts(): array
{
return get_posts(['s' => $this->query, 'posts_per_page' => 10]);
}
public function render(): \Illuminate\View\View
{
return view('livewire.post-search');
}
}
{{-- resources/views/livewire/post-search.blade.php --}}
<div> {{-- single root element required --}}
<input wire:model.live.debounce.300ms="query" placeholder="Search..." />
@forelse ($this->posts as $post)
<a href="{{ get_permalink($post) }}">{{ $post->post_title }}</a>
@empty
<p>No results.</p>
@endforelse
</div>
| Directive | When to use |
|---|---|
wire:model="name" | Default — syncs on form submit (no extra requests) |
wire:model.live="name" | Real-time — sends request on every keystroke |
wire:model.blur="name" | Field-level validation on focus loss |
wire:model.live.debounce.300ms="name" | Real-time search (debounced) |
# Create a Livewire component (PascalCase name required)
bash skills/acorn-livewire/scripts/create-component.sh <ComponentName>
# Check package versions (Livewire, Acorn, PHP)
bash skills/acorn-livewire/scripts/check-versions.sh
Scripts: scripts/create-component.sh · scripts/check-versions.sh
Boilerplate templates with {{PLACEHOLDER}} tokens. Copy and replace placeholders.
extends Component, WithPagination commented out, mount() stub, wp_set_current_user stub, render().<div> root, wire:loading spinner, wire:model input example, Tailwind v4 note.Deep content loaded on demand — zero tokens until needed.
@livewireStyles/@livewireScripts, layout setup, Blade tag syntax, View Composer data passing, sage-html-forms comparison.wire:model variants, #[Computed] properties, lifecycle hooks (mount, hydrate, updated), loading states, Form objects (v3), component events.$wire.entangle, combining Alpine + Livewire, $wire.propertyName, Tailwind v4 coordination, dynamic class names, skeleton loaders.WithFileUploads trait, media_handle_sideload(), Lando storage paths, S3 driver, temporary file cleanup, validation rules.<div>, 404 on Livewire endpoint, wire:model not syncing.wire:click, wire:submit, or wire:model bindings and confirm the component updates reactively without a full page reload.app/Livewire/ with namespace App\Livewire. Tag convention: ContactForm → <livewire:contact-form />. Always generate with lando acorn make:livewire.WP_Post, closures, resource handles).#[Computed] for derived data. See references/common-errors.md.For all other failure modes (419 CSRF, Alpine conflicts, 404 on Livewire endpoint) see references/common-errors.md.
<div>. Livewire requires exactly one root element per component view — multiple roots or naked text break hydration.lando acorn make:livewire — never create component files manually. The generator sets correct namespaces, file paths, and naming conventions.wire:model.live for real-time; wire:model for form submit. Each .live event is an HTTP request. Default to wire:model and use .live only when the UX genuinely requires instant server feedback.wp_set_current_user for user context. If the component calls current_user_can() or any WP function that relies on the current user, call wp_set_current_user(get_current_user_id()) in mount().#[Computed] for post lists and other derived data.references/alpine-interop.md.@livewireStyles in <head>, @livewireScripts before </body>. Both are required. Missing either causes Livewire to silently fail.Before creating or referencing a Livewire component, query the live environment:
discover-abilities
execute-ability livewire/components
Use real class names from the query. Do not invent component names.
If the stack is not installed, run /ai-setup first.
See sageing/references/mcp-query-patterns.md for the full pattern.