Basic developers understand, at some level, what WordPress "does" and how to modify its behavior. Better developers understand how to create objects, object meta data, and object relationships in WordPress (post types, meta, taxonomies). But the best engineers understand how all of this data actually manifests itself in the raw database architecture.
Understanding how WordPress stores, organizes, and relates data when you strip away the PHP software layer can give you a deeper understanding and appreciation for the brilliance, deficits, potential, limits, and legacy of WordPress.
We'll study WordPress's database schema, relate it back to core data model concepts like custom post types and taxonomies, meander holes in the models (like "why isn't there term meta??"), and even compare to past database structure to see how WordPress's database has evolved with the software.
1. The Core of WordPress Core
Digging Into WordPress’s Core Data Model
2. @jakemgold
• President of 10up - a growing WordPress-centric agency with 18 full time employees
• Clients like Juicy Couture, Time Inc, Condé Nast, Consumer Reports, TechCrunch,
Universal Sports, Trulia, & More
• 10 of our 13 software engineers (including me!) contributed to WordPress 3.5, and we
maintain some of the best rated, most downloaded plug-ins.
• Personal background: 15 years in web development, with a concentration in
information systems & architecture
3. Premise
$args
=
array( _type',
>
'my_custom_post
'post_type'
=
'age',
'meta_key'
=> alue_num',
'ord erby'
=>
'meta_v
SC',
'order'
=>
'A
array(
'meta_query'
=>
array(
SELECT
*
FROM
...
'key'
=>
'age',
ray(3,
4),
...
blah
blah
blah
'value'
=>
ar
'
=>
'IN',
'compare
)
)
);
ery($args);
$q uery
=
new
WP_Qu
As a content management framework, WordPress mostly
conceals abstract database complexity from us. Cool.
4. Premise
$args
=
array( _type',
>
'my_custom_post
'post_type'
=
'age',
'meta_key'
=> alue_num',
'ord erby'
=>
'meta_v
SC',
'order'
=>
'A
array(
'meta_query'
=>
array(
SELECT
*
FROM
...
'key'
=>
'age',
ray(3,
4),
...
blah
blah
blah
'value'
=>
ar
'
=>
'IN',
'compare
)
)
);
ery($args);
$q uery
=
new
WP_Qu
As a result, few consider how WordPress stores all
the things when you peel the software layer back.
Less cool.
5. Premise
type',
SELECT
*
FROM
...
,
...
blah
blah
blah
??
As a result, few consider how WordPress stores all
the things when you peel the software layer back.
Less cool.
6. Premise
type',
SELECT
*
FROM
...
...
blah
blah
blah
??
Studying how “the things” are stored (the data model) and
its evolution empowers us to understand WordPress, its
potential, and its limitations in deeper ways.
7. Premise
type',
SELECT
*
FROM
...
...
blah
blah
blah
??
Studying how “the things” are stored (the data model) and
its evolution empowers us to understand WordPress, its
potential, and its limitations in deeper ways.
9. On Platforms & Abstraction
Good platforms make it easy to build stuff it wasn’t explicitly
designed for.
10. On Platforms & Abstraction
Good platforms make it easy to build stuff it wasn’t explicitly
designed for.
Good content platforms make it easy to create content it wasn’t
explicitly designed for.
12. On Abstraction
If we wanted to build an application
to manage project tasks, its data
model might look like this.
13. On Abstraction
If we wanted to build an application
to manage project tasks, its data
model might look like this.
If we were building a platform that
could be used for project tasks, or
any other kind of content, it would
look very different.
14. WordPress’s data model essentially handles abstraction with:
One fairly generic content object table: wp_posts
Field Type
ID bigint(20)
unsigned
post_author bigint(20)
unsigned
post_date datetime
post_date_gmt datetime
post_content longtext
post_title text
post_excerpt text
post_status varchar(20)
comment_status varchar(20)
ping_status varchar(20)
post_password varchar(20)
post_name varchar(200)
to_ping text
pinged text
post_modified datetime
post_modified_gmt datetime
post_content_filtered longtext
post_parent bigint(20)
unsigned
guid varchar(255)
menu_order int(11)
post_type varchar(20)
post_mime_type varchar(100)
comment_count bigint(20)
15. WordPress’s data model essentially handles abstraction with:
One fairly generic content object table: wp_posts
Field Type
ID bigint(20)
unsigned
post_author bigint(20)
unsigned
post_date datetime
post_date_gmt datetime
post_content longtext
post_title text
post_excerpt text
post_status varchar(20)
post_content comment_status varchar(20)
generic field for content ping_status
post_password
varchar(20)
varchar(20)
post_name varchar(200)
to_ping text
pinged text
post_modified datetime
post_modified_gmt datetime
post_content_filtered longtext
post_parent bigint(20)
unsigned
guid varchar(255)
menu_order int(11)
post_type varchar(20)
post_mime_type varchar(100)
comment_count bigint(20)
16. WordPress’s data model essentially handles abstraction with:
One fairly generic content object table: wp_posts
Field Type
ID bigint(20)
unsigned
post_author bigint(20)
unsigned
post_date datetime
post_date_gmt datetime
post_content longtext
post_title text
post_excerpt text
post_status post_status
comment_status
varchar(20)
varchar(20)
generic field for identifier of ping_status varchar(20)
state of content object post_password
post_name
varchar(20)
varchar(200)
to_ping text
pinged text
post_modified datetime
post_modified_gmt datetime
post_content_filtered longtext
post_parent bigint(20)
unsigned
guid varchar(255)
menu_order int(11)
post_type varchar(20)
post_mime_type varchar(100)
comment_count bigint(20)
17. WordPress’s data model essentially handles abstraction with:
One fairly generic content object table: wp_posts
Field Type
ID bigint(20)
unsigned
post_author bigint(20)
unsigned
post_date datetime
post_date_gmt datetime
post_content longtext
post_title text
post_excerpt text
post_status varchar(20)
post_parent comment_status varchar(20)
object hierarchy ping_status
post_password
varchar(20)
varchar(20)
post_name varchar(200)
to_ping text
pinged text
post_modified datetime
post_modified_gmt datetime
post_content_filtered longtext
post_parent bigint(20)
unsigned
guid varchar(255)
menu_order int(11)
post_type varchar(20)
post_mime_type varchar(100)
comment_count bigint(20)
18. WordPress’s data model essentially handles abstraction with:
One fairly generic content object table: wp_posts
Field Type
ID bigint(20)
unsigned
post_author bigint(20)
unsigned
post_date datetime
post_date_gmt datetime
post_content longtext
post_title text
post_excerpt text
post_status varchar(20)
menu_order comment_status varchar(20)
relative order of content ping_status
post_password
varchar(20)
varchar(20)
post_name varchar(200)
to_ping text
pinged text
post_modified datetime
post_modified_gmt datetime
post_content_filtered longtext
post_parent bigint(20)
unsigned
guid varchar(255)
menu_order int(11)
post_type varchar(20)
post_mime_type varchar(100)
comment_count bigint(20)
19. WordPress’s data model essentially handles abstraction with:
One fairly generic content object table: wp_posts
Field Type
ID bigint(20)
unsigned
post_author bigint(20)
unsigned
post_date datetime
post_date_gmt datetime
post_content longtext
post_title text
post_excerpt text
post_type (!!!) post_status
comment_status
varchar(20)
varchar(20)
generic identifier for type of ping_status varchar(20)
content object post_password
post_name
varchar(20)
varchar(200)
to_ping text
pinged text
post_modified datetime
post_modified_gmt datetime
post_content_filtered longtext
post_parent bigint(20)
unsigned
guid varchar(255)
menu_order int(11)
post_type varchar(20)
post_mime_type varchar(100)
comment_count bigint(20)
20. WordPress’s data model essentially handles abstraction with:
One fairly generic content object table: wp_posts
Field Type
ID bigint(20)
unsigned
post_author bigint(20)
unsigned
post_date datetime
post_date_gmt datetime
post_content longtext
post_title text
post_mime_type post_excerpt
post_status
text
varchar(20)
standards based identifier of comment_status varchar(20)
the type of information ping_status
post_password
varchar(20)
varchar(20)
contained in content post_name varchar(200)
to_ping text
pinged text
post_modified datetime
post_modified_gmt datetime
post_content_filtered longtext
post_parent bigint(20)
unsigned
guid varchar(255)
menu_order int(11)
post_type varchar(20)
post_mime_type varchar(100)
comment_count bigint(20)
21. WordPress’s data model essentially handles abstraction with:
A completely abstract content object properties table: wp_postmeta
Field Type
meta_id bigint(20)
post_id bigint(20)
meta_key varchar(255)
meta_value text
Meta data is defined as “data about data.”
It doesn’t get more abstract.
22. WordPress’s data model essentially handles abstraction with:
A completely abstract content object properties table: wp_postmeta
Field Type
meta_id bigint(20)
post_id bigint(20)
meta_key varchar(255) identifier of content object
meta_value text
this is all about
Meta data is defined as “data about data.”
It doesn’t get more abstract.
23. WordPress’s data model essentially handles abstraction with:
A completely abstract content object properties table: wp_postmeta
Field Type
meta_id bigint(20)
post_id bigint(20)
arbitrary identifier for the
meta_key varchar(255) content property we want
meta_value text to define
Meta data is defined as “data about data.”
It doesn’t get more abstract.
24. WordPress’s data model essentially handles abstraction with:
A completely abstract content object properties table: wp_postmeta
Field Type
meta_id bigint(20)
post_id bigint(20)
arbitrary value for our
meta_key varchar(255)
arbitrary property
meta_value text
Meta data is defined as “data about data.”
It doesn’t get more abstract.
25. WordPress’s data model essentially handles abstraction with:
An abstract set of tables for content classification.
26. WordPress’s data model essentially handles abstraction with:
An abstract set of tables for content classification.
Field Type
term_id bigint(20)
unsigned
name varchar(200)
slug varchar(200)
term_group bigint(10)
wp_terms
Arbitrary classifications for
content objects.
27. WordPress’s data model essentially handles abstraction with:
An abstract set of tables for content classification.
Field Type Field Type
term_taxonomy_id bigint(20)
unsigned term_id bigint(20)
unsigned
term_id bigint(20)
unsigned name varchar(200)
taxonomy varchar(32) slug varchar(200)
description longtext term_group bigint(10)
parent bigint(20)
unsigned
count bigint(20)
wp_terms
Arbitrary classifications for
wp_term_taxonomy content objects.
Describes the arbitrary
classification (term) for each
unique classification group
(taxonomy).
28. WordPress’s data model essentially handles abstraction with:
An abstract set of tables for content classification.
Field Type Field Type Field Type
term_taxonomy_id bigint(20)
unsigned term_id bigint(20)
unsigned object_id bigint(20)
unsigned
term_id bigint(20)
unsigned name varchar(200) term_taxonomy_id bigint(20)
unsigned
taxonomy varchar(32) slug varchar(200) term_order int(11)
description longtext term_group bigint(10)
parent bigint(20)
unsigned
wp_term_relationships
wp_terms Associates classifications with
count bigint(20)
Arbitrary classifications for content objects.
wp_term_taxonomy content objects.
Describes the arbitrary
classification (term) for each
unique classification group
(taxonomy).
29. WordPress’s data model essentially handles abstraction with:
An abstract set of tables for content classification.
Field Type Field Type
term_taxonomy_id bigint(20)
unsigned term_id bigint(20)
unsigned
term_id
taxonomy
bigint(20)
unsigned
varchar(32)
name
slug
varchar(200)
varchar(200)
Huh?
description longtext term_group bigint(10)
... oops.
parent bigint(20)
unsigned
count bigint(20)
wp_terms
Arbitrary classifications for
wp_term_taxonomy content objects.
Describes the arbitrary
classification (term) for each
unique classification group
(taxonomy).
30. WordPress’s data model essentially handles abstraction with:
An abstract set of tables for content classification.
Field Type
Anything else here surprise you? object_id bigint(20)
unsigned
term_taxonomy_id bigint(20)
unsigned
term_order int(11)
wp_term_relationships
Associates classifications with
content objects.
31. WordPress’s data model essentially handles abstraction with:
An abstract set of tables for content classification.
Field Type
Anything else here surprise you? object_id bigint(20)
unsigned
term_taxonomy_id bigint(20)
unsigned
term_order (??) term_order int(11)
WordPress’s API does not
support ordering terms. Its wp_term_relationships
data model actually does. Associates classifications with
content objects.
32. WordPress’s data model essentially handles abstraction with:
An abstract set of tables for content classification.
Field Type
Anything else here surprise you? object_id bigint(20)
unsigned
term_taxonomy_id bigint(20)
unsigned
term_order (??) term_order int(11)
WordPress’s API does not
support ordering terms. Its wp_term_relationships
data model actually does. Associates classifications with
content objects.
Where’s term meta?
The data model doesn’t yet
(really) support arbitrary data
about a classification / term.
33. WordPress’s data model essentially handles abstraction with:
A completely abstract global data table: wp_options
Field Type
option_id bigint(20)
unsigned
option_name varchar(64)
option_value longtext
autoload varchar(20)
34. WordPress’s data model essentially handles abstraction with:
A completely abstract global data table: wp_options
Field Type
option_id bigint(20)
unsigned
option_name varchar(64)
arbitrary name of data
option_value longtext
autoload varchar(20)
35. WordPress’s data model essentially handles abstraction with:
A completely abstract global data table: wp_options
Field Type
option_id bigint(20)
unsigned
option_name varchar(64)
arbitrary value
option_value longtext for said data
autoload varchar(20)
36. Other tables and abstraction!
wp_comments & wp_commentmeta
Comments are a specific type of content object, separated
for legacy and scalability reasons.
wp_users & wp_usermeta
Users a special object (not really content).
Also have arbitrary properties / meta data.
wp_links
A specific content object (and leftover.)
37.
38. How did we get here?
Why do we call content objects “posts”?
And why the heck is there a “links” table?
41. WordPress 1.5*: Blogging Software
Field Type
Tables: ID
post_author
bigint(20)
unsigned
int(4)
wp_categories post_date
post_date_gmt
datetime
datetime
wp_comments post_content
post_title
longtext
text
wp_linkcategories post_category
post_excerpt
int(4)
text
wp_links post_status enum('publish','draft','private','static','object')
wp_options
comment_status enum('open','closed','registered_only')
ping_status enum('open','closed')
wp_post2cat post_password
post_name
varchar(20)
varchar(200)
wp_postmeta to_ping
pinged
text
text
wp_posts post_modified
post_modified_gmt
datetime
datetime
wp_users post_content_filtered
post_parent
text
int(11)
guid varchar(255)
menu_order int(11)
42. WordPress 1.5: Blogging Software
Tables: Field Type
wp_categories meta_id bigint(20)
wp_comments
post_id bigint(20)
meta_key varchar(255)
wp_linkcategories meta_value text
wp_links
wp_options
wp_post2cat
wp_postmeta
wp_posts
wp_users
43. WordPress 1.5: Blogging Software
Tables: Field Type
wp_categories meta_id bigint(20)
wp_comments
post_id bigint(20)
meta_key varchar(255)
wp_linkcategories meta_value text
wp_links
wp_options Arbitrary content (post) meta data!
wp_post2cat Early sign of data model
wp_postmeta abstraction... and possibility!
wp_posts
wp_users
44. WordPress 2.0: Foundation for Content Abstraction
Field Type
Tables:
ID bigint(20)
unsigned
post_author bigint(20)
post_date datetime
wp_categories post_date_gmt
post_content
datetime
longtext
wp_comments post_title
post_category
text
int(4)
wp_linkcategories post_excerpt
post_status
text
enum('publish','draft','private','static','object',
'attachment')
wp_links comment_status
ping_status
enum('open','closed','registered_only')
enum('open','closed')
wp_options post_password
post_name
varchar(20)
varchar(200)
wp_post2cat to_ping
pinged
text
text
wp_postmeta post_modified
post_modified_gmt
datetime
datetime
wp_posts post_content_filtered
post_parent
text
bigint(20)
wp_usermeta guid
menu_order
varchar(255)
int(11)
wp_users post_type
post_mime_type
varchar(100)
varchar(100)
comment_count bigint(20)
45. WordPress 2.0: Foundation for Content Abstraction
Field Type
Tables:
ID bigint(20)
unsigned
post_author bigint(20)
post_date datetime
wp_categories post_date_gmt
post_content
datetime
longtext
wp_comments post_title
post_category
text
int(4)
wp_linkcategories post_excerpt
post_status
text
enum('publish','draft','private','static','object',
'attachment')
wp_links comment_status
ping_status
enum('open','closed','registered_only')
enum('open','closed')
wp_options post_password
post_name
varchar(20)
varchar(200)
wp_post2cat to_ping
pinged
text
text Origin: Pages & Media.
wp_postmeta post_modified
post_modified_gmt
datetime
datetime
Post type API wouldn’t
come till 3.0!
wp_posts post_content_filtered
post_parent
text
bigint(20)
wp_usermeta guid
menu_order
varchar(255)
int(11)
wp_users post_type
post_mime_type
varchar(100)
varchar(100)
comment_count bigint(20)
46. WordPress 2.0: Foundation for Content Types
Tables:
wp_categories
wp_comments
wp_linkcategories
wp_links
wp_options
wp_post2cat
wp_postmeta
wp_posts
wp_usermeta
wp_users
47. WordPress 2.0: Foundation for Content Types
Tables: Field Type
wp_categories umeta_id bigint(20)
wp_comments
user_id bigint(20)
meta_key varchar(255)
wp_linkcategories meta_value longtext
wp_links
wp_options User objects are now extensible
wp_post2cat with arbitrary meta data.
wp_postmeta More signs of extensibility!
wp_posts
wp_usermeta
wp_users
50. WordPress 2.3: Classifications Get Abstract
Tables: Removed Tables:
wp_comments wp_categories
wp_links wp_linkcategories
wp_options wp_post2cat
wp_postmeta
wp_posts
Impetus: Tags.
wp_terms Taxonomy registration API
wp_term_relationships wouldn’t come till 2.9!
wp_term_taxonomy Category fields in post and
wp_usermeta links tables don’t get removed
until 2.8.
wp_users
51. WordPress 2.5: Enum Values Fade Away
post_status,
comment_status,
ping_status
in wp_posts table change from enumerated list (enforced options
in data model) to freeform field
term_order
curiously gets added to wp_term_relationships table
53. WordPress 2.9: Comment Objects Get Meta
Tables:
wp_comments
wp_commentmeta
wp_links
wp_options
wp_postmeta
wp_posts
wp_terms
wp_term_relationships
wp_term_taxonomy
wp_usermeta
wp_users
54. WordPress 3.0: Groups of Objects
WordPress Network Mode (Multisite)
(which we’re not going to study for time’s sake)
more detail: http://codex.wordpress.org/Database_Description/2.0
57. The Future of WordPress’s Data Model
• Clean up of taxonomy tables, and addition of term meta data?
• Legacy specific content object tables (links) fall away? (note 3.5)
• Post table fields very specific to blog posts get moved over to post
meta or taxonomies?
• Improvements to relationships between content objects?
58. The Core of WordPress Core
Thanks! Slides will be available at 10up.com.
Feedback? Want more? @jakemgold on Twitter