콘텐츠로 이동

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 enabledplugin:activate활성화 시 실행
Plugin disabledplugin:deactivate비활성화 시 실행
register_uninstall_hook()plugin:uninstallevent.deleteData는 사용자 선택을 나타냄
WordPressEmDash참고
wp_insert_post_datacontent:beforeSave수정된 콘텐츠를 반환하거나 취소하려면 예외 발생
save_postcontent:afterSave저장 후 부작용
before_delete_postcontent:beforeDelete취소하려면 false 반환
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');

사용자 정의 테이블 → 저장소 컬렉션

섹션 제목: “사용자 정의 테이블 → 저장소 컬렉션”
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를 사용하세요.