From superpowers-sage
Provides Eloquent ORM models, migrations, relationships, factories, and scopes for custom tables and WP core mirrors via Acorn in WordPress. Use for app data beyond WP core functions.
npx claudepluginhub codigodoleo/superpowers-sage --plugin superpowers-sageThis skill uses the workspace's default tool permissions.
| Use case | Use Eloquent | Use WordPress functions |
Guides Laravel migrations and factories with safe schema change rules, model pairing, seeding practices, and DB testing using RefreshDatabase.
Provides expert Laravel patterns for PHP 8.2+ including Eloquent ORM best practices, N+1 prevention, efficient queries, atomic operations, query optimization, and RESTful API controllers.
Executes safe WordPress data migrations to Sage/Acorn via 7-phase process: snapshot-before, dry-run, human approval, gates, apply, verify, idempotency checks.
Share bugs, ideas, or general feedback.
| Use case | Use Eloquent | Use WordPress functions |
|---|---|---|
| Custom tables (event logs, testimonials, form entries) | Yes | No |
| Complex joins across custom tables | Yes | No |
| Relationships between custom models | Yes | No |
| Post types, taxonomies, menus | No | Yes (WP_Query, get_posts) |
| User management, roles, capabilities | No | Yes (wp_insert_user, get_userdata) |
| Options, transients | No | Yes (get_option, get_transient) |
Complex read queries on wp_posts | Read-only, carefully | Prefer WP_Query first |
Rule: WordPress-managed content goes through WordPress functions so hooks fire. Custom application data goes through Eloquent.
# Create a model (PascalCase name required)
bash skills/acorn-eloquent/scripts/create-model.sh Testimonial
# Create a model with a migration
bash skills/acorn-eloquent/scripts/create-model.sh EventLog --migration
# Run pending migrations
bash skills/acorn-eloquent/scripts/run-migration.sh
# Run with additional flags (passed through to lando acorn migrate)
bash skills/acorn-eloquent/scripts/run-migration.sh --seed
bash skills/acorn-eloquent/scripts/run-migration.sh --step=2
Scripts: scripts/create-model.sh · scripts/run-migration.sh
Models live in app/Models/. Always declare $table explicitly with the WordPress prefix.
class Testimonial extends Model
{
use HasFactory;
protected $table = 'wp_testimonials';
protected $fillable = ['author_name', 'company', 'body', 'rating', 'is_featured', 'published_at'];
protected $casts = [
'rating' => 'integer',
'is_featured' => 'boolean',
'published_at' => 'datetime',
'metadata' => 'array',
];
}
See references/models.md for:
$primaryKey, $keyType, $incrementing)Attribute::make()Boilerplate templates with {{PLACEHOLDER}} tokens:
$table, $primaryKey, $timestamps, $fillable, $casts. Replace {{CLASS_NAME}}, {{TABLE_NAME}}.$primaryKey = 'ID', $timestamps = false, write guards. Replace {{CLASS_NAME}}, {{WP_TABLE}}.lando acorn make:migration create_testimonials_table
lando acorn migrate
lando acorn migrate:status
lando acorn migrate:rollback
return new class extends Migration
{
public function up(): void
{
Schema::create('wp_testimonials', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id')->nullable();
$table->string('author_name');
$table->text('body');
$table->unsignedTinyInteger('rating')->default(5);
$table->boolean('is_featured')->default(false);
$table->timestamp('published_at')->nullable();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('wp_testimonials');
}
};
See references/migrations.md for:
class Testimonial extends Model
{
public function author(): BelongsTo
{
return $this->belongsTo(User::class, 'user_id');
}
public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class, 'wp_testimonial_tag', 'testimonial_id', 'tag_id');
}
}
Eager load to avoid N+1:
Testimonial::with('author', 'tags')->get();
See references/relationships.md for:
wp_posts → wp_postmeta (hasMany with ID key)wp_terms → wp_termmetawp_users for read-only relationshipspublic function scopePublished(Builder $query): void
{
$query->whereNotNull('published_at')
->where('published_at', '<=', now());
}
public function scopeMinRating(Builder $query, int $rating): void
{
$query->where('rating', '>=', $rating);
}
Chain fluently:
Testimonial::published()->featured()->minRating(4)->with('author')->get();
See references/query-scopes.md for:
booted() registrationwithoutGlobalScope() usage->when()lando acorn make:factory TestimonialFactory
class TestimonialFactory extends Factory
{
protected $model = Testimonial::class;
public function definition(): array
{
return [
'author_name' => fake()->name(),
'body' => fake()->paragraphs(2, asText: true),
'rating' => fake()->numberBetween(1, 5),
'is_featured' => fake()->boolean(20),
'published_at' => fake()->optional(0.8)->dateTimeBetween('-1 year'),
];
}
}
Testimonial::factory()->count(10)->create();
Testimonial::factory()->featured()->count(3)->create();
Seed:
lando acorn db:seed --class=TestimonialSeeder
See references/factories.md for:
featured(), unpublished())fake() helper referenceDatabaseSeeder registration$timestamps = false for WP core tables (wp_posts, wp_users) — they have no created_at/updated_at.$table explicitly for every model — avoid Eloquent's table name guessing with WP prefix.wp_insert_post(), wp_update_post(), update_post_meta() so hooks fire.lando acorn migrate — never write raw SQL directly.$fillable explicitly — never use $guarded = []; list only known, safe attributes.::with() or ->load() to prevent N+1 queries in loops.lando acorn migrate:status and confirm all migrations show as "Ran".lando acorn tinker to verify: App\Models\Testimonial::first() returns data from the correct table.App\Models\Testimonial::with('author')->first() returns related data without errors.See references/troubleshooting.md for all failure modes and escalation paths.
Deep content loaded on demand — zero tokens until needed.
$table, $fillable, $casts, custom primary key, $timestamps = false for WP tables, accessors.Schema::create, column types reference, up()/down(), running via lando acorn migrate.hasMany, belongsTo, belongsToMany, WP-specific: Post → PostMeta, Term → TermMeta, polymorphic.HasFactory, definition(), fake() reference, states, seeding with lando acorn db:seed.withoutGlobalScope(), conditional ->when(), raw queries.wp_posts, wp_postmeta, etc.), read-only reporting, canonical patterns.superpowers-sage:wp-performance for eager loading strategies.wp_insert_post(), update_post_meta(), wp_insert_user().