Modern WordPress plugin template with dependency injection, event-driven architecture, and comprehensive testing infrastructure.
This template provides a production-ready foundation for WordPress plugins using:
- Dependency Injection: League Container (PSR-11)
- Event Management: WP Media EventManager with subscriber pattern
- Type Safety: PHP 7.4+ strict types, PHPStan level 5
- Testing: Separate unit (Brain Monkey) and integration (WordPress test suite) tests
- Code Quality: WordPress Coding Standards, PHPCompatibility checks
When creating a new plugin from this template:
- Create repository: Use this as GitHub template
- Update identifiers:
- Find/replace
WPMedia\PackageTemplate→WPMedia\YourPluginin all PHP files - Update
composer.json:name,description,homepage - Update
plugin.php: Plugin headers (Name, URI, Description, Text Domain, version) - Update
Config::init()array:plugin_slug,prefix - Update
phpcs.xml.dist:text_domain,prefixesproperties - Replace
wpmedia_package_template_loadedhook name inPlugin.php
- Find/replace
Requirements:
- PHP 7.4+
- Composer
- MySQL database (for integration tests)
svn(for WordPress test suite installation)
Installation:
# Install dependencies
composer install
# Setup WordPress test suite
bash bin/install-wp-tests.sh wordpress_test db_user db_pass localhost latest
# Run all tests
composer run-tests
# Check code standards
composer phpcsEntry Point (plugin.php)
- Loads Composer autoloader
- Initializes
Configsingleton with plugin metadata - Creates
Plugininstance and registers lifecycle hooks
Config (inc/Config.php)
- Singleton configuration container
- Stores:
version,plugin_file,plugin_basename,plugin_slug,prefix - Access via
Config::get('key')
Plugin (inc/Plugin.php)
- Main orchestrator with
load(),activate(),deactivate()methods - Sets up DI container, EventManager, Options
- Registers event subscribers
- Fires
wpmedia_package_template_loadedaction for extensibility
Subscribers (inc/Subscriber.php)
- Implement
WPMedia\EventManager\SubscriberInterface - Return hooks array from
get_subscribed_events():public static function get_subscribed_events(): array { return [ 'init' => 'on_init_callback', 'save_post' => ['on_save_post', 10, 2], // priority & args ]; }
This template uses WP Media packages (not direct WordPress hooks):
Core Dependencies:
league/container(^4.0): PSR-11 dependency injection containerwp-media/event-manager(^4.0): Event system withEventManager+PluginApiManagerwp-media/options(^4.0): Options handling with automatic prefixingwp-media/apply-filters-typed(^1.0): Type-safe filter application
Register hooks via $event_manager->add_subscriber(new Subscriber()) instead of direct add_action() calls.
composer run-tests # Run all tests (unit + integration)
composer test-unit # Unit tests only (Brain Monkey mocks)
composer test-integration # Integration tests (real WordPress)composer phpcs # Check coding standards
composer phpcs:fix # Auto-fix coding standards
composer phpstan # Static analysis (PHPStan level 5)- Base: Extend
WPMedia\PHPUnit\Unit\TestCase - Mocking: Uses Brain Monkey for WordPress functions
- Execution: Fast, no WordPress installation needed
- Pattern: Load test data via
configTestData()from co-located PHP files
Example:
namespace WPMedia\PackageTemplate\Tests\Unit;
class MyTest extends TestCase {
public function testSomething() {
Functions\expect('get_option')
->once()
->with('my_option')
->andReturn('value');
}
}- Base: Extend
WPMedia\PHPUnit\Integration\TestCase - Environment: Runs against real WordPress test suite
- Setup: Requires
install-wp-tests.shexecution - Plugin Loading: Auto-loads plugin via
tests_add_filterinbootstrap.php
Example:
namespace WPMedia\PackageTemplate\Tests\Integration;
class MyTest extends TestCase {
public function testWordPressFunctionality() {
$this->assertTrue(did_action('wpmedia_package_template_loaded') > 0);
}
}- Version: PHP 7.4+ minimum
- Strict Types:
declare(strict_types=1);in all files - Namespace:
WPMedia\PackageTemplate(core),WPMedia\PackageTemplate\Tests(tests) - Autoloading: PSR-4 via Composer
- Array Syntax: Short syntax
[]enforced
- Classes: PascalCase filenames matching class name (
Plugin.php,Subscriber.php) - Global Functions:
wpmedia_prefix - Database Options: Use prefix from
Config::get('prefix')(default:wpmpt_) - Hook Names:
wpmedia_package_template_*pattern
- Use type hints for all parameters and return types
- PHPStan level 5 with WordPress stubs
- Suppress false positives:
@phpstan-ignore-line
- Base: WordPress Coding Standards (WPCS)
- Excludes: File/class comments, hyphenated lowercase filenames
- Enforced: PHPCompatibility 7.4+, short array syntax, I18n text domain
Optional Composer packages for common use cases:
composer require berlindb/coreUse for: Custom database tables with ORM-like interface (e.g., logs, analytics data not fitting custom post types)
composer require --dev coenjacobs/mozartUse for: Prefix/wrap Composer dependencies to prevent conflicts when multiple plugins use the same libraries
composer require woocommerce/action-schedulerUse for: Reliable background job processing (cron alternative with automatic failure handling and retry logic)
composer require wp-media/wp-mixpanelUse for: Integrate Mixpanel analytics for plugin usage tracking
plugin.php # Entry point, plugin headers
inc/
├── Config.php # Configuration singleton
├── Plugin.php # Main plugin class
└── Subscriber.php # Event subscriber template
Tests/
├── Unit/ # Unit tests with Brain Monkey
│ ├── bootstrap.php
│ ├── TestCase.php # Base test class
│ └── ExampleTest.php
├── Integration/ # Integration tests with WordPress
│ ├── bootstrap.php
│ ├── TestCase.php
│ └── ExampleTest.php
└── Fixtures/ # Test data files
bin/
└── install-wp-tests.sh # WordPress test suite installer
.editorconfig # IDE coding standards
.gitattributes # Export exclusions
phpcs.xml.dist # Code standards config
phpstan.neon.dist # Static analysis config
composer.json # Dependencies and scripts
.editorconfig: IDE settings for WordPress coding standards (tabs, UTF-8, LF).gitattributes: Excludes development files from plugin exports (bin/,Tests/, etc.)phpcs.xml.dist: WordPress Coding Standards with PHPCompatibility 7.4+, custom exclusionsphpstan.neon.dist: PHPStan level 5 analyzinginc/andTests/with WordPress stubs
GPL-2.0-or-later