Copy-paste patterns for common module tasks. Each example is self-contained and production-ready.
Use the SettingsInterface to register module settings with defaults and validation.
<?php
use Meteorack\SDK\Contracts\SettingsInterface;
class My_Module implements ModuleInterface {
public function __construct(
private readonly SettingsInterface $settings,
) {}
public function boot(): void {
$this->settings->register('my-module', [
'api_key' => '',
'enabled' => true,
'per_page' => 25,
]);
// Read a setting
$key = $this->settings->get('my-module', 'api_key');
// Update a setting
$this->settings->set('my-module', 'per_page', 50);
}
}Use the CacheInterface to cache API responses, query results, or computed data with TTL support.
<?php
use Meteorack\SDK\Contracts\CacheInterface;
use Meteorack\SDK\Contracts\HttpInterface;
class Data_Module implements ModuleInterface {
public function __construct(
private readonly CacheInterface $cache,
private readonly HttpInterface $http,
) {}
public function get_stats(): array {
$key = 'stats:dashboard';
// Return cached if available
if ($this->cache->has($key)) {
return $this->cache->get($key);
}
// Fetch fresh data
$stats = $this->http->get('/api/stats')->json();
// Cache for 5 minutes
$this->cache->set($key, $stats, 300);
return $stats;
}
}Use the EventsInterface to dispatch domain events and listen to events from other modules.
<?php
use Meteorack\SDK\Contracts\EventsInterface;
class Orders_Module implements ModuleInterface {
public function __construct(
private readonly EventsInterface $events,
) {}
public function boot(): void {
// Listen to events from other modules
$this->events->listen('payment.completed', [$this, 'on_payment']);
}
public function create_order(array $data): void {
$order = $this->save_order($data);
// Dispatch event for other modules
$this->events->dispatch('order.created', [
'order_id' => $order['id'],
'total' => $order['total'],
]);
}
public function on_payment(array $payload): void {
$this->mark_paid($payload['order_id']);
}
}Mount a full React application inside wp-admin with the Admin Takeover system.
import { createRoot } from 'react-dom/client';
import { useState, useEffect } from 'react';
function Dashboard() {
const [stats, setStats] = useState(null);
useEffect(() => {
// WordPress REST API is available
fetch('/wp-json/meteorack/v1/my-module/stats')
.then((r) => r.json())
.then(setStats);
}, []);
if (!stats) {
return (
<div className="animate-pulse space-y-4 p-8">
<div className="h-8 w-48 rounded bg-gray-200" />
<div className="h-32 rounded bg-gray-200" />
</div>
);
}
return (
<div className="p-8">
<h1 className="text-2xl font-bold">Dashboard</h1>
<div className="mt-6 grid grid-cols-3 gap-4">
{Object.entries(stats).map(([key, value]) => (
<div key={key} className="rounded-lg border p-4">
<p className="text-sm text-gray-500">{key}</p>
<p className="text-2xl font-bold">{String(value)}</p>
</div>
))}
</div>
</div>
);
}
createRoot(
document.getElementById('meteorack-module-root')!
).render(<Dashboard />);Wrap risky components in the SDK's error boundary to prevent full-page crashes in admin.
import { ModuleErrorBoundary } from '@meteorack/sdk/components';
function RiskyChart({ data }: { data: unknown[] }) {
// This might throw if data is malformed
return (
<div className="h-64">
{data.map((point, i) => (
<div
key={i}
className="inline-block w-2 bg-blue-500"
style={{ height: `${Number(point)}%` }}
/>
))}
</div>
);
}
export function SafeWidget({ data }: { data: unknown[] }) {
return (
<ModuleErrorBoundary
slug="my-module"
fallback={
<div className="rounded-lg border border-red-200 bg-red-50 p-4">
<p className="text-sm text-red-600">
Chart failed to render. Data may be corrupted.
</p>
</div>
}
>
<RiskyChart data={data} />
</ModuleErrorBoundary>
);
}Use the SchedulerInterface to run recurring tasks — cron jobs managed by the Hub with crash protection.
<?php
use Meteorack\SDK\Contracts\SchedulerInterface;
use Meteorack\SDK\Contracts\LoggerInterface;
class Cleanup_Module implements ModuleInterface {
public function __construct(
private readonly SchedulerInterface $scheduler,
private readonly LoggerInterface $logger,
) {}
public function boot(): void {
// Run daily at 3:00 AM
$this->scheduler->daily('cleanup:expired', [$this, 'cleanup'], '03:00');
// Run every 15 minutes
$this->scheduler->every(15, 'sync:external', [$this, 'sync']);
}
public function cleanup(): void {
$deleted = $this->delete_expired_records();
$this->logger->info('cleanup.completed', [
'deleted' => $deleted,
]);
}
public function sync(): void {
$this->logger->info('sync.started');
// Sync logic here
}
}Need more depth? Check the guides for full walkthroughs.