本教程以一個「心情發布」插件為例,手把手演示 WordPress 插件完整開發流程:目錄結構、文件頭聲明、安裝/卸載鉤子、建表、後台菜單頁面、AJAX 交互(增刪改查)、前端短代碼調用。適合零基礎開發者快速上手。
wp-content/plugins/
└── my-mood/
├── index.php # 主文件
├── uninstall.php # 協載腳本
├── js/
│ └── index.js # 前端 AJAX
└── css/
└── style.css # 後台樣式
二、安裝鉤子:啟用時建表
register_activation_hook(__FILE__, 'my_mood_install'); function my_mood_install() { global $wpdb; $table = $wpdb->prefix . 'mood'; $charset = $wpdb->get_charset_collate(); $sql = "CREATE TABLE $table ( id mediumint(9) NOT NULL AUTO_INCREMENT, createdon datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, publishedon datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, status int NOT NULL DEFAULT 1, mood int NOT NULL, text text NOT NULL, address varchar(55) DEFAULT '' NOT NULL, UNIQUE KEY id (id) ) $charset;"; require_once ABSPATH . 'wp-admin/includes/upgrade.php'; dbDelta($sql); // 智能建表/升級 }三、卸載腳本:刪表清理
// uninstall.php query("DROP TABLE IF EXISTS {$wpdb->prefix}mood");四、後台菜單與列表頁面
add_action('admin_menu', 'my_mood_create_menu'); function my_mood_create_menu() { add_menu_page( 'My Mood', // 頁面標題 'My Mood', // 菜單標題 'manage_options', // 權限 'my-mood', // menu slug 'my_mood_render_page' // 回調 ); } function my_mood_render_page() { global $wpdb; $table = $wpdb->prefix . 'mood'; $items = $wpdb->get_results("SELECT * FROM $table ORDER BY createdon DESC"); ?>五、AJAX 交互:載入 JS/CSS、註冊路由、處理增刪改
1. 載入前端資源
add_action('admin_enqueue_scripts', 'my_mood_enqueue_assets'); function my_mood_enqueue_assets($hook) { if ($hook !== 'toplevel_page_my-mood') return; // 僅在本插件頁載入 wp_enqueue_script('my-mood-js', plugin_dir_url(__FILE__) . 'js/index.js', ['jquery'], null, true); wp_enqueue_style('my-mood-css', plugin_dir_url(__FILE__) . 'css/style.css'); // 傳遞 nonce 給 JS wp_localize_script('my-mood-js', 'myMood', ['nonce' => wp_create_nonce('my_mood_nonce')]); }2. JS 交互邏輯
js/index.jsjQuery($ => { const $table = $('table.wp-list-table'); const nonce = myMood.nonce; // 添加 $table.on('click', '.add-mood', function() { const $tr = $(this).closest('tr'); post('add_mood', { text: $tr.find('[name=text]').val(), address: $tr.find('[name=address]').val(), mood: $tr.find('[name=mood]:checked').val() }, () => location.reload()); }); // 編輯 $table.on('click', '.edit-mood', function() { const $tr = $(this).closest('tr'); post('edit_mood', { id: $tr.data('id'), text: $tr.find('[name=text]').val(), address: $tr.find('[name=address]').val(), mood: $tr.find('[name=mood]:checked').val() }, () => location.reload()); }); // 刪除 $table.on('click', '.delete-mood', function() { if (!confirm('確定刪除?')) return; const $tr = $(this).closest('tr'); post('delete_mood', {id: $tr.data('id')}, () => location.reload()); }); function post(action, data, done) { data.action = action; data._nonce = nonce; $.post(ajaxurl, data, done); } });3. PHP AJAX 路由與處理器
// 註冊路由(wp_ajax_{action}) add_action('wp_ajax_add_mood', 'my_mood_ajax_add'); add_action('wp_ajax_edit_mood', 'my_mood_ajax_edit'); add_action('wp_ajax_delete_mood', 'my_mood_ajax_delete'); function my_mood_ajax_add() { check_ajax_referer('my_mood_nonce', '_nonce'); $data = [ 'createdon' => current_time('mysql'), 'publishedon' => current_time('mysql'), 'status' => 1, 'mood' => intval($_POST['mood']), 'text' => sanitize_text_field($_POST['text']), 'address' => sanitize_text_field($_POST['address']), ]; $wpdb->insert($wpdb->prefix . 'mood', $data); wp_send_json_success(); } function my_mood_ajax_edit() { check_ajax_referer('my_mood_nonce', '_nonce'); $id = intval($_POST['id']); $data = [ 'mood' => intval($_POST['mood']), 'text' => sanitize_text_field($_POST['text']), 'address' => sanitize_text_field($_POST['address']), ]; $wpdb->update($wpdb->prefix . 'mood', $data, ['id' => $id]); wp_send_json_success(); } function my_mood_ajax_delete() { check_ajax_referer('my_mood_nonce', '_nonce'); $wpdb->delete($wpdb->prefix . 'mood', ['id' => intval($_POST['id'])]); wp_send_json_success(); }六、前端調用:短代碼顯示最新心情
add_shortcode('my_mood_latest', 'my_mood_frontend_display'); function my_mood_frontend_display() { global $wpdb; $items = $wpdb->get_results("SELECT text, address, mood, createdon FROM {$wpdb->prefix}mood ORDER BY createdon DESC LIMIT 10"); if (!$items) return ''; $moodLabels = ['高興','一般','悲傷','憂慮','其他']; $html = ''; return $html; }'; foreach ($items as $item) { $html .= sprintf( '
- %s @ %s [%s]
', esc_html($item->text), esc_html($item->address), $item->mood, $moodLabels[$item->mood], $item->createdon ); } $html .= '前端頁面/文章中插入
[my_mood_latest]即可顯示最新 10 條心情。七、安全與最佳實踐清單
check_ajax_referermanage_options,前端操作用 current_user_cansanitize_text_field、esc_html、esc_attr、wp_kses_post$wpdb->prepare/insert/update/delete,禁用字符串拼接__()/_e(),生成 .pot 文件$hook)跟著教程敲一遍,你就擁有了屬於自己的 WordPress 插件開發脚手架,後續業務只需在這套結構上疊加即可。