I’m fairly new to writing wordpress plugins, but I’ve jumped in the deep end already and I want to make sure I’m doing it “right” on my upcoming big project.
I’m going to be heavily extending wordpress into a pretty big web app and want to keep my data structures as native as possible to rely on the wordpress framework, but I don’t know if it is better to create my own custom database tables or try to make use of custom post types.
I don’t know all my data yet, but there will be a number of tables (or cpts) relationally linked. I get the “vibe” from my research that I should avoid custom database tables, but I’m not sure how to determine the best solution.
Specifically I’m concerned about three areas:
- the number of post metafields I’ll need for my extra fields per cpt if I go that route, and if that will make things “tricky”
- how well I can get back queries using semi complex relational filters for reports
- how to best manage relationships, especially if I have many to many relationships
Is there a “right” way? Thanks for your input.
You should be skeptical of anyone who says that there is a single “right” way. The right way depends on the situation. Using the CPT infrastructure has a number of notable benefits:
WP_Query
class, which means that, in theory, you don’t have to write any (or at least not much) likely-to-be-buggy-and-vulnerable-and-inefficient SQLThe problems with the CPT API mostly stem from the fact that it is highly married to the metaphor of ‘posts’, and all the aspects of that data type that come along with the metaphor. From the MySQL command line, run
DESCRIBE wp_posts
. WP assumes that your content has a title, that it has a (single) author, that you only need to keep track of the created date and the last-edited date, that you’ll need space for an unindexedpost_content
, etc. This works well for some kinds of content, but not necessarily for others. You’ve already gestured in the direction of some potential problems:There are two ways to augment the
wp_posts
schema through the CPT API: postmeta and taxonomies. Postmeta is unindexed key-value pairs, which is great for storing a bunch of miscellaneous data, but not at all optimized for doing complex lookups. Taxonomies are somewhat more flexible in this regard, but you’ll still face lots of potentially costly subqueries if you have very complex lookups. (Themeta_query
andtax_query
arguments and their query constructor classes are very nice and handy, though.)If, as you suggest, you only need to do these kinds of “semi complex relational filters” in the case of occasional reports, then this architecture is probably OK for you. It’s when you start exposing the filters to users, so that you have to run many complex
JOIN
s and subqueries all the time, that things get out of hand quickly.Many-to-many relationships are a longtime sticking point in the WP dev community (see https://core.trac.wordpress.org/ticket/14513). You can fake it without using custom tables by mapping taxonomy items onto post_ids (so that, eg, you can say that ‘P3 has the relationship Y to P5’ by saying that P3 has the tag ‘Y-P3’) but this gets confusing (and inefficient) very quickly. You also may consider creating your own relationships table that links together CPTs – you’d still get the benefit of CPTs, and only be creating a single DB table. For a nicely-executed version of this method, see the Posts 2 Posts plugin: https://wordpress.org/extend/plugins/posts-to-posts/
So, in the end, you should decide based on:
If the answers are: Very posty, not too complex, and don’t have to scale super-huge, go with CPTs. Otherwise consider your own tables.