Template repository for creating production-ready WordPress plugins with MVC architecture and PHP-Scoper namespace isolation.
📖 Full Documentation | 🐛 Report Issues
- Complete MVC Structure — Controllers, Services, Views, Routes
- PSR-4 Autoloading — Modern PHP namespace organization
- PHP-Scoper Ready — Pre-configured namespace isolation for multi-plugin compatibility
- Service Providers — Modular dependency injection
- Database Migrations — Version-controlled schema changes
- WordPress Compliant — Proper headers, MIT license, readme.txt
- Intelligent CLI — Version prompting, smart file discovery, auto-versioning
- Build Pipeline — Scaffold CLI with QA checks and ZIP creation
- Security First — Nonce verification, capability checks, input sanitization
| Requirement | Version |
|---|---|
| PHP | ^8.0 |
| WordPress | 6.0+ |
| Composer | 2.0+ |
| WP-CLI | Optional |
Click "Use this template" on GitHub to create a new repository.
cd /path/to/wordpress/wp-content/plugins
composer create-project wpdiggerstudio/wpzylos-scaffold your-plugin-name
cd your-plugin-namegit clone https://github.com/WPDiggerStudio/wpzylos-scaffold.git your-plugin-name
cd your-plugin-name
rm -rf .git
composer installAfter creating your project, run the Scaffold CLI to customize and manage your plugin.
Open Windows PowerShell (search "PowerShell" in Start menu):
.\scaffold.ps1 # Interactive menu
.\scaffold.ps1 init # Initialize plugin directly
.\scaffold.ps1 build # Build for production directlyOpen Command Prompt (cmd.exe). Since .ps1 files don't run directly in cmd, use:
powershell -ExecutionPolicy Bypass -File scaffold.ps1
powershell -ExecutionPolicy Bypass -File scaffold.ps1 init
powershell -ExecutionPolicy Bypass -File scaffold.ps1 buildFor Linux, macOS, or Git Bash on Windows (install Git for Windows):
chmod +x scaffold.sh # Make executable (first time only)
./scaffold.sh # Interactive menu
./scaffold.sh init # Initialize plugin directly
./scaffold.sh build # Build for production directlyGit Bash alternative: If
./scaffold.shdoesn't work, trybash scaffold.sh
The intelligent init script handles all scenarios:
| Scenario | Behavior |
|---|---|
| Fresh install | Detects my-plugin.php, uses scaffold defaults |
| Re-configure | Loads .plugin-config.json, shows current values as defaults |
| Config deleted | Auto-detects plugin from *.php with "Plugin Name:" header |
| Partial update | Only changes modified values, shows "Skipped" for unchanged |
Features:
- Version Prompting: Sets initial version and updates plugin header + PluginContext
- Namespace support: Supports nested namespaces like
WPDigger\WPBraCalculator
your-plugin/
├── app/ # Application code (PSR-4: YourPlugin\)
│ ├── Core/
│ │ └── PluginContext.php # Plugin identity (slug, prefix, text domain)
│ ├── Lifecycle/
│ │ ├── Activator.php # Activation logic
│ │ ├── Deactivator.php # Deactivation logic
│ │ └── Uninstaller.php # Uninstall cleanup
│ └── Support/
│ └── helpers.php # Global helper functions
├── bootstrap/
│ └── app.php # Application bootstrap & service providers
├── config/
│ └── app.php # Application configuration
├── database/
│ └── migrations/ # Database migrations
├── resources/
│ ├── lang/ # Translation files
│ └── views/ # PHP view templates
├── routes/
│ └── web.php # Route definitions
├── tests/
│ └── Unit/ # PHPUnit tests
├── scaffold.ps1 # Scaffold CLI (Windows)
├── scaffold.sh # Scaffold CLI (Linux/Mac)
├── .scripts/ # CLI scripts
│ ├── init-plugin.ps1/.sh # Initialization logic
│ └── build.ps1/.sh # Build pipeline logic
├── your-plugin.php # Main plugin entry point
├── uninstall.php # WordPress uninstall handler
├── scoper.inc.php # PHP-Scoper configuration
├── composer.json # Dependencies
└── readme.txt # WordPress.org readme
Run the Scaffold CLI for automated setup:
PowerShell:
.\scaffold.ps1 initCommand Prompt:
powershell -ExecutionPolicy Bypass -File scaffold.ps1 initLinux/Mac/Git Bash:
./scaffold.sh initIf you prefer manual customization, perform search and replace:
| Find | Replace With | Description |
|---|---|---|
my-plugin |
your-plugin |
Plugin slug (lowercase, hyphenated) |
my_plugin |
your_plugin |
Scoper prefix (lowercase, underscored) |
MyPlugin |
YourPlugin |
PHP namespace (PascalCase) |
myplugin_ |
yourplugin_ |
Database/option prefix |
My Plugin |
Your Plugin |
Display name |
your-plugin.php— Plugin headers, PluginContext configurationcomposer.json— Package name, namespace in autoloadscoper.inc.php— Scoper prefix variable.plugin-config.json— Created by init, used by builduninstall.php— Context configuration
The PluginContext class (app/Core/PluginContext.php) is the single source of truth for plugin identity. All framework components use this for prefixing.
$context = PluginContext::create([
'file' => __FILE__,
'slug' => 'your-plugin',
'prefix' => 'yourplugin_',
'textDomain' => 'your-plugin',
'version' => '1.0.0',
]);Available Methods:
| Method | Returns | Example |
|---|---|---|
slug() |
Plugin slug | your-plugin |
prefix() |
Database prefix | yourplugin_ |
textDomain() |
Translation domain | your-plugin |
version() |
Plugin version | 1.0.0 |
file() |
Main plugin file path | /path/to/your-plugin.php |
path($relative) |
Absolute path | /path/to/your-plugin/config/ |
url($relative) |
Plugin URL | https://site.com/wp-content/plugins/your-plugin/ |
hook($name) |
Prefixed hook name | yourplugin_custom_hook |
optionKey($key) |
Prefixed option key | yourplugin_settings |
transientKey($key) |
Prefixed transient key | yourplugin_cache |
cronHook($name) |
Prefixed cron hook | yourplugin_daily_task |
tableName($name) |
Full table name | wp_yourplugin_orders |
metaKey($key) |
Prefixed meta key | _yourplugin_data |
assetHandle($handle) |
Asset handle | your-plugin-main |
Global helpers available after bootstrap (app/Support/helpers.php):
// Escaping
zylos_e($text); // esc_html()
zylos_ea($text); // esc_attr()
zylos_eu($url); // esc_url()
zylos_ej($text); // esc_js()
zylos_kses($html); // wp_kses_post()
// Application
zylos_app(); // Get application instance
zylos_app('service'); // Resolve service from container
context(); // Get PluginContext
// Translation
zylos_m($text); // __($text, $textDomain)
zylos_em($text); // echo translated textreturn [
'name' => 'Your Plugin',
'debug' => defined('WP_DEBUG') && WP_DEBUG,
'providers' => [
// \YourPlugin\Providers\CustomServiceProvider::class,
],
'capability' => 'manage_options',
];The bootstrap (bootstrap/app.php) registers framework service providers in dependency order:
- ConfigServiceProvider — Configuration and .env loading
- I18nServiceProvider — Internationalization
- HookServiceProvider — WordPress hook management
- SecurityServiceProvider — Nonce, Gate, Sanitizer
- HttpServiceProvider — Request, Response, Pipeline
- ValidationServiceProvider — Input validation
- ViewsServiceProvider — Template rendering
- DatabaseServiceProvider — Database connection
- MigrationsServiceProvider — Schema migrations
- RoutingServiceProvider — URL routing
- WpCliServiceProvider — WP-CLI commands (when available)
Define routes in routes/web.php:
use WPZylos\Framework\Routing\Router;
return static function (Router $router): void {
// Frontend routes
$router->get('/products', [ProductController::class, 'index'])->name('products.index');
$router->get('/products/{id}', [ProductController::class, 'show'])->name('products.show');
$router->post('/cart/add', [CartController::class, 'add'])->name('cart.add');
// Route groups with middleware
$router->group(['prefix' => '/account', 'middleware' => AuthMiddleware::class], function (Router $router) {
$router->get('/dashboard', [AccountController::class, 'dashboard']);
$router->post('/update', [AccountController::class, 'update']);
});
};composer install # Install all dependencies
composer test # Run PHPUnit tests
composer analyze # Run PHPStan analysisUse the Scaffold CLI for production builds:
Windows (PowerShell):
.\scaffold.ps1 build # Full build (QA + Scoper + ZIP)
.\scaffold.ps1 build -SkipQA # Skip code style/analysis checks
.\scaffold.ps1 build -SkipScoper # Dev build (skip PHP-Scoper)Windows (Command Prompt):
powershell -ExecutionPolicy Bypass -File scaffold.ps1 build
powershell -ExecutionPolicy Bypass -File scaffold.ps1 build -SkipQA
powershell -ExecutionPolicy Bypass -File scaffold.ps1 build -SkipScoperLinux/Mac (or Git Bash):
./scaffold.sh build # Full build (QA + Scoper + ZIP)
./scaffold.sh build --skip-qa # Skip code style/analysis checks
./scaffold.sh build --skip-scoper # Dev build (skip PHP-Scoper)The build script will:
- Clean previous build artifacts
- Run
phpcbf --standard=PSR12(code style fix) - Run
phpstan analyze(static analysis) - Install production dependencies
- Run PHP-Scoper for namespace isolation
- Copy required files & rebuild autoloader
- Remove development files
- Create versioned ZIP in
dist/
Note: The build script reads configuration from
.plugin-config.json(created byscaffold init).
Intelligent Features:
- Smart File Discovery: Automatically detects project files/folders and prompts for unknown items
- Preference Persistence: Saves your include/exclude choices for future builds
- Auto-Versioning: Suggests next patch version based on existing ZIP files in
dist/ - Artifact Preservation: Preserves the
dist/directory with previous builds
The production build creates a zip file at dist/your-plugin-1.0.0.zip ready for deployment.
The scaffold includes pre-configured PHP-Scoper (scoper.inc.php) that:
- Prefixes all vendor namespaces for multi-plugin isolation
- Excludes WordPress core functions, classes, and constants
- Excludes your plugin's namespace
- Generates unique build prefixes using git hash
# Run all tests
composer test
# Or
./vendor/bin/phpunit
# Run specific test
./vendor/bin/phpunit --filter TestClassNameTests are located in tests/Unit/. The test bootstrap is at tests/bootstrap.php.
The scaffold implements WordPress security best practices:
- Nonce verification in form submissions
- Capability checks for user permissions
- Prepared statements for database queries
- Output escaping with proper functions
- Input sanitization before processing
See the Security Package for detailed security utilities.
php -v # Verify PHP 8.0+
php -m | grep json # Verify json extensioncomposer dump-autoloadVerify composer.json PSR-4 namespace matches your class namespace.
Check scoper.inc.php and ensure WordPress functions are excluded.
Verify WordPress symbols are excluded in scoper configuration.
| Package | Description |
|---|---|
| wpzylos-core | Application foundation |
| wpzylos-container | PSR-11 dependency injection container |
| wpzylos-config | Configuration management |
| wpzylos-routing | URL routing system |
| wpzylos-database | Database abstraction |
| wpzylos-migrations | Database migrations |
| wpzylos-hooks | WordPress hook management |
| wpzylos-security | Security utilities |
| wpzylos-validation | Input validation |
| wpzylos-views | Template rendering |
| wpzylos-http | HTTP request/response |
| wpzylos-i18n | Internationalization |
| wpzylos-wp-cli | WP-CLI integration |
For comprehensive documentation, tutorials, and API reference, visit wpzylos.com.
If you find this scaffold helpful, consider buying me a coffee! Your support helps maintain and improve the WPZylos ecosystem.
This project is licensed under the MIT License. See LICENSE for details.
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
Made with ❤️ by WPDiggerStudio