sympress / kernel
WordPress kernel and shared service container built on Symfony DependencyInjection.
Requires
- php: >=8.4.1
- ext-dom: *
- ext-json: *
- psr/clock: ^1.0
- psr/event-dispatcher: ^1.0
- psr/log: ^3.0
- symfony/clock: ^8.0
- symfony/config: ^8.0
- symfony/console: ^8.0
- symfony/dependency-injection: ^8.1
- symfony/event-dispatcher: ^8.0
- symfony/expression-language: ^8.0
- symfony/filesystem: ^8.0
- symfony/service-contracts: ^3.6
- symfony/yaml: ^8.0
Requires (Dev)
- phpunit/phpunit: ^11.5
- sympress/coding-standards: @dev
This package is auto-updated.
Last update: 2026-06-13 04:15:47 UTC
README
sympress/kernel is the foundation package for SymPress. It gives WordPress
projects one Symfony-powered application kernel, one shared dependency injection
container, and a predictable way for Composer packages, plugins, MU plugins, and
themes to contribute services.
WordPress stays the runtime. The kernel adds structure around bootstrapping, configuration, hooks, console commands, package discovery, and compiled service containers.
Why This Exists
WordPress projects often grow through plugin boot files, global functions, and runtime hook registration. That works well at small scale, but it becomes hard to test and hard to reason about once several packages need to collaborate.
The kernel keeps the parts WordPress is good at:
- the normal plugin, MU plugin, and theme lifecycle
- WordPress hooks as the integration boundary
- Composer packages that can be adopted one at a time
Then it adds the Symfony patterns that pay off in larger codebases:
- constructor-injected services
- bundle-level configuration
- compiler passes and autoconfiguration
- declarative hooks
- cached runtime containers
- Symfony-compatible bundle lifecycle hooks
- resettable services and service subscribers
- testable package boundaries
Requirements
- PHP
>=8.4.1 - Composer
- WordPress
- Symfony DependencyInjection
^8.1, Config, Console, Filesystem, Service Contracts, EventDispatcher, Clock, ExpressionLanguage, and Yaml components
Installation
composer require sympress/kernel
Boot the kernel from an MU plugin or another early WordPress bootstrap file:
<?php declare(strict_types=1); use SymPress\Kernel\App; use SymPress\Kernel\Kernel\SiteKernel; require dirname(__DIR__, 2) . '/vendor/autoload.php'; App::bootKernel(new SiteKernel(dirname(__DIR__, 2)));
After the kernel has booted, services can be resolved from the shared application container:
$mailer = App::make(App\Mailer\TransactionalMailer::class);
Minimal Bundle
SymPress discovers installed Composer packages that expose extra.kernel
metadata. Projects that want to narrow discovery can set
extra.kernel.package_prefixes in the root composer.json.
{
"name": "sympress/project-plugin",
"type": "wordpress-plugin",
"extra": {
"kernel": {
"bundle": "SymPress\\ProjectPlugin\\ProjectPluginBundle",
"entry": "project-plugin/project-plugin.php"
}
}
}
The bundle class can stay small:
<?php declare(strict_types=1); namespace SymPress\ProjectPlugin; use SymPress\Kernel\Bundle\AbstractBundle; final class ProjectPluginBundle extends AbstractBundle { }
Add package services in Resources/config/services.yaml:
services: _defaults: autowire: true autoconfigure: true public: false SymPress\ProjectPlugin\: resource: '../../src/' exclude: - '../../src/ProjectPluginBundle.php'
Register a WordPress hook declaratively:
<?php declare(strict_types=1); namespace SymPress\ProjectPlugin\Admin; use SymPress\Kernel\Attribute\AsHook; final class AdminMenu { #[AsHook('admin_menu')] public function register(): void { add_options_page('Project', 'Project', 'manage_options', 'project', [$this, 'render']); } public function render(): void { echo '<div class="wrap"><h1>Project</h1></div>'; } }
The same hook can be registered with a service tag when central configuration is clearer:
services: SymPress\ProjectPlugin\Admin\AdminMenu: tags: - { name: kernel.hook, hook: 'admin_menu', method: register }
Architecture
The runtime model has four layers:
Appowns the singleton application instance and coordinates booting.SiteKernelextendsAbstractKerneland describes the WordPress site.BundleDiscoveryfinds active kernel packages and creates aBundleRegistry.Containerimplements Symfony's container interface, wraps aContainerBuilder, then delegates to the compiled runtime container after boot.
Configuration is loaded in this order:
- kernel package defaults
- discovered bundle
Resources/config/directories - site root
config/directory
Within each config directory, the kernel loads:
packages/*.{php,yaml,yml,ini}packages/{environment}/*.{php,yaml,yml,ini}services.{php,yaml,yml,ini}services_{environment}.{php,yaml,yml,ini}wordpress.{php,yaml,yml,ini}wordpress_{environment}.{php,yaml,yml,ini}
Files are imported through Symfony's DelegatingLoader with PHP, YAML, INI,
glob, directory, and closure loaders. The kernel file locator also understands
Symfony-style bundle resources such as @ProjectPlugin/Resources/config/foo.yaml.
The compiled container is cached under var/cache/{environment}/kernel.
In debug mode, source and config contents are fingerprinted more strictly. In
production, cache invalidation follows file mtimes, composer.lock, or the
optional SYMPRESS_KERNEL_BUILD_ID value.
Extension Points
Use these points before adding work to plugin boot files:
- Override
AbstractKernel::build(ContainerBuilder $builder)for site-wide compiler passes or global container customization. - Add
DependencyInjection/{BundleName}Extensionto expose classic Symfony-style bundle configuration. The kernel registers it automatically. - Or keep configuration directly in the bundle with Symfony 8.1's
configure(),prependExtension(), andloadExtension()methods. When no classic extension class exists, the kernel uses Symfony'sBundleExtension. - Override
AbstractBundle::build(ContainerBuilder $builder)for package-level compiler passes. Callparent::build($builder)when you want to preserve the automatic extension registration from custom build logic. - Add
Resources/config/services.php,Resources/config/services.yaml,Resources/config/wordpress.php,.inivariants, or environment-specific variants for package configuration. Package-levelconfig/is still loaded as a compatibility fallback. - Use the
kernel.hookservice tag or#[AsHook]attribute for WordPress actions and filters. - Use Symfony's
#[AsCommand]attribute to expose console commands through the kernel console integration. - Use Symfony DI attributes from the component directly, including
#[Autowire],#[AutowireIterator],#[AutowireLocator],#[AsAlias],#[AsDecorator],#[AsTagDecorator],#[AutowireDecorated],#[AutowireCallable],#[AutowireMethodOf],#[AutowireServiceClosure],#[AutowireInline],#[Required],#[Target],#[When],#[WhenNot],#[Lazy],#[AutoconfigureResourceTag], and#[Exclude]. - Use Symfony's
#[RequiredBundle]attribute when one bundle must be loaded before another. Missing optional requirements can useignoreOnInvalid: true. - Depend on the synthetic services
SymPress\Kernel\Container,SymPress\Kernel\SiteConfig,SymPress\Kernel\WpContext,SymPress\Kernel\Kernel\KernelInterface, andSymPress\Kernel\Appwhen a service needs runtime context.
Core Services
The runtime container exposes Symfony-compatible core IDs and aliases:
kernelservice_containerparameter_bagevent_dispatcherfilesystemclockfile_locatorreverse_containerconfig_cache_factoryservices_resettercontainer.env_var_processorcontainer.expression_languagekernel.containerkernel.configkernel.contextkernel.kernelkernel.app
Symfony\Contracts\Service\ResetInterface services are autoconfigured with the
kernel.reset tag and wired into services_resetter.
When the optional Symfony components are installed, EventDispatcher listeners,
subscribers, LoggerAwareInterface, Clock aliases, and PSR/EventDispatcher
aliases are autoconfigured in the same style as Symfony's DI ServicesBundle.
Console
Commands tagged with console.command or marked with #[AsCommand] are exposed
through the kernel console integration. The kernel also ships lightweight
container tooling:
wp console debug:container wp console debug:container --parameters wp console debug:container --env-vars wp console debug:container --tag=kernel.hook --types wp console debug:container app --types --show-arguments wp console lint:container wp console container:dump --format=yaml
Documentation
More focused docs live in docs/:
docs/boot-and-bundles.mddocs/services-and-autowiring.mddocs/attributes.mddocs/hooks.mddocs/showcase-plugin.md
Development
composer install composer tests composer qa
License
This package is licensed under GPL-2.0-or-later.