A Wonderful Relations child plugin is a regular WordPress plugin that depends on the Wonderful Relations mother plugin and extends it with custom Projects, Entities, Forms, DataTables, ActionTypes, Tasks, Workers and so on. The mother plugin provides a small base class so every child gets the same lifecycle — activation, deactivation, update-center plumbing, admin menu, dependency checks — for free.
The four building blocks
| Concept | Purpose | Page |
|---|---|---|
AbstractChildPlugin | Base class your provider extends. Wires WR lifecycle hooks, activation/deactivation, update notices. | AbstractChildPlugin |
ChildPluginContext | Immutable builder that declares slug, version, modules bootstrap, menu, required plugins, cron, …. | ChildPluginContext |
Kernel | Default loader. Boots Resources, Modules, Menu, Update Center. | Kernel |
| Lifecycle hooks | Plugin-level signals you can listen to. | Lifecycle Hooks |
Minimal example
The plugin’s main file your-plugin.php becomes:
<?php
/**
* Plugin Name: Your WR Child Plugin
* Version: 1.0.0
* Text Domain: your-plugin
*/
require_once __DIR__ . '/vendor/autoload.php';
new \TS\YourPlugin\Plugin( __FILE__ );And the provider class src/Plugin.php:
namespace TS\YourPlugin;
use TS\WonderfulRelations\System\ChildPlugin\AbstractChildPlugin;
use TS\WonderfulRelations\System\ChildPlugin\ChildPluginContext;
final class Plugin extends AbstractChildPlugin {
public function __construct( private readonly string $main_file ) {
parent::__construct();
}
protected static function make_context(): ChildPluginContext {
return ChildPluginContext::create(
slug: 'your-plugin',
version: '1.0.0',
textdomain: 'your-plugin',
title: 'Your WR Child Plugin',
main_file: __FILE__ // resolved by the bootstrap above
)
->with_modules_bootstrap( \TS\YourPlugin\Modules\Init::class )
->with_dashboard_shortcode( 'your_plugin_dashboard' )
->with_menu_icon( 'dashicons-database' );
}
}Everything else — registering activation hooks, listening for
wonderful_relations_plugin_loaded, gating modules behind a pending
DB update, registering the admin menu — is derived from the context.
See Minimal Example for the full
walkthrough.
What you get for free
Once the provider is wired up, Wonderful Relations:
- Registers an
activation_hookthat bails with a friendly message if the mother plugin (or any required plugin) is missing. - Listens for
wonderful_relations_plugin_loadedso your modules boot after WR is fully initialized. - Gates module loading while a DB update is pending and shows a red admin banner with a link to the Update Center.
- Registers your admin menu with the configured icon and your dashboard shortcode as the entry page.
- Registers cron schedules from
with_cron_schedules()oninit. - Picks up
src/Database/Config/config.jsonif present and wires the Update Center for it.
Folder layout convention
your-plugin/
├── your-plugin.php # main file, calls new Plugin(__FILE__)
├── composer.json
├── src/
│ ├── Plugin.php # provider extends AbstractChildPlugin
│ ├── Modules/
│ │ ├── Init.php # bootstraps your ActionTypes / Tasks / …
│ │ ├── Person/
│ │ │ ├── Actions/
│ │ │ ├── Tasks/
│ │ │ └── …
│ │ └── …
│ └── Database/
│ └── Config/
│ └── config.json # optional: declarative migration plan
├── languages/
└── vendor/
This layout matches the wonderful-relations-plugin-template repo —
copy that template if you want a working starting point.
