corcel/woocommerce
Corcel WooCommerce brings WooCommerce data into Laravel’s Eloquent ORM. Query products, orders, customers, coupons, and related WordPress/WooCommerce records using familiar models, relationships, and queries—without leaving your Laravel application.
This release is primarily a compatibility release: v6.0.0 adds Laravel 12 support and Corcel v9 support. There are no new day-to-day APIs described, so the main action is to verify your Laravel/PHP/Corcel version matrix before upgrading.
Minimal steps:
composer require <vendor>/<package>:^6.0
config/database.php. Do not point this at your Laravel application database unless WordPress and Laravel intentionally share one.// config/corcel.php or equivalent package config
'connection' => 'wordpress',
'table_prefix' => 'wp_',
$posts = Corcel\Models\Post::published()
->with('meta')
->latest('post_date')
->paginate(20);
The first thing to validate after upgrading is that the package can resolve the WordPress connection and hydrate a basic Post model. If that works, most other features are variations on the same Eloquent-over-WordPress-schema pattern.
Treat the package as an Eloquent adapter over the WordPress schema, not as a replacement for WordPress itself.
Keep the WordPress connection isolated:
// config/database.php
'wordpress' => [
'driver' => 'mysql',
'host' => env('WP_DB_HOST'),
'database' => env('WP_DB_DATABASE'),
'username' => env('WP_DB_USERNAME'),
'password' => env('WP_DB_PASSWORD'),
'prefix' => '',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
],
Then wrap package models in application-level models or repositories so you do not spread WordPress-specific assumptions through controllers:
namespace App\Models\WordPress;
class Post extends \Corcel\Models\Post
{
protected $connection = 'wordpress';
}
This gives you one place to add scopes, casts, accessors, and eager-loading defaults.
The common daily pattern is defining a small model per custom post type:
class CaseStudy extends \Corcel\Models\Post
{
protected $postType = 'case_study';
}
Use similar thin wrappers for taxonomies and terms. Keep business logic in services or query objects rather than in the WordPress model subclasses.
Use Eloquent normally, but eager-load relationships deliberately:
$posts = Post::published()
->with(['meta', 'taxonomies', 'terms', 'attachment'])
->latest('post_date')
->paginate(20);
For API endpoints, prefer explicit query objects or scopes:
final class PublishedPostsQuery
{
public function handle(int $perPage = 20)
{
return Post::query()
->where('post_status', 'publish')
->where('post_type', 'post')
->with('meta')
->orderByDesc('post_date')
->paginate($perPage);
}
}
WordPress content is stored as HTML/markup. In Laravel views, render it intentionally:
{!! $post->content !!}
Only do this for trusted editorial content. If content can come from untrusted authors, sanitize it before rendering.
For WordPress-style formatting, decide explicitly whether to apply paragraph formatting, shortcode expansion, or neither. Do not assume Corcel applies the full WordPress rendering pipeline.
WordPress reads are often slower than native Laravel queries because of post/meta joins. Cache list pages and expensive meta lookups:
$posts = Cache::remember("wp.posts.page.{$page}", 300, fn () => $query->handle());
Invalidate by time or by a WordPress-side webhook/event. Avoid caching user-specific or draft content without a per-user key.
You can read WordPress users through the package, but do not assume Laravel authentication will “just work.” WordPress password hashes and Laravel’s hasher are different. The safe pattern is:
password column without a verification strategy.If you use WordPress multisite, isolate site switching in a service or middleware. Do not scatter switch_to_blog-style logic across controllers. Cache keys and model scopes should include the site identifier.
The headline changes are Laravel 12 and Corcel v9 support. Before upgrading:
The package reads and sometimes writes WordPress tables. Those tables are owned by WordPress. Use WordPress migrations/plugins or explicit SQL changes for schema, not Laravel migrations.
Symptoms: “table not found,” empty results, or queries hitting the wrong tables. Verify:
prefix setting.wp_ prefix or a custom one.Many teams use this package read-only. If that is your intent, use a database user with SELECT only. If you allow writes, test post/meta/term writes carefully: WordPress stores serialized data and maintains its own invariants that Eloquent will not enforce.
Post meta is stored in a key/value table. Filtering by multiple meta keys often produces expensive joins. For high-traffic endpoints:
meta_query-style filtering in public APIs.Some meta values are PHP-serialized. Do not treat every meta value as a scalar string. If the package does not already deserialize a field, handle it explicitly and fail safely on malformed data.
Shortcodes, blocks, embeds, and wpautop formatting may not be applied by the package. If your frontend depends on WordPress rendering, define a rendering layer or call WordPress rendering endpoints rather than assuming the package reproduces it.
WordPress uses columns such as post_date, post_date_gmt, and post_modified. Do not assume Laravel’s created_at/updated_at conventions apply. Cast and format dates explicitly in API resources.
Attachment models expose WordPress metadata, but public URLs depend on your WordPress upload directory and domain configuration. Centralize attachment URL generation in a helper or presenter rather than reconstructing paths in views.
Use a dedicated test WordPress database or a schema fixture. Do not rely on SQLite: the WordPress schema and MySQL-specific behavior are part of the contract. For CI, seed a minimal set of posts, terms, and meta rows.
How can I help you explore Laravel packages today?