コンテンツにスキップ

WordPressプラグインの移植

多くのWordPressプラグインはEmDashに移植できます。プラグインモデルは異なります(PHPの代わりにTypeScript、アクション/フィルターの代わりにフック、wp_optionsの代わりに構造化ストレージ)が、ほとんどの機能はきれいにマッピングできます。

すべてのプラグインが移植に適しているわけではありません。開始前に候補を評価してください。

適した候補

カスタムフィールド、SEOプラグイン、コンテンツプロセッサー、管理パネルUI拡張、アナリティクス、ソーシャル共有、フォーム

不適な候補

マルチサイト機能、WooCommerce/Gutenberg統合、WordPressコア内部をパッチするプラグイン

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

WordPressは文字列フック名を使用したadd_action()とadd_filter()を使用します。EmDashはプラグイン定義で宣言された型付きフックを使用します。

WordPressEmDash注記
register_activation_hook()plugin:install初回インストール時に一度実行
プラグイン有効化plugin:activate有効化時に実行
プラグイン無効化plugin:deactivate無効化時に実行
register_uninstall_hook()plugin:uninstallevent.deleteDataはユーザーの選択を示します
WordPressEmDash注記
wp_insert_post_datacontent:beforeSave変更されたコンテンツを返すか、キャンセルするためにスロー
save_postcontent:afterSave保存後の副作用
before_delete_postcontent:beforeDeletefalseを返してキャンセル
deleted_postcontent:afterDelete削除後のクリーンアップ
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);
WordPressEmDash注記
wp_handle_upload_prefiltermedia:beforeUpload検証または変換
add_attachmentmedia:afterUploadアップロード後に反応
php
$api_key = get_option('my_plugin_api_key', '');
update_option('my_plugin_api_key', 'abc123');
delete_option('my_plugin_api_key');

カスタムテーブル → ストレージコレクション

Section titled “カスタムテーブル → ストレージコレクション”
php
global $wpdb;
$table = $wpdb->prefix . 'my_plugin_items';
// 挿入
$wpdb->insert($table, ['name' => 'Item 1', 'status' => 'active']);
// クエリ
$items = $wpdb->get_results(
"SELECT \* FROM $table WHERE status = 'active' LIMIT 10"
);

WordPressは管理パネル用フォームにSettings APIを使用します。EmDashはUIを自動生成する宣言型スキーマを使用します。

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の管理パネルページはPHPです。EmDashはReactコンポーネントを使用します。

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>総アイテム数: {count}</div>
;
},
};
export const pages = {
settings: function SettingsPage() {
// React component for settings page
return <div>Settings content</div>
;
},
};

プラグイン定義で登録:

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);
},
]);

ルートは/_emdash/api/plugins/{plugin-id}/{route-name}で利用可能です。

  1. WordPressプラグインを分析

    機能を文書化: フック、データベース操作、管理パネルページ、RESTエンドポイント。

  2. EmDashの概念にマッピング

    WordPressフック → EmDashフック。wp_options → ctx.kv。カスタムテーブル → ストレージコレクション。管理パネルページ → Reactコンポーネント。RESTエンドポイント → プラグインルート。

  3. プラグインスケルトンを作成

    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. 順番に実装

    ストレージ → フック → 管理パネルUI → ルート

  5. 徹底的にテスト

    フックが正しく発火するか、ストレージが機能するか、管理パネルUIがレンダリングされるかを確認。

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);

プラグインはセキュリティサンドボックス化のために必要な機能を宣言する必要があります:

機能提供するもの使用例
network:fetchctx.http.fetch()外部API呼び出し
read:contentctx.content.get(), list()CMSコンテンツの読み取り
write:contentctx.content.create()などコンテンツの変更
read:mediactx.media.get(), list()メディアの読み取り
write:mediactx.media.getUploadUrl()メディアのアップロード

グローバル状態なし — グローバル変数の代わりにストレージを使用してください。

すべてが非同期 — ストレージとAPI呼び出しは常にawaitしてください。

直接SQLなし — 構造化ストレージコレクションを使用してください。

ファイルシステムなし — ファイルにはメディアAPIを使用してください。