Every WordPress plugin starts with a single PHP file. As your plugin grows, that single file becomes unmanageable. Functions are scattered, naming conventions are inconsistent, and finding the right line of code takes longer than it should. A well-structured plugin is easier to maintain, less prone to bugs, and simpler for other developers to understand.
This guide covers the boilerplate structure that professional WordPress plugins use, from file organization to autoloading to dependency injection.
The File Structure
A well-organized plugin follows a predictable structure. The root file is your main plugin file with the plugin header. The /includes directory holds your PHP classes. The /admin directory holds admin-specific code. The /public directory holds frontend code. The /languages directory holds translation files. The /assets directory holds CSS and JavaScript files.
This separation of concerns makes it clear where to find specific code and prevents admin code from loading on the front end and vice versa.
Namespace Your Code
PHP namespaces prevent naming collisions between your code and other plugins. Use a unique namespace based on your plugin name — YourPlugin\Admin, YourPlugin\Frontend, YourPlugin\Api. WordPress doesn’t require namespaces, but they’re considered best practice for any plugin that defines classes or functions.
Use the namespace keyword at the top of each PHP file. Import classes with the use keyword instead of referencing fully qualified names throughout your code. This keeps your code clean and makes it easy to see which external dependencies a file uses.
Autoloading with Composer
Manual require_once statements are error-prone and difficult to maintain. Composer’s autoloader handles class loading automatically based on your directory structure and namespace conventions.
Define your autoloading in composer.json using the PSR-4 standard. Map your namespace prefix to your source directory. Run composer dump-autoload to generate the autoloader. Include the generated vendor/autoload.php in your main plugin file.
The Main Plugin Class
The main plugin class is the entry point for your plugin’s functionality. It defines constants, loads dependencies, registers hooks, and initializes sub-components. Use a singleton pattern or dependency injection to manage the main class instance.
Keep the main class focused on orchestration. It shouldn’t contain business logic — that belongs in specialized classes. The main class knows which classes to load and when, but not how they work internally.
Separating Admin and Frontend Code
Admin code — settings pages, custom post type registration, admin AJAX handlers — should not load on the front end. Similarly, frontend code — public-facing shortcodes, templates, frontend scripts — should not load in the admin.
Use separate directories and separate loader classes for admin and frontend code. WordPress provides is_admin() to check the current context, but don’t rely on if-else blocks in a single file. Use separate classes that are conditionally instantiated.
Registering Hooks in a Class-Based Plugin
In a class-based plugin, hooks are registered by calling add_action() and add_filter() in the constructor or an init method. Store the hook registrations in a dedicated method rather than scattering them across the class. This makes it easy to see all hooks at a glance.
Use $this to reference the method when the hook callback is a class method. Pass an array with [$this, ‘method_name’] as the callback. For static methods, use [‘ClassName’, ‘method_name’].
The Bottom Line
A well-structured plugin is an investment that pays dividends throughout your plugin’s lifetime. Namespace your code, use Composer autoloading, separate concerns into dedicated classes, and keep your main plugin class focused on orchestration. Future you — and any developers who work on your code — will thank you for it.
