Learn how to implement a Controller layer for WordPress admin pages. Separate your UI and business logic to maintain a scalable, professional plugin architecture.
Previously in this course, we explored the Creating Admin Menus lesson. While that lesson showed you how to register menus using simple callback functions, dumping all your HTML and business logic into the main plugin file will quickly lead to a "spaghetti code" nightmare as your Knowledge Base project grows.
In this lesson, we will implement the Controller layer of our MVC architecture. By shifting admin logic into a dedicated class, we ensure our main plugin file stays slim, readable, and focused solely on bootstrapping our services.
In the context of WordPress, a controller is a class responsible for handling requests from the admin dashboard and returning the appropriate response (usually a rendered view).
When you follow the Designing for MVC in WordPress approach, you stop treating your main plugin file as a dumping ground for logic. Instead, you treat it like an orchestrator. Your main plugin class initializes your controllers, and your controllers handle the "how" of your admin pages.
To keep our architecture clean, create a new file: app/Controllers/AdminController.php. This class will contain the logic previously handled by anonymous functions or global procedural callbacks.
PHPnamespace KnowledgeBase\Controllers; class AdminController { #6A9955">/** * Renders the main dashboard page for the Knowledge Base. */ public function renderDashboard() { #6A9955">// In a real-world scenario, you might pass data from a Model here. echo '<div class="wrap"><h1>Knowledge Base Dashboard</h1><p>Welcome to your KB admin area.</p></div>'; } #6A9955">/** * Handles the submenu page rendering. */ public function renderSettings() { echo '<div class="wrap"><h1>KB Settings</h1><p>Configure your plugin here.</p></div>'; } }
Now that we have a controller, we need to wire it into the WordPress menu system. We do this inside our main plugin class, which we established in Defining the Plugin Core Class.
Instead of passing a simple function name to add_menu_page, we pass an array containing our controller instance and the method name: [$this->adminController, 'renderDashboard'].
PHPnamespace KnowledgeBase; use KnowledgeBase\Controllers\AdminController; class Plugin { protected $adminController; public function __construct() { $this->adminController = new AdminController(); add_action('admin_menu', [$this, 'registerAdminMenus']); } public function registerAdminMenus() { add_menu_page( 'Knowledge Base', 'Knowledge Base', 'manage_options', 'kb-dashboard', [$this->adminController, 'renderDashboard'], #6A9955">// Routing here 'dashicons-book' ); add_submenu_page( 'kb-dashboard', 'Settings', 'Settings', 'manage_options', 'kb-settings', [$this->adminController, 'renderSettings'] ); } }
app/Controllers/AdminController.php file in your plugin directory.AdminController methods.registerAdminMenus method in the main plugin class to use the array syntax ([$this->adminController, 'methodName']) to point to your new controller.AdminController has the correct namespace and that your autoloader is correctly mapping the app/ directory. If you get a "callable not found" error, double-check your class loading.AdminController. If you need to fetch data, follow the Laravel Repository Pattern logic: keep the controller thin and delegate data retrieval to a Model or Service layer.By introducing a controller, we have successfully decoupled our menu registration logic from our UI rendering logic. Your main plugin class is now responsible only for "hooking" things up, while the AdminController owns the execution of admin-facing requests. This separation of concerns is the bedrock of maintainable WordPress development.
Up next: We will move beyond static menus and start interacting with the database by Registering Custom Post Types for our Knowledge Base articles.
Learn to organize your WordPress plugin using the MVC pattern. Master directory structures, class loading, and separation of concerns for scalable code.
Read moreLearn to extend the WordPress REST API by registering custom endpoints. We'll show you how to securely serve your Knowledge Base data as structured JSON.
The Controller Layer for Admin Pages
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