As your WordPress plugin grows in size and complexity, organizing your code into modular components becomes essential. Using Composer with PSR-4 autoloading allows you to follow modern PHP standards, write cleaner code, and scale your plugin like a professional application.
In this guide, you’ll learn how to:
- Structure your plugin using modular classes
- Set up Composer for dependency management
- Implement PSR-4 autoloading
- Autoload your classes cleanly without manual
require
statements
Why Use Composer and PSR-4?
Composer is the de facto dependency manager for PHP. With it, you can:
- Autoload your plugin classes automatically
- Organize code using namespaces and folders
- Pull in external libraries (e.g., Guzzle, Carbon, Monolog)
PSR-4 is a PHP-FIG standard that maps namespaces to directory paths, making code intuitive and standardized.
Recommended Plugin Structure
Here’s a scalable folder structure:
my-plugin/
│
├── my-plugin.php # Main plugin bootstrap
├── composer.json # Composer config
├── vendor/ # Composer dependencies
├── src/ # Your plugin's core code
│ ├── Admin/
│ │ └── SettingsPage.php
│ ├── Frontend/
│ │ └── Shortcode.php
│ └── Core/
│ └── Plugin.php
├── assets/
│ ├── css/
│ └── js/
└── templates/
Step 1: Initialize Composer
In your plugin directory, run:
bashCopyEditcomposer init
Fill out your plugin’s metadata. Then, define autoloading in the composer.json
:
{
"name": "yourname/my-plugin",
"description": "A modular WordPress plugin with PSR-4 autoloading",
"type": "wordpress-plugin",
"autoload": {
"psr-4": {
"MyPlugin\\": "src/"
}
},
"require": {}
}
Then install the autoloader:
bashCopyEditcomposer install
This creates the vendor/
directory with the autoloader.
Step 2: Create Your Plugin Classes
For example, in src/Core/Plugin.php
:
namespace MyPlugin\Core;
class Plugin {
public function boot() {
add_action('init', [$this, 'init_plugin']);
}
public function init_plugin() {
// Boot your plugin logic here
}
}
In src/Admin/SettingsPage.php
:
namespace MyPlugin\Admin;
class SettingsPage {
public function register() {
add_action('admin_menu', [$this, 'add_settings_page']);
}
public function add_settings_page() {
add_menu_page('My Plugin Settings', 'My Plugin', 'manage_options', 'my-plugin', [$this, 'render_page']);
}
public function render_page() {
echo '<h1>My Plugin Settings</h1>';
}
}
Step 3: Bootstrap in the Main Plugin File
In my-plugin.php
:
<?php
/**
* Plugin Name: My Plugin
* Description: A scalable, modular WordPress plugin using Composer and PSR-4.
*/
if (!defined('ABSPATH')) exit;
// Load Composer autoloader
require_once __DIR__ . '/vendor/autoload.php';
use MyPlugin\Core\Plugin;
use MyPlugin\Admin\SettingsPage;
$plugin = new Plugin();
$plugin->boot();
$settings = new SettingsPage();
$settings->register();
Step 4: Use Namespaces Consistently
Each file in src/
should follow PSR-4 conventions:
- Namespace matches directory
- Class name matches file name
- No manual
require
statements needed
Bonus: Add External Libraries via Composer
Want to use something like Carbon?
bashCopyEditcomposer require nesbot/carbon
Then in your code:
use Carbon\Carbon;
echo Carbon::now()->toDateTimeString();
Don’t Forget on Deployment
- Never edit the
vendor/
directory manually - If you’re uploading to a live server, include the
vendor/
folder - If publishing to WordPress.org, use a pre-build script to bundle
vendor/
Why This Matters
- Scalability: You can separate your logic across services, making it easy to maintain
- Modern PHP: Namespaces, OOP, and dependency injection become more manageable
- Reusability: Your code can be reused across plugins or even Laravel/Symfony projects
Final Thoughts
By building your plugin with Composer and PSR-4, you’re stepping into the world of modern PHP development while still taking full advantage of the WordPress ecosystem. Whether you’re working on client projects or commercial plugins, this approach will save time, reduce bugs, and scale better.