Data Modeling & Metadata
Data Modeling & Metadata
In this repository, data modeling follows WordPress best practices while emphasizing performance, scalability, and ease of maintenance. This section outlines how to define Custom Post Types (CPTs), Taxonomies, and handle Post Metadata consistently across your project.
Custom Post Types (CPTs)
Custom Post Types represent the primary data entities of your application. When registering a CPT, ensure you utilize a unique prefix for the slug to avoid collisions with plugins or core WordPress functionality.
Implementation Pattern
We recommend defining CPTs using a configuration-driven approach. This allows for a clean separation between the registration logic and the post type settings.
// Example: Registering a 'Project' Post Type
add_action('init', function() {
register_post_type('ua_project', [
'labels' => [
'name' => __('Projects', 'ua-textdomain'),
'singular_name' => __('Project', 'ua-textdomain'),
],
'public' => true,
'has_archive' => true,
'show_in_rest' => true, // Enable Gutenberg and REST API support
'supports' => ['title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'],
'menu_icon' => 'dashicons-portfolio',
'rewrite' => ['slug' => 'projects'],
]);
});
Key Considerations:
show_in_rest: Always set this totrueif you intend to use the block editor or headless WordPress features.supports: Explicitly define what your post type needs (e.g.,thumbnail,comments) to keep the UI clean.
Custom Taxonomies
Taxonomies provide a way to group and categorize your CPTs. Use Hierarchical taxonomies (like Categories) for fixed structures and Non-hierarchical taxonomies (like Tags) for flexible labeling.
Usage Example
To associate a "Technology Stack" taxonomy with the "Project" post type:
register_taxonomy('ua_tech_stack', ['ua_project'], [
'hierarchical' => true,
'labels' => [
'name' => __('Tech Stacks', 'ua-textdomain'),
'singular_name' => __('Tech Stack', 'ua-textdomain'),
],
'show_ui' => true,
'show_admin_column' => true,
'show_in_rest' => true,
'query_var' => true,
'rewrite' => ['slug' => 'tech-stack'],
]);
Metadata Management
Metadata allows you to store additional structured information about your posts. While WordPress handles post_meta natively, maintaining a strict schema for your keys is critical for data integrity.
Naming Conventions
- Internal Metadata: Prefix with an underscore (e.g.,
_ua_project_budget) to hide the field from the default "Custom Fields" meta box in the admin UI. - Public Metadata: Use a consistent prefix (e.g.,
ua_project_deadline) for fields intended to be queryable or visible.
CRUD Operations for Metadata
Use the standard WordPress API for metadata manipulation. Always ensure data is sanitized on input and escaped on output.
| Function | Purpose | Input Type |
| :--- | :--- | :--- |
| update_post_meta() | Create or update a meta value. | (int) $post_id, (string) $key, (mixed) $value |
| get_post_meta() | Retrieve a meta value. | (int) $post_id, (string) $key, (bool) $single |
| delete_post_meta() | Remove a meta entry. | (int) $post_id, (string) $key |
Example: Storing and Retrieving Meta
// Updating metadata with sanitization
$budget = sanitize_text_field($_POST['project_budget']);
update_post_meta($post_id, '_ua_project_budget', $budget);
// Retrieving metadata
$project_budget = get_post_meta($post_id, '_ua_project_budget', true);
Performance Best Practices
- Avoid EAV Bloat: Do not store massive blobs of JSON in a single meta key if you need to query individual properties. Use separate meta keys for filterable data.
- Indexing: When performing complex queries based on metadata, use
WP_Querywithmeta_query. Note that high-volume meta queries can be resource-intensive; consider using a dedicated search index (like Elasticsearch) for extremely large datasets. - Caching:
get_post_meta()is internally cached by WordPress. You do not need to implement manual caching for standard meta retrieval.
Data Validation API
While the repository provides several helper functions (internal), ensure you use the following standard WordPress functions for data validation before storage:
absint(): For ID and numeric storage.sanitize_email(): For email addresses.wp_kses(): For fields where specific HTML tags are allowed.rest_sanitize_boolean(): For flag/boolean storage via REST API.