Understanding Custom Post Types
In WordPress, wp_posts and wp_postmeta hold what you enter for Posts, Pages and other structures.

When you add a Post or a Page to your WordPress site, what you enter goes into the database. When a Viewer wants to see that Post or Page, programming makes a call to the database and sends the Post or Page to the Viewer’s computer. Posts and Pages go into a database table named wp_posts by default ***. Many systems change the first part of the name to make it harder for hackers to get into the database.

The wp_posts table has a specific set of fields for information related to the Post or Page. You can see the field list in WordPress.org. There is a second table named wp_postmeta that can hold additional information about posts.

The table that holds WordPress Posts, Pages, etc, has a post_type field to differentiate between the various types of structures.

By default, WordPress has many types of Posts. In fact, Pages are stored in the wp_posts table. The post_type field records what type of post it is so that the programming can use that record correctly.

But, what if you want a Post to have different fields? For example, if you have a product for sale, instead of just adding the price to the description, you may want to have a Price field that will allow you to move it to a specific part of the page. That is where the WordPress function of Custom Post Types comes in. Custom Post Types mimic the function of adding new fields to the database, but actually add the new data in a way that doesn’t disrupt the structure of the database.

Plugins Often Create Custom Post Types

Plugins, such as WooCommerce or event plugins, often create Custom Post Types. You hope that they are using the WordPress core functionality, because then it is more likely that the plugin will stay in sync with the rest of the WordPress core. Usually, plugins that add Custom Post Types, also add a new menu item near Posts, Pages and Media in the left sidebar navigation in the WordPress Dashboard.

One example is the Triple Divide Seeds website, a company that provides organic seeds that are hardy for the weather patterns in the northwest. Their site uses WooCommerce. Shopping Cart plugins have many pieces. One of those is the Products Custom Post Type that has its own menu item in the Dashboard. The WooCommerce Products custom post type  has many fields where you can add information about a product, such as weight and dimension for shipping.

Instead of all the plugins with additional fields making a mess of the core WordPress database, they can add their own tables, or they can create records in a second table in the WordPress database called _postmeta. When they use _postmeta, instead of making new fields in the database, plugins use “name – value” pairs in existing fields.

In the screenshot, the table has the default fields: meta_id, post_id, meta_key and meta_value.

The fields in the _postmeta table are:

  1. meta_id is the primary key field that all well constructed relational database tables have.
  2. post_id ties that record to a specific Product which is a record in the _posts table. The title, description, etc are in the _posts table.
  3. meta_key identifies which custom field the record is for, such as weight or length (for shipping). This is the “name” part of the name-value pair.
  4. meta_value is what was entered into the field in the Products. For example, if you update the price of the product, the 3.00 will change to the new price.

    WooCommerce Products is an example of a Custom Post Type


Side Note: From a pure database science standpoint, the way plugins use the postmeta table is not following the “normal forms”.

The _postmeta table is used to store the values of the extra fields a Custom Post Type Needs. Here is an example of how the extra fields for WooCommerce are stored.

*** From a security standpoint, it is not wise to leave the table names starting with wp_ because that is one more piece of information that hackers will try in their software.


Leave a Reply

Your email address will not be published. Required fields are marked *