Getting started with Corcel

Corcel is a PHP package that allows using WordPress as a (headless) content management system for your application. Corcel communicates directly with the WordPress MySQL database using CRUD operations to manage posts, pages, custom post types, and basically all other data stored inside the WordPress database.

In this post, I'm using Corcel to create a simple blog as a part of a Laravel application with WordPress as the CMS. This setup makes it possible to manage your posts within the WordPress admin interface while using a Laravel application and Corcel to query and render the content.

Installing Corcel in a Laravel project

Require the latest version of Corcel via Composer:

composer require jgrossi/corcel

And publish the Corcel configuration file:

php artisan vendor:publish --provider="Corcel\Laravel\CorcelServiceProvider"

You can customize the name of the database connection in the configuration file:

config/corcel.php
'connection' => 'wordpress',

Add the additional database connection to the connections[] in your database configuration file:

config/database.php
'wordpress' => [
    'driver'    => 'mysql',
    'host'      => env('WP_DB_HOST', '127.0.0.1'),
    'database'  => env('WP_DB_DATABASE', 'forge'),
    'username'  => env('WP_DB_USERNAME', 'forge'),
    'password'  => env('WP_DB_PASSWORD', ''),
    'charset'   => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix'    => env('WP_DB_PREFIX', 'wp_'),
    'strict'    => false,
    'engine'    => null,
],

Make sure to define the environment variables WP_DB_HOST, WP_DB_DATABASE, WP_DB_USERNAME, WP_DB_PASSWORD, WP_DB_PREFIX in your .env file.

Usage

Let's start making use of Corcel by building a simple blog based on the WordPress database. Following the logic of WordPress, the blog consists of individual posts.

The first step is to create a Post model which extends Corcel\Model\Post. This step is optional but provides extra flexibility once you need to add custom methods for example view presenters. You can also use Corcel\Model\Post directly.

php artisan make:model Post
app/Models/Post.php
use Corcel\Model\Post as Corcel;
class Post extends Corcel
{
    protected $postType = 'post';
}

Next, create the corresponding PostsController:

php artisan make:controller PostsController

Corcel is built on top of the Laravel Eloquent ORM to interacting with the database. In the index() method, get the newest five public posts from the WordPress database and paginate the results using Eloquents paginate() method. In the show() method get the post from the $slug:

app/Http/Controllers/PostsController.php
use App\Models\Post;
use Illuminate\Contracts\View\View;
public function index(): View
{
    return view('posts.index', [
        'posts' => Post::published()->newest()->paginate(5),
    ]);
}
public function show(string $slug): View
{
    return view('posts.show', [
        'post' => Post::slug($slug)->status('publish')->firstOrFail(),
    ]);
}

To access the view, let's add the routes for the blog overview and the single blog posts in the routes file referencing the methods in the PostsController:

routes/web.php
use App\Http\Controllers\PostsController;
use Illuminate\Support\Facades\Route;
Route::get('/blog', [PostsController::class, 'index'])->name('posts.index');
Route::get('/blog/{post:slug}', [PostsController::class, 'show'])->name('posts.show');

In the Laravel Blade front-end template for the index view, loop through the list of posts and display the pagination links using the links() method:

resources/views/posts/index.blade.php
@foreach($posts as $post)
  <a href="{{ route('posts.show', $post ) }}">
    {{ $post->post_title }}
  </a>
@endforeach
{{ $posts->links() }}

Use Cases

WordPress is a widely used CMS. As a developer, you may find it helpful to use built-in and well-tested features (uploads, comments) in addition to the far-ranging ecosystem (page builder, custom fields) without losing the flexibility of a PHP framework like Laravel.

Corcel supports all WordPress post types, including author, taxonomies, attachments, comments, options, users, and even Advanced Custom Fields. Corcel is a full-featured solution to use WordPress as your content management system in the background.

The best part is, this approach also works backward: You can update the WordPress database every time something happens in your application!


Headless WordPress

If you are using WordPress as a decoupled or headless CMS, I recommend the WordPress plugin Headless Mode. The plugin blocks all requests to the WordPress site if the request is not part of a CRON, REST, GraphQL, or admin request (logged-in user). With the plugin installed, you can still use the wp-admin part of WordPress and entirely disable (redirect) the front-end requests.

How do I use Headless Mode?

Activate the plugin and add the constant HEADLESS_MODE_CLIENT_URL to your wp-config.php file. If the (logged-in) user doesn't have the capability of edit_posts a redirect happens:

wp-config.php
define('HEADLESS_MODE_CLIENT_URL', 'https://hofmannsven.com');

How can I entirely disable the WordPress front-end?

To also redirect logged-in users, return true in the filter. The setting disables the front-end entirely and redirects all users:

functions.php
add_filter('headless_mode_disable_front_end', '__return_true');

How do I handle WordPress file uploads?

WordPress is storing the absolute path in the database. To not leak the URL of your CMS, use a subdomain or CDN for your uploads.

You can change the upload path using the pre_option_{$option} hook. Links to images and attachments inside of the $post->post_content are now served from the subdomain or CDN:

functions.php
add_filter('pre_option_upload_path', function($upload_path) {
    return '/path/to/your/uploads';
});
add_filter('pre_option_upload_url_path', function($upload_url_path) {
    return 'https://cdn.hofmannsven.com';
});