Guides

Creating Your First Module

Beginner~10 min

Build a Meteorack module: install the Hub plugin, scaffold a portable module, and verify it boots.

Prerequisites

  • A WordPress site with the Meteorack Hub plugin active.
  • WP-CLI access on the target environment.
  • Basic familiarity with editing PHP, JSON, and TypeScript files.

What You Will Finish With

  • Scaffold a module with the canonical runtime directory layout.
  • Understand the split between portable module code and WordPress bootstrap glue.
  • Activate the module and confirm the runtime recognizes it.

Meteorack modules are the replacement path for legacy WordPress plugins. You install the Hub plugin, which provides the runtime, and then create modules that register into it.

WordPress is the current host runtime, but not the permanent platform. Modules are built against portable SDK contracts so they can later run on other runtimes without rewriting.

Install the Hub plugin

The Hub plugin (meteorack-suite) is the install surface. It provides:

  • the module runtime loader
  • shared services (settings, events, cache, auth, etc.)
  • the admin UI shell
  • crash isolation and safe mode

Install and activate it like any WordPress plugin.

Scaffold the module

The runtime ships with a scaffold command that creates the canonical directory structure, bootstrap file, React entry, tests, and Vite config.

wp meteorack scaffold my-module

Generated structure

The scaffold creates two kinds of files:

  • Portable code (src/, module.json) — module logic that works across runtimes
  • WordPress bootstrap (bootstrap.php, includes/) — runtime-wp glue
wp-content/meteorack/modules/my-module/
├── module.json            ← Portable manifest (parsed by any runtime)
├── bootstrap.php          ← WordPress-specific bootstrap (runtime-wp glue)
├── includes/
│   ├── class-module.php
│   └── class-rest-routes.php
├── src/                   ← Portable frontend/admin code
│   ├── components/ExampleWidget.tsx
│   └── pages/MainPage.tsx
├── assets/
│   ├── package.json
│   └── vite.config.ts
├── migrations/
└── tests/
    ├── js/MainPage.test.tsx
    └── php/ModuleTest.php

module.json

The manifest describes the module's identity, compatibility, portable entry points, and runtime targets. It is parsed by any runtime, not just WordPress.

{
  "slug": "my-module",
  "name": "My Module",
  "version": "1.0.0",
  "minSdkVersion": "1.0.0",
  "maxTestedSdkVersion": "1.0.0",
  "description": "My first Meteorack module",
  "provider": "acme",
  "kind": "provider",
  "category": "Other",
  "tags": [],
  "builderConfigurable": false,
  "reactMode": "wp",
  "priority": 10,
  "capabilities": ["manage_options"],
  "requires": [],
  "runtimeTargets": ["wp"],
  "entrypoints": {
    "admin": ["my-module"],
    "wpBootstrap": "bootstrap.php"
  },
  "events": {
    "emits": [],
    "listens": []
  },
  "services": {
    "exposes": [],
    "requires": []
  },
  "settings": {
    "schema": ""
  },
  "healthCheck": false
}

bootstrap.php

The WordPress runtime loads bootstrap.php and expects it to return an AbstractModule instance. This file contains only WordPress-specific glue. Portable module logic should live in TypeScript under src/.

<?php

declare(strict_types=1);

use Meteorack\Sdk\Core\SdkContext;
use Meteorack\Sdk\RuntimeWp\AbstractModule;

class MyModule extends AbstractModule
{
    public function getSlug(): string { return 'my-module'; }
    public function getName(): string { return 'My Module'; }
    public function getVersion(): string { return '1.0.0'; }

    public function onSdkReady(SdkContext $ctx): void
    {
        parent::onSdkReady($ctx);

        $ctx->logger()->info('my_module.boot', []);
        $this->setSetting('enabled', true);
    }
}

return new MyModule();

Activate and verify

Activation validates module.json, capability requirements, dependencies, and signature rules before marking the module active.

wp meteorack modules activate my-module
wp meteorack modules list