Zum Inhalt springen

Portierung von WordPress-Plugins

Viele WordPress-Plugins können zu EmDash portiert werden. Das Plugin-Modell ist anders – TypeScript statt PHP, Hooks statt Actions/Filter, strukturierter Speicher statt wp_options – aber die meisten Funktionen lassen sich sauber abbilden.

Nicht alle Plugins sind sinnvoll zu portieren. Bewerten Sie Kandidaten, bevor Sie beginnen.

Gute Kandidaten

Benutzerdefinierte Felder, SEO-Plugins, Content-Prozessoren, Admin-UI-Erweiterungen, Analytics, Social Sharing, Formulare

Schlechte Kandidaten

Multisite-Funktionen, WooCommerce-/Gutenberg-Integrationen, Plugins, die WordPress-Core-Interna patchen

wp-content/plugins/my-plugin/
├── my-plugin.php # Main file with plugin header
├── includes/
│ ├── class-admin.php
│ └── class-api.php
└── admin/
└── js/

WordPress verwendet add_action() und add_filter() mit String-Hook-Namen. EmDash verwendet typisierte Hooks, die in der Plugin-Definition deklariert werden.

WordPressEmDashAnmerkungen
register_activation_hook()plugin:installLäuft einmal bei der ersten Installation
Plugin aktiviertplugin:activateLäuft bei Aktivierung
Plugin deaktiviertplugin:deactivateLäuft bei Deaktivierung
register_uninstall_hook()plugin:uninstallevent.deleteData zeigt Benutzerauswahl an
WordPressEmDashAnmerkungen
wp_insert_post_datacontent:beforeSaveModifizierten Inhalt zurückgeben oder abbrechen
save_postcontent:afterSaveNebeneffekte nach dem Speichern
before_delete_postcontent:beforeDeletefalse zurückgeben, um abzubrechen
deleted_postcontent:afterDeleteBereinigung nach Löschung
php
add_action('save_post', function($post_id, $post, $update) {
if ($post->post_type !== 'product') return;
$price = get_post_meta($post_id, 'price', true);
if ($price > 1000) {
update_post_meta($post_id, 'is_premium', true);
}
}, 10, 3);
WordPressEmDashAnmerkungen
wp_handle_upload_prefiltermedia:beforeUploadValidieren oder transformieren
add_attachmentmedia:afterUploadNach Upload reagieren
php
$api_key = get_option('my_plugin_api_key', '');
update_option('my_plugin_api_key', 'abc123');
delete_option('my_plugin_api_key');

Benutzerdefinierte Tabellen → Storage Collections

Abschnitt betitelt „Benutzerdefinierte Tabellen → Storage Collections“
php
global $wpdb;
$table = $wpdb->prefix . 'my_plugin_items';
// Einfügen
$wpdb->insert($table, ['name' => 'Item 1', 'status' => 'active']);
// Abfrage
$items = $wpdb->get_results(
"SELECT \* FROM $table WHERE status = 'active' LIMIT 10"
);

WordPress verwendet die Settings API für Admin-Formulare. EmDash verwendet ein deklaratives Schema, das automatisch die UI generiert.

php
add_action('admin_init', function() {
register_setting('my_plugin', 'my_plugin_api_key');
add_settings_section('main', 'Settings', null, 'my-plugin');
add_settings_field('api_key', 'API Key', function() {
$value = get_option('my_plugin_api_key');
echo '<input type="text" name="my_plugin_api_key"
value="' . esc_attr($value) . '">';
}, 'my-plugin', 'main');
});

WordPress-Admin-Seiten sind PHP. EmDash verwendet React-Komponenten.

tsx title="src/admin.tsx"
import { useState, useEffect } from "react";
export const widgets = {
summary: function SummaryWidget() {
const [count, setCount] = useState(0);
useEffect(() => {
fetch("/_emdash/api/plugins/my-plugin/status")
.then((r) => r.json())
.then((data) => setCount(data.count));
}, []);
return <div>Gesamtanzahl Elemente: {count}</div>
;
},
};
export const pages = {
settings: function SettingsPage() {
// React component for settings page
return <div>Settings content</div>
;
},
};

In der Plugin-Definition registrieren:

typescript title="src/index.ts"
admin: {
entry: "@my-org/my-plugin/admin",
pages: [{ path: "/settings", label: "Dashboard" }],
widgets: [{ id: "summary", title: "Summary", size: "half" }],
},
php
register_rest_route('my-plugin/v1', '/items', [
'methods' => 'GET',
'callback' => function($request) {
global $wpdb;
$items = $wpdb->get_results("SELECT * FROM items LIMIT 50");
return new WP_REST_Response($items);
},
]);

Routen sind verfügbar unter /_emdash/api/plugins/{plugin-id}/{route-name}.

  1. WordPress-Plugin analysieren

    Dokumentieren Sie, was es tut: Hooks, Datenbankoperationen, Admin-Seiten, REST-Endpunkte.

  2. Auf EmDash-Konzepte abbilden

    WordPress-Hooks → EmDash-Hooks. wp_options → ctx.kv. Benutzerdefinierte Tabellen → Storage Collections. Admin-Seiten → React-Komponenten. REST-Endpunkte → Plugin-Routen.

  3. Plugin-Grundgerüst erstellen

    src/index.ts
    import { definePlugin } from "emdash";
    export function createPlugin() {
    return definePlugin({
    id: "my-ported-plugin",
    version: "1.0.0",
    capabilities: [],
    storage: {},
    hooks: {},
    routes: {},
    admin: {},
    });
    }
  4. In Reihenfolge implementieren

    Speicher → Hooks → Admin-UI → Routen

  5. Gründlich testen

    Überprüfen Sie, ob Hooks korrekt ausgelöst werden, der Speicher funktioniert und die Admin-UI gerendert wird.

php
add_filter('wp_insert_post_data', function($data, $postarr) {
if ($data['post_type'] !== 'post') return $data;
$content = strip_tags($data['post_content']);
$word_count = str_word_count($content);
$read_time = ceil($word_count / 200);
if (!empty($postarr['ID'])) {
update_post_meta($postarr['ID'], '_read_time', $read_time);
}
return $data;
}, 10, 2);

Plugins müssen aus Sicherheitsgründen für die Sandbox erforderliche Fähigkeiten deklarieren:

FähigkeitBietet Zugriff aufAnwendungsfall
network:fetchctx.http.fetch()Externe API-Aufrufe
read:contentctx.content.get(), list()Lesen von CMS-Inhalten
write:contentctx.content.create(), etc.Ändern von Inhalten
read:mediactx.media.get(), list()Lesen von Medien
write:mediactx.media.getUploadUrl()Hochladen von Medien

Kein globaler Zustand — Verwende Speicher statt globaler Variablen.

Alles asynchron — Warte immer mit await auf Speicher- und API-Aufrufe.

Kein direkter SQL — Verwende strukturierte Speichersammlungen.

Kein Dateisystem — Verwende die Media-API für Dateien.