Every WordPress plugin that stores structured data has to answer one question early: where does the data go? WordPress gives you two main routes. You can reuse the built-in tables with custom post types and post meta, or you can create your own tables. Both are valid, and the right choice depends on what you are storing.
The built-in route: posts and meta
WordPress stores content in wp_posts and extra attributes in wp_postmeta, a key-value table. Custom post types let you add new kinds of content on top.
Advantages:
- Little schema work. Registering a post type is quick.
- You inherit core features: revisions, REST endpoints, capabilities, import and export tools.
- Other plugins can read your data through standard functions.
- Nothing extra to create or remove on install and uninstall.
For content such as events, products or portfolio items, this is often the right answer.
Where it strains
Post meta stores each attribute as its own row. A task with a priority, due date, assignees, labels and a checklist becomes many meta rows. That has costs:
- Querying gets awkward. “All open tasks on this board, sorted by due date” means joining the meta table repeatedly, which gets slow as data grows.
- Types are weak. Meta values are strings, so dates and numbers need careful casting.
- Shared space. Your data lives next to everything else, in tables that other plugins, exports and search features also touch. Posts can be picked up by sitemaps, search or backup tools in ways you did not intend.
- Relationships are clumsy. A board with stages, tasks, comments and members is relational data, and flattening it into posts means inventing your own links.
The custom table route
A custom table gives you real columns, real types and indexes designed for your queries.
Advantages:
- Faster, simpler queries for the access patterns you actually have.
- Clear schema with typed columns and indexes.
- Data separated from your site’s public content, so it is not accidentally exposed through content features.
- Straightforward cleanup: drop the tables and the data is gone.
Costs:
- You write and maintain the schema, including migrations when it changes.
- You lose core features you would have received for free, such as revisions or built-in REST routes. You build what you need.
- Other plugins cannot easily read your data unless you provide an API.
- Backups and exports must include your tables. Most database-level backups do, but content-only exports may not.
How KanbanWP stores its data
KanbanWP uses custom tables. The table names use your WordPress prefix followed by kwp_; the helper in includes/class-kanbanwp-db.php builds the names that way. On activation it creates tables for:
- boards, stages and tasks
- comments and an activity log
- board members, labels and saved views
- notifications
- AI usage records
- webhooks
A task row has real columns for its board, stage, parent task, title, priority, position, start and due dates, and flags such as whether it is internal or archived. Flexible, list-shaped details such as assignees, labels, checklist items, attachments and custom fields are kept in text columns holding JSON. That is a pragmatic compromise: the things you filter and sort on are proper columns, and the things you only read as a whole are compact JSON.
Cards can still link to WordPress posts through a post ID column, so editorial work stays connected to real content without duplicating it.
What happens on uninstall
By default, deactivating or deleting the plugin leaves your data alone, which protects you from accidental loss. There is a general setting to delete data on uninstall. When it is on, deleting the plugin drops the tables and removes the plugin’s options and capability. The option is called “Delete data on uninstall”; see the settings documentation.
A rule of thumb for your own plugins
- Is it content people publish, search or edit like posts? Use post types.
- Is it a small amount of simple data? Use options or meta.
- Is it relational, queried in many ways, or private by nature? Consider custom tables.
If you extend KanbanWP, you do not need to touch its tables. The REST API and hooks and filters are the supported way in.