Learn how to register a meta-box, create callback functions for HTML inputs, and link them to your CPT to capture specialized metadata in the WordPress editor.
Previously in this course, we explored Introduction to Taxonomies to categorize our Knowledge Base articles. Now, we move beyond simple categories to collect specific, structured data—like a "Difficulty Level" or "External Reference ID"—directly within the post editor.
To do this, we use the add_meta_box function. A meta-box is essentially a container for custom input fields on the post editing screen. While the Gutenberg block editor has largely taken over content creation, meta-boxes remain the standard way to store "sidecar" metadata that describes a post rather than being part of its body text.
We register meta-boxes using the add_meta_boxes action. This action fires after all post types have been registered, making it the perfect place to inject our custom UI.
In our MVC architecture, we should handle this inside a dedicated class—let's call it MetaBoxController.
PHP#6A9955">// Inside our AdminController or a dedicated MetaBoxController public function register_meta_boxes() { add_meta_box( 'kb_article_details', #6A9955">// Unique ID 'Article Metadata', #6A9955">// Title [$this, 'render_meta_box'], #6A9955">// Callback function 'knowledge_article', #6A9955">// Post type 'side', #6A9955">// Context(side, normal, advanced) 'default' #6A9955">// Priority(high, core, default, low) ); } #6A9955">// Hook it up in your plugin constructor add_action('add_meta_boxes', [$this, 'register_meta_boxes']);
The third argument in add_meta_box is a callback function. WordPress passes the $post object to this function, which we can use to retrieve existing data to pre-fill our inputs.
It is critical to use get_post_meta to retrieve existing values so the user doesn't lose data when they return to edit an article.
PHPpublic function render_meta_box($post) { #6A9955">// Retrieve the existing value from the database $value = get_post_meta($post->ID, '_kb_difficulty_level', true); #6A9955">// Add a nonce for security(we'll cover validation in the next lesson) wp_nonce_field('kb_save_meta_box_data', 'kb_meta_box_nonce'); ?> <p> <label for="kb_difficulty">Difficulty Level:</label> <select name="kb_difficulty" id="kb_difficulty"> <option value="beginner" <?php selected($value, 'beginner'); ?>>Beginner</option> <option value="intermediate" <?php selected($value, 'intermediate'); ?>>Intermediate</option> <option value="advanced" <?php selected($value, 'advanced'); ?>>Advanced</option> </select> </p> <?php }
When we registered the meta-box, we passed 'knowledge_article' as the fourth argument. This explicitly limits the box to our Knowledge Base CPT. This is a best practice—never pollute the editor screens of standard Posts or Pages unless your plugin specifically intends to target them.
By keeping the meta-box context set to 'side', we ensure our custom fields appear in the right-hand column, keeping the main content area clean for the block editor.
AdminController (or create a MetaBoxController).add_meta_boxes hook.knowledge_article CPT.get_post_meta to display the saved ID if it exists.echo its output. If you return the HTML, WordPress will display nothing._kb_...) to avoid collisions with other plugins or theme settings.To truly master how this data interacts with the database, I recommend reading our guide on the WordPress Metadata API, which details how to handle these fields at scale. Once you've captured this input, you'll need to secure it, which we explore in the next lesson.
Up next: Sanitizing User Input
Master WordPress security by implementing capability checks. Learn to use current_user_can to restrict admin features and enforce proper access control.
Designing Meta-Boxes
Plugin Security Best Practices
Composer for Dependencies
Theme Integration Hooks
Managing Assets with Gulp/Webpack
Documentation Standards
Plugin Deployment Strategy
Advanced MVC: Dependency Injection
Handling Large Datasets
Error Handling and Logging