Understanding WordPress through its database


WordPress uses a relational database with 12 default tables. Understanding their roles will help you understand the fundamental logic that WordPress runs on.

This article will explain the tables’ jobs. If you want to know the technical nitty-gritty of the database, check out the WordPress Database Description. It has all the details you could want and includes a nice table diagram.

Database prefixes

WordPress lets you define a prefix for your tables. This is so you can use 1 database for the tables of multiple WordPress websites. I don’t recommend it.

The default prefix is “wp_”. And that’s what I’ll use in this article. Just know that “wp_posts” could be “wp1_posts” or “wp_some_website_posts”.

WordPress Multisite

If you’re using a multisite install of WordPress, you’ll have additional tables. This article covers the base tables you’ll find in every WordPress installation.

The tables


Let’s start with an easy one. This table should be deprecated. It was used back when blogrolls were a thing. It was where that data was stored.

I’d be shocked if you ever use it. In fact, the associated feature is completely deprecated.


This is another easy-to-understand table. It’s the home for site-wide options.


Now we’re getting into the heart of the system. All standalone content is a “post” and is stored in this table. I say “standalone” because it includes blog posts and pages and even images. But it doesn’t include comments which need their associated post to make sense.

The table holds the main data about a post except for author (user) and taxonomy data. That information is stored relationally in their own tables.

Post types

If everything is in wp_posts, how do we know what is a post vs what is a page? The answer is post types. A page is a specific post type with a specific set of rules. A blog post is another post type – specifically “post”. You can create custom post types programmatically.


What if you have extra data that you want related to a post? It goes here. And it could be anything.

Want some examples?

Have a review site? The review score. Have a business directory? Addresses, phone numbers, websites, etc.

And you can store the data however you like. You could store a street address as text. You could put it all in a serialized array or as JSON.

Nothing in WordPress will use your custom data. You’ll be writing the functions that store and read the data. The only limitation is if you want the data to be queriable.


A home for your basic user account data.


What if you have extra data that you want related to a user? It goes here.

All of the “…meta” tables serve the same purpose.

Example: What if you want to add more social accounts to a user’s record? It would be kept here.


A home for your comment data.


What if you have extra data that you want related to a comment? It goes here.


To understand this, you have to understand taxonomies. A taxonomy is a type of grouping. WordPress has 2 built-in taxonomies: categories and tags.

Taxonomies are associated with post types. So blog posts have categories and tags, but pages don’t.

Terms are the specific taxonomy elements associated with specific posts.

An example should make this make sense. This article is a “post”. Categories are associated with posts. “Understanding WordPress” is a term in that taxonomy. It is associated with this post (and other posts). You would never display a list of a post’s taxonomies. But you do display a list of a post’s terms. This post’s category is at the top of the page and its tags are at the end of the article.

So what’s in this table?

Not much. This table has the terms’ basic data: ID, name, and slug. The relationship data is kept elsewhere.


What if you have extra data that you want related to a term? It goes here.

Example: I’ve seen sites color-code their categories. That color information would go in here.


This table stores the relationship between terms and posts. It’s little more than a term’s ID and a post/object ID.


This table is a little confusing. But it makes sense if you understand how WordPress worked 10 years ago.

Before 2015, WordPress would reuse terms in wp_terms. So if a term, say “Cleveland”, was a term in both categories and tags, there would only be 1 record for “Cleveland” in wp_terms. This table would record the data for the 2 separate implementations.

The field “term_taxonomy_id” stored an ID for the unique term/taxonomy relationship. The term “description” field is in this table (instead of in wp_terms) so you could have different descriptions for identical terms in different taxonomies. The same goes for “parent”. (Terms can be hierarchical.)

If you ignore term_taxonomy_id, the rest of the fields make sense. Just think of it as an extension of wp_terms.

Some takeaways

Before we get into what we can learn from this, let’s put the tables into 2 groups.

Group 1 is primary tables. There are 7 of them: wp_links, wp_options, wp_posts, wp_comments, wp_users, wp_terms, and wp_taxonomies. (Remember: it’s basically only 6 tables since wp_links isn’t used.)

Group 2 is support tables. That’s the 4 “meta” tables and wp_term_relationships.

Takeaway #1

Everything operated on IDs. Posts have IDs. Users have IDs. Even terms have IDs.

My write-up doesn’t display that. But it’s clear if you look at the image. IDs are at the heart of WordPress table relationships.

Takeaway #2

The 2nd takeaway is that every THING in WordPress goes into 1 of the primary tables.

That’s why all standalone content is a “post”. Content is a thing. It has to go somewhere. “wp_posts” is the only place it makes sense. All content has mostly the same requirements as posts. And content clearly doesn’t fit anywhere else.

Takeaway #3

What’s the difference between a comment and a post? A post stands alone. A comment needs something to comment about like a post or another comment.

Any content like this can be a comment. I’ve seen many systems where reviews are comments. (Think business reviews in a directory – not posts where the author is doing a review.)


In some ways, the WordPress and its database are straightforward. Would you be surprised to find out that wp_users is full of users?

But I know the idea that everything is a post confuses people. (Maybe the real issue is that posts are posts of the post type post.) Understanding the database structure can help you understand this concept.

Tagged: ,

Josh on Github Josh on LinkedIn Josh on Twitter