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

ConceptPurposePage
AbstractChildPluginBase class your provider extends. Wires WR lifecycle hooks, activation/deactivation, update notices.AbstractChildPlugin
ChildPluginContextImmutable builder that declares slug, version, modules bootstrap, menu, required plugins, cron, ….ChildPluginContext
KernelDefault loader. Boots Resources, Modules, Menu, Update Center.Kernel
Lifecycle hooksPlugin-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_hook that bails with a friendly message if the mother plugin (or any required plugin) is missing.
  • Listens for wonderful_relations_plugin_loaded so 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() on init.
  • Picks up src/Database/Config/config.json if 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.