Aller au contenu

Portage des extensions WordPress

De nombreux plugins WordPress peuvent être adaptés pour EmDash. Le modèle de plugin est différent—TypeScript au lieu de PHP, hooks au lieu d’actions/filtres, stockage structuré au lieu de wp_options—mais la plupart des fonctionnalités se transposent clairement.

Tous les plugins ne sont pas pertinents à porter. Évaluez les candidats avant de commencer.

Bons candidats

Champs personnalisés, plugins SEO, processeurs de contenu, extensions d’interface d’administration, analytiques, partage social, formulaires

Mauvais candidats

Fonctionnalités multisite, intégrations WooCommerce/Gutenberg, plugins qui corrigent les internes du cœur de WordPress

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

WordPress utilise add_action() et add_filter() avec des noms de hooks sous forme de chaînes. EmDash utilise des hooks typés déclarés dans la définition du plugin.

WordPressEmDashNotes
register_activation_hook()plugin:installS’exécute une fois lors de la première installation
Plugin activéplugin:activateS’exécute lors de l’activation
Plugin désactivéplugin:deactivateS’exécute lors de la désactivation
register_uninstall_hook()plugin:uninstallevent.deleteData indique le choix de l’utilisateur
WordPressEmDashNotes
wp_insert_post_datacontent:beforeSaveRetourner le contenu modifié ou lancer une erreur pour annuler
save_postcontent:afterSaveEffets secondaires après la sauvegarde
before_delete_postcontent:beforeDeleteRetourner false pour annuler
deleted_postcontent:afterDeleteNettoyage après suppression
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);
WordPressEmDashNotes
wp_handle_upload_prefiltermedia:beforeUploadValider ou transformer
add_attachmentmedia:afterUploadRéagir après le téléchargement
php
$api_key = get_option('my_plugin_api_key', '');
update_option('my_plugin_api_key', 'abc123');
delete_option('my_plugin_api_key');

Tables personnalisées → Collections de stockage

Section intitulée « Tables personnalisées → Collections de stockage »
php
global $wpdb;
$table = $wpdb->prefix . 'my_plugin_items';
// Insertion
$wpdb->insert($table, ['name' => 'Item 1', 'status' => 'active']);
// Requête
$items = $wpdb->get_results(
"SELECT \* FROM $table WHERE status = 'active' LIMIT 10"
);

WordPress utilise l’API Settings pour les formulaires d’administration. EmDash utilise un schéma déclaratif qui génère automatiquement l’interface utilisateur.

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

Les pages d’administration de WordPress sont en PHP. EmDash utilise des composants 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>Total des éléments : {count}</div>
;
},
};
export const pages = {
settings: function SettingsPage() {
// React component for settings page
return <div>Settings content</div>
;
},
};

Enregistrez dans la définition du plugin :

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

Les routes sont disponibles à l’adresse /_emdash/api/plugins/{plugin-id}/{route-name}.

  1. Analysez le plugin WordPress

    Documentez ce qu’il fait : hooks, opérations de base de données, pages d’administration, points de terminaison REST.

  2. Mappez vers les concepts d’EmDash

    Hooks WordPress → Hooks EmDash. wp_options → ctx.kv. Tables personnalisées → Collections de stockage. Pages d’administration → Composants React. Points de terminaison REST → Routes de plugin.

  3. Créez le squelette du plugin

    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. Implémentez dans l’ordre

    Stockage → Hooks → Interface d’administration → Routes

  5. Testez minutieusement

    Vérifiez que les hooks se déclenchent correctement, que le stockage fonctionne et que l’interface d’administration s’affiche.

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

Les plugins doivent déclarer les capacités requises pour le sandboxing de sécurité :

CapacitéFournitCas d’utilisation
network:fetchctx.http.fetch()Appels API externes
read:contentctx.content.get(), list()Lecture du contenu CMS
write:contentctx.content.create(), etc.Modification du contenu
read:mediactx.media.get(), list()Lecture des médias
write:mediactx.media.getUploadUrl()Téléversement de médias

Pas d’état global — Utilisez le stockage au lieu des variables globales.

Tout est asynchrone — Toujours await les appels de stockage et d’API.

Pas de SQL direct — Utilisez les collections de stockage structuré.

Pas de système de fichiers — Utilisez l’API média pour les fichiers.