A shared PHP base for WordPress projects, distributed as a Composer package
(rtcamp/wp-framework). It ships the contracts, loaders, and
utilities that plugins and themes boot through — so you write intent instead
of registration boilerplate.
wp-framework is a library, not a plugin. It ships contracts (interfaces,
abstracts, traits) plus concrete loaders and utilities; consuming plugins and
themes build their features on top. It has zero Composer runtime dependencies.
Requirements:
- PHP 8.2+
- WordPress 6.5+
- Composer
- The OpenSSL PHP extension when using
Encryptor
Not on public Packagist — add the repository to the consuming project's
composer.json, then require it with a caret constraint:
{
"repositories": [
{ "type": "vcs", "url": "https://github.com/rtCamp/wp-framework" }
]
}composer require rtcamp/wp-framework:^1.0(The repositories entry is unnecessary when the project already resolves this
package through an rtCamp-hosted Composer registry.)
PSR-4 autoloading: rtCamp\WPFramework\ → inc/.
use rtCamp\WPFramework\Contracts\Abstracts\AbstractPostType;
use rtCamp\WPFramework\Contracts\Traits\Loader;
use rtCamp\WPFramework\Contracts\Traits\Singleton;
final class ArticlePostType extends AbstractPostType {
public static function get_slug(): string { return 'article'; }
public function get_singular_label(): string { return __( 'Article', 'acme' ); }
public function get_plural_label(): string { return __( 'Articles', 'acme' ); }
public function get_menu_icon(): string { return 'dashicons-media-document'; }
}
final class Main {
use Loader;
use Singleton;
protected function __construct() {
static::$instance = $this; // before loading classes that can re-enter
$this->load( [ ArticlePostType::class ] ); // instantiates + registers hooks
}
}
Main::get_instance();A registered, REST-enabled post type with no register_post_type() call and no
init hook written by hand. Full walkthrough in
docs/getting-started.md.
- Registration core — the spine every consumer boots through:
Registrable,ConditionallyRegistrable,Shareable,CLICommandinterfaces- the
Loadertrait (instantiate a list of classes, register their hooks, cache the shared ones) and theContainerit stores instances in
- Ten
Abstract*base classes — one per WordPress registration chore, so a consumer writes intent instead of boilerplate:AbstractModule,AbstractPostType,AbstractTaxonomy,AbstractBlock,AbstractShortcode,AbstractRESTController,AbstractSettingsPage,AbstractAdminPage,AbstractUserRole,AbstractFeature - Asset & render loaders —
AssetLoader(scripts/styles/modules +*.asset.phpmanifests),ComponentLoaderandTemplateLoader(resolve components/templates across the child-theme → parent-theme → package hierarchy) Singletontrait — standardget_instance()with clone/wakeup guards- Utilities & services (
inc/Utils/) — context-scoped helpers:Encryptor— authenticated AES-256-GCM encryption for values stored in the DBCache— typed wrapper over the WP object cache, group-namespaced, optional SWRFeatureSelector+FeatureSelectorSettingsPage— a fail-closed feature-flag registry and its admin toggle pageLogger— context-prefixed,WP_DEBUG-gated loggingTimer— named request-scoped timers and lapsTransients— prefix-namespaced transient storage
The contract surface (inc/Contracts/) is the public API: every interface,
abstract, and signature there is consumed by dependents, so changes to it are
treated as breaking.
- No bootstrap /
Mainclass. The framework gives you theLoadertrait and the contracts; each consumer writes its own entry class that kicks off the firstload(). The framework is the spine, not the application. - No project scaffolding engine. Scaffold/init tooling lives in a separate
package (
@rtcamp/wp-tooling), not here.
Start with docs/index.md, then:
| Doc | What it covers |
|---|---|
| getting-started.md | Install, bootstrap a plugin or theme, load a module, and share a service. |
| architecture.md | How a class becomes a live hook — the Registrable → Loader → Container flow. Read first. |
| contracts.md | The interfaces and traits in detail. |
| abstracts.md | Cookbook for the Abstract* base classes. |
| loaders.md | AssetLoader, ComponentLoader, TemplateLoader and the theme-override hierarchy. |
| utilities.md | Encryptor, Cache, feature flags, logging, transients, timers, and Container. |
| upgrading.md | What changes between releases and what a consumer has to do about it. |
| troubleshooting.md | Symptom → cause for the errors and silent no-ops the framework emits. |
| ai-review-system.md | How the AI review instructions are authored here and synced into the skeletons. |
| maintainers.md | Development environment, tests, change checklist, and documentation maintenance. |
composer install
npm ci
npm run wp-env start
composer lint
composer analyse
npm run test:phpTests run against real WordPress via @wordpress/env.
Use npm run test:php, which runs PHPUnit inside the wp-env test container;
composer test only works directly when a host WordPress test suite has been
configured. See docs/maintainers.md for the complete
workflow.
See CONTRIBUTING.md.
GPL-2.0-or-later © rtCamp
