Skip to content

Michael LaRoy - Home

WordPress and Laravel: What is a Post?


I have been a developer in the WordPress space for many years now, but Laravel has come to occupy my thoughts more and more lately. Trying to articulate just how they are similar or different is a tall order, but in order to gain an understanding of these similarities and differences, one must begin somewhere.

To start with, out of the box WordPress is a full-on Content Management System, whereas Laravel is a highly configurable web framework that doesn’t provide very much for you without some kind of starter package. WordPress has pages, posts, media, comments, and more, whereas Laravel has… nothing?

Not quite nothing, as it turns out. Rather, it has the building blocks to create all of that and more, just the way you want it, and probably in a better fashion, depending on your needs. But before we get into that, let’s review how WordPress stores all of the kinds of information listed above.

The WordPress “Post”

When you open up a database for a WordPress site, you will see a table called “wp_posts,” which is where every piece of content is stored. It has columns for fields like the title, post content, publish dates, and more. Plus, it has a special column called “post_type” which reveals what “type” of content a given post might be.

If we follow the logic, this tells us that within WordPress, each kind of content mentioned above is considered a “post” with a specific “post_type” value, such as “page”, “post” (as in “blog post”), “nav_menu_item”, even media items which are an “attachment.”

A single database table is used to store all of the content in the website. To even create the post type in the first place, we need to call a function in PHP that hooks into WordPress’ startup actions, and ensures the post type will be “registered” if it hasn’t yet been.

Consider the following code:

function register_tshirt_post_type() {
    $args = array(
        'public' => true,
        'label'  => 'T-Shirts',
        'supports' => array('title', 'editor', 'thumbnail')
        // etc.
    );

    register_post_type('tshirt', $args);
}
add_action('init', 'register_tshirt_post_type');

This is a simplistic example of how a post type gets defined in our WordPress site, but essentially we can give an array of arguments to tell it how to look and behave in certain areas of our app when initializing it.

To reference any given kind of content (like a T-shirt, for instance), we can envision a database query like the following:

SELECT *
FROM wp_posts
WHERE post_type = 'tshirt'
AND post_status = 'publish';

To retrieve some of this data with the WP_Query class that WordPress gives us, it might look something like this:

$args = array(
    'post_type' => 'tshirt',
    'publish' => true
    // etc.
)

$tshirts_query = new WP_Query( $args );

foreach( $tshirts_query->posts as $tshirt) {
    // do stuff
}

Besides this, there is a “wp_postmeta” table which is meant to keep “meta” information about a given post with a key/value-style association, which references the ID of the post in a separate column.

It gets a little more complicated in the DB when we use a plugin like Advanced Custom Fields, but the tradeoff is the simplicity in our code.

Let’s retrieve some metadata. Let’s get the color of our imagined T-shirt product.

In our template code, we can use functions provided by ACF to retreieve that data without dropping into our database directly, but would require a separate query:


foreach( $tshirts_query->posts as $tshirt) {
    // get some meta data
    $color = get_field('color', $tshirt['id']);
    echo '<li>' . $color . '</li>';
}

That separate query might look something like this:

SELECT meta_key, meta_value
FROM wp_postmeta
WHERE post_id = 7
AND meta_key IN ('color');

It is possible to incorporate the meta query into the previous query (for those of you who wish to point that out), but I want to illustrate that either way, we are referencing different tables for that information.

⚠️

I’m confident these query examples aren’t exactly how WordPress might do it under the hood. No doubt they will get more complicated or convoluted depending on the structure of the data involved; I wrote them this way for the sake of clarity for these concepts.

The Laravel “Model”

Let’s contrast this to how Laravel works. Rather than a single table that contains all of the content types, where a “post_type” column will differentiate the kinds of content there, Laravel has the concept of a “Model,” where each content Model has its own database table and corresponding PHP class.

Laravel provides a base Model class that has certain properties and abilities, which we would then extend when creating our Tshirts model:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Tshirt extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'tshirts';

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['title', 'description', 'color', 'is_published'];

    // Add any other model properties or methods you need here
}

Typically, we would run a migration on the database to add the appropriate fields (title, description, color, etc.) to the table in the database. In addition, we can run an artisan command in our Terminal to generate this Model code, migrations, controllers (and more) for us all at once, but we’ll save that for a separate topic. For now, let’s assume that’s been done already.

In Laravel, the Eloquent ORM provides our way of accessing the database in our controllers. Consider this code from the tshirt controller:

$tshirts = Tshirt::where('is_published', true)->get();

Perhaps this might translate into a query like the following:

SELECT *
FROM tshirts
WHERE is_published = true;

And then a Blade template might look like:

@foreach( $tshirts as $shirt)
    <li>{{ $shirt->color }}</li>
@endforeach

Which one is better?

In our analysis, we’ve seen WordPress treats all content types as “posts” in a single database table, simplifying content management but potentially complicating customization. Laravel, in contrast, allows for distinct database tables per content type through its Model system, offering precision and flexibility in data architecture. This distinction underscores WordPress’s ease of use for straightforward projects versus Laravel’s adaptability for customized solutions.

With WordPress, can have us up and running with posts, pages, and media in minutes. We have a handy way to interact with the database via WP_Query right inside our template if we wish, or in a function elsewhere in the theme or plugin.

With Laravel, we have an optimized environment for moulding the data and wielding it any way we want. Structuring our data from the ground up ensures we only have that which we need in our database, and we can separate out Models into their own tables. Querying the database feels a little more expressive, closer to the SQL, thanks to Eloquent.

Is one more better than the other for your project? No doubt there are a lot more factors to consider than our content modelling in order to make that call. What are the things that are important for your project?

Jimmy Fallon: "your choice"

5 Accessibility Fixes You Can Make Today

Learn about the most common reasons that websites fail accessibility standards, and what you can do about it.