文章目录
-
- 在当今数字化工作环境中,高效的团队协作工具已成为企业提升生产力的关键因素。虽然市面上已有Trello、Asana、Jira等专业协作工具,但许多企业仍面临数据孤岛、定制化不足和高昂成本等问题。此时,利用WordPress构建内部协作平台成为一个值得考虑的解决方案。 WordPress作为全球最流行的内容管理系统,占据互联网超过43%的网站份额。其优势不仅在于易用性和庞大的插件生态,更在于其开源特性带来的无限定制可能。通过代码二次开发,我们可以将WordPress从一个简单的博客系统转变为功能强大的内部协作平台,同时集成各种常用互联网小工具,打造一体化工作环境。 本教程将详细指导您如何通过WordPress二次开发,构建一个包含任务看板、团队协作和常用工具的综合性平台,既能满足特定业务需求,又能保持成本可控。
-
- 在开始开发前,我们需要搭建一个适合的开发环境。推荐使用本地开发环境,如Local by Flywheel、XAMPP或MAMP,这些工具可以快速配置PHP、MySQL和Web服务器环境。 对于团队协作平台的开发,建议选择以下技术栈: WordPress 5.8或更高版本 PHP 7.4或更高版本(推荐PHP 8.0+) MySQL 5.6或更高版本 代码编辑器(VS Code、PHPStorm等) 安装WordPress后,需要进行一些基础配置优化: 设置固定链接结构为“文章名”模式,便于API调用 禁用不必要的插件和主题,保持系统简洁 配置WP_DEBUG模式,便于开发调试
- 对于团队协作平台,我们有两种开发方式:创建自定义主题或开发独立插件。考虑到协作功能的独立性,建议创建专用插件,这样可以在任何主题上使用。 创建插件的基本结构: team-collaboration-platform/ ├── team-collaboration-platform.php ├── includes/ │ ├── class-database.php │ ├── class-task-manager.php │ └── class-user-manager.php ├── assets/ │ ├── css/ │ ├── js/ │ └── images/ ├── templates/ ├── languages/ └── vendor/ 插件主文件头部信息: <?php /** * Plugin Name: 团队协作与任务看板平台 * Plugin URI: https://yourcompany.com/ * Description: 基于WordPress的团队协作、任务管理和工具集成平台 * Version: 1.0.0 * Author: 您的团队 * License: GPL v2 or later */
-
- 团队协作平台需要存储任务、项目、团队成员关系等复杂数据。虽然可以使用WordPress自带的文章类型,但对于复杂关系,创建自定义表更为合适。 创建数据库表的示例代码: class Collaboration_Database { public function create_tables() { global $wpdb; $charset_collate = $wpdb->get_charset_collate(); // 项目表 $projects_table = $wpdb->prefix . 'collab_projects'; $projects_sql = "CREATE TABLE IF NOT EXISTS $projects_table ( id mediumint(9) NOT NULL AUTO_INCREMENT, name varchar(200) NOT NULL, description text, status varchar(50) DEFAULT 'active', created_by bigint(20) NOT NULL, created_at datetime DEFAULT CURRENT_TIMESTAMP, updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id) ) $charset_collate;"; // 任务表 $tasks_table = $wpdb->prefix . 'collab_tasks'; $tasks_sql = "CREATE TABLE IF NOT EXISTS $tasks_table ( id mediumint(9) NOT NULL AUTO_INCREMENT, project_id mediumint(9) NOT NULL, title varchar(500) NOT NULL, description longtext, status varchar(50) DEFAULT 'todo', priority varchar(20) DEFAULT 'medium', assignee_id bigint(20), due_date date, estimated_hours decimal(5,2), actual_hours decimal(5,2) DEFAULT 0, created_by bigint(20) NOT NULL, created_at datetime DEFAULT CURRENT_TIMESTAMP, updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY project_id (project_id), KEY assignee_id (assignee_id) ) $charset_collate;"; // 团队成员关系表 $team_members_table = $wpdb->prefix . 'collab_team_members'; $team_members_sql = "CREATE TABLE IF NOT EXISTS $team_members_table ( id mediumint(9) NOT NULL AUTO_INCREMENT, project_id mediumint(9) NOT NULL, user_id bigint(20) NOT NULL, role varchar(50) DEFAULT 'member', joined_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY project_user (project_id, user_id) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($projects_sql); dbDelta($tasks_sql); dbDelta($team_members_sql); } }
- WordPress自带的用户角色系统可能无法满足团队协作的复杂需求,我们需要扩展或创建自定义角色系统。 创建自定义用户角色和权限: class User_Role_Manager { public function add_collaboration_roles() { // 添加项目经理角色 add_role('project_manager', '项目经理', array( 'read' => true, 'edit_posts' => true, 'delete_posts' => true, 'publish_posts' => true, 'upload_files' => true, 'manage_collab_projects' => true, 'assign_collab_tasks' => true, 'edit_collab_tasks' => true, 'delete_collab_tasks' => false, )); // 添加团队成员角色 add_role('team_member', '团队成员', array( 'read' => true, 'edit_posts' => true, 'upload_files' => true, 'edit_assigned_tasks' => true, 'update_task_status' => true, )); } public function add_capabilities_to_roles() { // 为管理员添加所有协作权限 $admin_role = get_role('administrator'); $admin_role->add_cap('manage_collab_projects'); $admin_role->add_cap('assign_collab_tasks'); $admin_role->add_cap('edit_collab_tasks'); $admin_role->add_cap('delete_collab_tasks'); $admin_role->add_cap('view_all_tasks'); } }
-
- 看板(Kanban)是团队协作中常用的任务可视化工具。我们将使用HTML5、CSS3和JavaScript(配合Vue.js或React)创建交互式看板界面。 创建看板主模板: class Task_Kanban { public function display_kanban_board($project_id = null) { ob_start(); ?> <div id="task-kanban-app" data-project-id="<?php echo esc_attr($project_id); ?>"> <div class="kanban-header"> <h2>任务看板</h2> <div class="kanban-actions"> <button class="add-task-btn" @click="showAddTaskModal">+ 添加任务</button> <button class="filter-btn" @click="toggleFilters">筛选</button> </div> </div> <div class="kanban-filters" v-if="showFilters"> <!-- 筛选条件组件 --> </div> <div class="kanban-board"> <div class="kanban-column" v-for="column in columns" :key="column.id"> <div class="column-header"> <h3>{{ column.name }} ({{ column.tasks.length }})</h3> </div> <div class="column-body" @dragover.prevent @drop="dropTask($event, column.id)"> <div class="task-card" v-for="task in column.tasks" :key="task.id" draggable="true" @dragstart="dragTask($event, task.id)"> <div class="task-priority" :class="'priority-' + task.priority"></div> <div class="task-content"> <h4>{{ task.title }}</h4> <p class="task-description">{{ task.description | truncate(100) }}</p> <div class="task-meta"> <span class="assignee">{{ task.assignee_name }}</span> <span class="due-date" :class="{ 'overdue': task.isOverdue }"> {{ task.due_date | formatDate }} </span> </div> </div> </div> </div> </div> </div> <!-- 任务详情模态框 --> <div class="modal" v-if="showTaskModal"> <!-- 模态框内容 --> </div> </div> <?php return ob_get_clean(); } }
- 实现拖放功能和实时更新是看板系统的核心。我们将使用HTML5 Drag & Drop API和WebSocket或AJAX轮询实现实时同步。 JavaScript拖放实现: // 在Vue组件中实现拖放逻辑 const TaskKanban = { data() { return { columns: [ { id: 'todo', name: '待处理', tasks: [] }, { id: 'in_progress', name: '进行中', tasks: [] }, { id: 'review', name: '审核中', tasks: [] }, { id: 'done', name: '已完成', tasks: [] } ], draggedTaskId: null, showFilters: false, showTaskModal: false }; }, methods: { dragTask(event, taskId) { event.dataTransfer.setData('text/plain', taskId); this.draggedTaskId = taskId; }, async dropTask(event, columnId) { event.preventDefault(); const taskId = event.dataTransfer.getData('text/plain'); // 发送AJAX请求更新任务状态 try { const response = await fetch('/wp-json/collab/v1/tasks/' + taskId, { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': collabData.nonce }, body: JSON.stringify({ status: columnId }) }); if (response.ok) { this.moveTaskToColumn(taskId, columnId); this.showNotification('任务状态已更新', 'success'); } } catch (error) { console.error('更新任务失败:', error); this.showNotification('更新失败,请重试', 'error'); } }, moveTaskToColumn(taskId, targetColumnId) { // 在前端移动任务卡片 let task = null; let sourceColumnIndex = -1; // 查找任务所在列 this.columns.forEach((column, colIndex) => { const taskIndex = column.tasks.findIndex(t => t.id == taskId); if (taskIndex !== -1) { task = column.tasks[taskIndex]; sourceColumnIndex = colIndex; column.tasks.splice(taskIndex, 1); } }); // 将任务添加到目标列 if (task && sourceColumnIndex !== -1) { const targetColumn = this.columns.find(col => col.id === targetColumnId); if (targetColumn) { task.status = targetColumnId; targetColumn.tasks.push(task); } } }, // 实时更新任务状态 setupRealTimeUpdates() { // 使用WebSocket或AJAX轮询 if ('WebSocket' in window) { this.setupWebSocket(); } else { this.setupPolling(); } }, setupWebSocket() { const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const wsUrl = `${protocol}//${window.location.host}/ws/collab`; this.ws = new WebSocket(wsUrl); this.ws.onmessage = (event) => { const data = JSON.parse(event.data); if (data.type === 'task_update') { this.updateTask(data.task); } else if (data.type === 'task_created') { this.addTask(data.task); } }; } }, mounted() { this.loadTasks(); this.setupRealTimeUpdates(); } };
-
- 团队协作离不开实时沟通。我们将集成一个简单的实时聊天系统,支持一对一和群组聊天。 聊天系统数据库设计: // 聊天消息表 $chat_messages_sql = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}collab_chat_messages ( id bigint(20) NOT NULL AUTO_INCREMENT, room_id varchar(100) NOT NULL, sender_id bigint(20) NOT NULL, message_type varchar(20) DEFAULT 'text', content text NOT NULL, attachment_id bigint(20), parent_id bigint(20), is_read tinyint(1) DEFAULT 0, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY room_id (room_id), KEY sender_id (sender_id), KEY created_at (created_at) ) $charset_collate;"; // 聊天室表 $chat_rooms_sql = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}collab_chat_rooms ( id varchar(100) NOT NULL, name varchar(200), type varchar(20) DEFAULT 'direct', -- direct, group, project project_id mediumint(9), created_by bigint(20), created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) $charset_collate;"; // 聊天室成员表 $chat_room_members_sql = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}collab_chat_room_members ( id bigint(20) NOT NULL AUTO_INCREMENT, room_id varchar(100) NOT NULL, user_id bigint(20) NOT NULL, joined_at datetime DEFAULT CURRENT_TIMESTAMP, last_seen_at datetime, PRIMARY KEY (id), UNIQUE KEY room_user (room_id, user_id) ) $charset_collate;"; 实时聊天前端实现: class ChatSystem { constructor() { this.socket = null; this.currentRoom = null; this.initialize(); } initialize() { this.connectWebSocket(); this.bindEvents(); this.loadChatRooms(); } connectWebSocket() { const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const wsUrl = `${protocol}//${window.location.host}/ws/chat`; this.socket = new WebSocket(wsUrl); this.socket.onopen = () => { console.log('WebSocket连接已建立'); this.authenticate(); }; this.socket.onmessage = (event) => { this.handleMessage(JSON.parse(event.data)); }; this.socket.onclose = () => { console.log('WebSocket连接已关闭,尝试重连...'); setTimeout(() => this.connectWebSocket(), 3000); }; } authenticate() { this.send({ type: 'auth', token: this.getAuthToken() }); } sendMessage(content, roomId) { const message = { type: 'chat_message', room_id: roomId, content: content, timestamp: new Date().toISOString() }; this.send(message); // 本地显示消息 this.displayMessage({ ...message, sender_id: currentUserId, sender_name: currentUserName, is_own: true }); } handleMessage(data) { switch (data.type) { case 'chat_message': this.displayMessage(data.message); break; case 'user_online': this.updateUserStatus(data.user_id, true); break; case 'user_offline': this.updateUserStatus(data.user_id, false); break; case 'typing': this.showTypingIndicator(data.user_id, data.room_id); break; } } displayMessage(message) { const chatContainer = document.querySelector(`.chat-room[data-room-id="${message.room_id}"] .chat-messages`); const messageElement = document.createElement('div'); messageElement.className = `chat-message ${message.is_own ? 'own-message' : 'other-message'}`; messageElement.innerHTML = ` <div class="message-sender">${message.sender_name}</div> <div class="message-content">${this.formatMessageContent(message)}</div> <div class="message-time">${this.formatTime(message.timestamp)}</div> `; chatContainer.appendChild(messageElement); chatContainer.scrollTop = chatContainer.scrollHeight; // 播放消息提示音(如果不是自己的消息) if (!message.is_own) { this.playNotificationSound(); } } }
- 文件共享是团队协作的重要功能。我们将扩展WordPress媒体库,添加团队共享文件夹和版本控制功能。 文件共享系统实现: class File_Sharing_System {
- class File_Sharing_System { public function create_team_folders() { // 为每个项目创建专用文件夹 add_action('project_created', function($project_id) { $project = $this->get_project($project_id); $folder_name = sanitize_title($project->name) . '-' . $project_id; $upload_dir = wp_upload_dir(); $team_folder = $upload_dir['basedir'] . '/team-files/' . $folder_name; if (!file_exists($team_folder)) { wp_mkdir_p($team_folder); // 创建子文件夹结构 $subfolders = ['documents', 'images', 'designs', 'code', 'archive']; foreach ($subfolders as $subfolder) { wp_mkdir_p($team_folder . '/' . $subfolder); } // 记录文件夹信息到数据库 $this->save_folder_to_db($project_id, $folder_name, $team_folder); } }); } public function handle_file_upload($file, $project_id, $user_id) { // 验证文件类型和大小 $allowed_types = $this->get_allowed_file_types(); $max_size = 100 * 1024 * 1024; // 100MB if ($file['size'] > $max_size) { return new WP_Error('file_too_large', '文件大小不能超过100MB'); } $file_ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); if (!in_array($file_ext, $allowed_types)) { return new WP_Error('invalid_file_type', '不支持的文件类型'); } // 生成唯一文件名 $unique_name = wp_unique_filename($this->get_project_upload_dir($project_id), $file['name']); // 移动文件 $destination = $this->get_project_upload_dir($project_id) . '/' . $unique_name; if (move_uploaded_file($file['tmp_name'], $destination)) { // 保存文件信息到数据库 $file_id = $this->save_file_metadata(array( 'project_id' => $project_id, 'user_id' => $user_id, 'original_name' => $file['name'], 'file_name' => $unique_name, 'file_path' => $destination, 'file_size' => $file['size'], 'file_type' => $file_ext, 'version' => 1 )); // 生成缩略图(如果是图片) if (in_array($file_ext, ['jpg', 'jpeg', 'png', 'gif'])) { $this->generate_thumbnails($destination, $file_id); } return $file_id; } return new WP_Error('upload_failed', '文件上传失败'); } public function create_file_version($file_id, $new_file, $user_id, $comment = '') { global $wpdb; // 获取原文件信息 $original = $wpdb->get_row($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}collab_files WHERE id = %d", $file_id )); if (!$original) { return new WP_Error('file_not_found', '文件不存在'); } // 创建新版本 $new_version = $original->version + 1; // 保存旧版本到版本历史 $wpdb->insert("{$wpdb->prefix}collab_file_versions", array( 'file_id' => $file_id, 'version' => $original->version, 'file_name' => $original->file_name, 'file_path' => $original->file_path, 'user_id' => $user_id, 'comment' => $comment, 'created_at' => current_time('mysql') )); // 更新主文件记录 $wpdb->update("{$wpdb->prefix}collab_files", array( 'file_name' => $new_file['name'], 'file_path' => $new_file['path'], 'file_size' => $new_file['size'], 'version' => $new_version, 'updated_at' => current_time('mysql') ), array('id' => $file_id)); return $new_version; } public function get_file_version_history($file_id) { global $wpdb; return $wpdb->get_results($wpdb->prepare( "SELECT v.*, u.display_name as user_name FROM {$wpdb->prefix}collab_file_versions v LEFT JOIN {$wpdb->users} u ON v.user_id = u.ID WHERE v.file_id = %d ORDER BY v.version DESC", $file_id )); } }
-
- class Code_Collaboration_Tool { public function init() { // 注册代码片段自定义文章类型 add_action('init', array($this, 'register_code_snippet_post_type')); // 添加代码编辑器短代码 add_shortcode('code_editor', array($this, 'code_editor_shortcode')); // 注册REST API端点 add_action('rest_api_init', array($this, 'register_code_api')); } public function register_code_snippet_post_type() { $args = array( 'public' => true, 'label' => '代码片段', 'supports' => array('title', 'editor', 'author', 'revisions'), 'show_in_rest' => true, 'capability_type' => 'code_snippet', 'capabilities' => array( 'edit_posts' => 'edit_code_snippets', 'edit_others_posts' => 'edit_others_code_snippets', 'publish_posts' => 'publish_code_snippets', 'read_post' => 'read_code_snippet', 'delete_post' => 'delete_code_snippet' ) ); register_post_type('code_snippet', $args); } public function code_editor_shortcode($atts) { $atts = shortcode_atts(array( 'language' => 'javascript', 'theme' => 'monokai', 'height' => '400px', 'readonly' => false, 'snippet_id' => 0 ), $atts); ob_start(); ?> <div class="code-collaboration-editor" data-language="<?php echo esc_attr($atts['language']); ?>" data-theme="<?php echo esc_attr($atts['theme']); ?>" data-snippet-id="<?php echo esc_attr($atts['snippet_id']); ?>"> <div class="editor-toolbar"> <select class="language-selector"> <option value="javascript">JavaScript</option> <option value="php">PHP</option> <option value="python">Python</option> <option value="html">HTML</option> <option value="css">CSS</option> <option value="sql">SQL</option> </select> <button class="run-code-btn">运行代码</button> <button class="save-code-btn">保存</button> <button class="share-code-btn">分享</button> <div class="collaborators"> <span class="online-users">在线用户: <span class="count">0</span></span> </div> </div> <div class="editor-container" style="height: <?php echo esc_attr($atts['height']); ?>;"> <div class="code-editor" id="code-editor-<?php echo uniqid(); ?>"></div> </div> <div class="output-container"> <div class="output-header">输出结果</div> <div class="output-content"></div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { initializeCodeEditor('code-editor-<?php echo uniqid(); ?>', { language: '<?php echo $atts["language"]; ?>', theme: '<?php echo $atts["theme"]; ?>', readonly: <?php echo $atts["readonly"] ? 'true' : 'false'; ?>, snippetId: <?php echo $atts["snippet_id"]; ?> }); }); </script> <?php return ob_get_clean(); } public function register_code_api() { register_rest_route('collab/v1', '/code/execute', array( 'methods' => 'POST', 'callback' => array($this, 'execute_code'), 'permission_callback' => function() { return current_user_can('edit_code_snippets'); } )); register_rest_route('collab/v1', '/code/save', array( 'methods' => 'POST', 'callback' => array($this, 'save_code_snippet'), 'permission_callback' => function() { return current_user_can('edit_code_snippets'); } )); } public function execute_code($request) { $code = $request->get_param('code'); $language = $request->get_param('language'); // 安全执行代码(使用沙箱环境) $result = $this->safe_execute_code($code, $language); return rest_ensure_response(array( 'success' => true, 'output' => $result['output'], 'error' => $result['error'], 'execution_time' => $result['execution_time'] )); } }
- class API_Testing_Tool { private $endpoints = array(); public function init() { add_action('admin_menu', array($this, 'add_api_testing_page')); add_action('wp_ajax_save_api_endpoint', array($this, 'save_api_endpoint')); add_action('wp_ajax_test_api_endpoint', array($this, 'test_api_endpoint')); add_action('wp_ajax_save_webhook', array($this, 'save_webhook')); } public function add_api_testing_page() { add_menu_page( 'API测试工具', 'API测试', 'manage_options', 'api-testing-tool', array($this, 'render_api_testing_page'), 'dashicons-rest-api', 30 ); } public function render_api_testing_page() { ?> <div class="wrap api-testing-tool"> <h1>API测试与Webhook管理</h1> <div class="api-tool-container"> <!-- API测试界面 --> <div class="api-tester-section"> <h2>API请求测试</h2> <div class="request-builder"> <div class="request-method"> <select id="request-method"> <option value="GET">GET</option> <option value="POST">POST</option> <option value="PUT">PUT</option> <option value="DELETE">DELETE</option> <option value="PATCH">PATCH</option> </select> <input type="text" id="request-url" placeholder="https://api.example.com/endpoint" style="width: 60%;"> <button id="send-request" class="button button-primary">发送请求</button> </div> <div class="request-tabs"> <ul> <li><a href="#params-tab">参数</a></li> <li><a href="#headers-tab">请求头</a></li> <li><a href="#body-tab">请求体</a></li> <li><a href="#auth-tab">认证</a></li> </ul> <div id="params-tab"> <table class="params-table"> <thead> <tr> <th>参数名</th> <th>值</th> <th>操作</th> </tr> </thead> <tbody id="params-body"> <tr> <td><input type="text" class="param-key" placeholder="参数名"></td> <td><input type="text" class="param-value" placeholder="值"></td> <td><button class="remove-param button">删除</button></td> </tr> </tbody> </table> <button id="add-param" class="button">添加参数</button> </div> <div id="headers-tab"> <!-- 请求头配置界面 --> </div> <div id="body-tab"> <select id="body-type"> <option value="none">无</option> <option value="form-data">表单数据</option> <option value="x-www-form-urlencoded">x-www-form-urlencoded</option> <option value="raw">原始数据</option> <option value="json">JSON</option> </select> <textarea id="request-body" rows="10" style="width: 100%;"></textarea> </div> <div id="auth-tab"> <!-- 认证配置界面 --> </div> </div> </div> <div class="response-section"> <h3>响应结果</h3> <div class="response-info"> <div class="response-status"> 状态码: <span id="response-status">-</span> 响应时间: <span id="response-time">-</span>ms 大小: <span id="response-size">-</span> </div> <div class="response-tabs"> <ul> <li><a href="#response-body-tab">响应体</a></li> <li><a href="#response-headers-tab">响应头</a></li> <li><a href="#response-cookies-tab">Cookies</a></li> </ul> <div id="response-body-tab"> <pre id="response-body"></pre> </div> <div id="response-headers-tab"> <pre id="response-headers"></pre> </div> </div> </div> </div> </div> <!-- Webhook管理界面 --> <div class="webhook-manager-section"> <h2>Webhook管理</h2> <button id="add-webhook" class="button button-primary">添加Webhook</button> <table class="wp-list-table widefat fixed striped"> <thead> <tr> <th>名称</th> <th>URL</th> <th>事件</th> <th>状态</th> <th>最后触发</th> <th>操作</th> </tr> </thead> <tbody id="webhooks-list"> <?php $this->render_webhooks_list(); ?> </tbody> </table> <div class="webhook-details" style="display: none;"> <h3>Webhook详情</h3> <form id="webhook-form"> <input type="hidden" id="webhook-id"> <table class="form-table"> <tr> <th><label for="webhook-name">名称</label></th> <td><input type="text" id="webhook-name" class="regular-text" required></td> </tr> <tr> <th><label for="webhook-url">URL</label></th> <td><input type="url" id="webhook-url" class="regular-text" required></td> </tr> <tr> <th><label for="webhook-events">触发事件</label></th> <td> <select id="webhook-events" multiple style="width: 100%; height: 100px;"> <option value="task_created">任务创建</option> <option value="task_updated">任务更新</option> <option value="task_completed">任务完成</option> <option value="file_uploaded">文件上传</option> <option value="comment_added">评论添加</option> <option value="user_joined">用户加入</option> </select> </td> </tr> <tr> <th><label for="webhook-secret">签名密钥</label></th> <td> <input type="text" id="webhook-secret" class="regular-text"> <button type="button" id="generate-secret" class="button">生成密钥</button> </td> </tr> <tr> <th><label for="webhook-active">状态</label></th> <td> <label> <input type="checkbox" id="webhook-active" checked> 启用 </label> </td> </tr> </table> <div class="submit"> <button type="submit" class="button button-primary">保存</button> <button type="button" id="cancel-webhook" class="button">取消</button> <button type="button" id="test-webhook" class="button">测试Webhook</button> </div> </form> </div> </div> </div> </div> <script> jQuery(document).ready(function($) { // API测试功能 $('#send-request').on('click', function() { const method = $('#request-method').val(); const url = $('#request-url').val(); const params = {}; $('#params-body tr').each(function() { const key = $(this).find('.param-key').val();
在当今数字化工作环境中,高效的团队协作工具已成为企业提升生产力的关键因素。虽然市面上已有Trello、Asana、Jira等专业协作工具,但许多企业仍面临数据孤岛、定制化不足和高昂成本等问题。此时,利用WordPress构建内部协作平台成为一个值得考虑的解决方案。
WordPress作为全球最流行的内容管理系统,占据互联网超过43%的网站份额。其优势不仅在于易用性和庞大的插件生态,更在于其开源特性带来的无限定制可能。通过代码二次开发,我们可以将WordPress从一个简单的博客系统转变为功能强大的内部协作平台,同时集成各种常用互联网小工具,打造一体化工作环境。
本教程将详细指导您如何通过WordPress二次开发,构建一个包含任务看板、团队协作和常用工具的综合性平台,既能满足特定业务需求,又能保持成本可控。
在开始开发前,我们需要搭建一个适合的开发环境。推荐使用本地开发环境,如Local by Flywheel、XAMPP或MAMP,这些工具可以快速配置PHP、MySQL和Web服务器环境。
对于团队协作平台的开发,建议选择以下技术栈:
- WordPress 5.8或更高版本
- PHP 7.4或更高版本(推荐PHP 8.0+)
- MySQL 5.6或更高版本
- 代码编辑器(VS Code、PHPStorm等)
安装WordPress后,需要进行一些基础配置优化:
- 设置固定链接结构为“文章名”模式,便于API调用
- 禁用不必要的插件和主题,保持系统简洁
- 配置WP_DEBUG模式,便于开发调试
对于团队协作平台,我们有两种开发方式:创建自定义主题或开发独立插件。考虑到协作功能的独立性,建议创建专用插件,这样可以在任何主题上使用。
创建插件的基本结构:
team-collaboration-platform/
├── team-collaboration-platform.php
├── includes/
│ ├── class-database.php
│ ├── class-task-manager.php
│ └── class-user-manager.php
├── assets/
│ ├── css/
│ ├── js/
│ └── images/
├── templates/
├── languages/
└── vendor/
插件主文件头部信息:
<?php
/**
* Plugin Name: 团队协作与任务看板平台
* Plugin URI: https://yourcompany.com/
* Description: 基于WordPress的团队协作、任务管理和工具集成平台
* Version: 1.0.0
* Author: 您的团队
* License: GPL v2 or later
*/
团队协作平台需要存储任务、项目、团队成员关系等复杂数据。虽然可以使用WordPress自带的文章类型,但对于复杂关系,创建自定义表更为合适。
创建数据库表的示例代码:
class Collaboration_Database {
public function create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
// 项目表
$projects_table = $wpdb->prefix . 'collab_projects';
$projects_sql = "CREATE TABLE IF NOT EXISTS $projects_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
name varchar(200) NOT NULL,
description text,
status varchar(50) DEFAULT 'active',
created_by bigint(20) NOT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) $charset_collate;";
// 任务表
$tasks_table = $wpdb->prefix . 'collab_tasks';
$tasks_sql = "CREATE TABLE IF NOT EXISTS $tasks_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
project_id mediumint(9) NOT NULL,
title varchar(500) NOT NULL,
description longtext,
status varchar(50) DEFAULT 'todo',
priority varchar(20) DEFAULT 'medium',
assignee_id bigint(20),
due_date date,
estimated_hours decimal(5,2),
actual_hours decimal(5,2) DEFAULT 0,
created_by bigint(20) NOT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY project_id (project_id),
KEY assignee_id (assignee_id)
) $charset_collate;";
// 团队成员关系表
$team_members_table = $wpdb->prefix . 'collab_team_members';
$team_members_sql = "CREATE TABLE IF NOT EXISTS $team_members_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
project_id mediumint(9) NOT NULL,
user_id bigint(20) NOT NULL,
role varchar(50) DEFAULT 'member',
joined_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY project_user (project_id, user_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($projects_sql);
dbDelta($tasks_sql);
dbDelta($team_members_sql);
}
}
WordPress自带的用户角色系统可能无法满足团队协作的复杂需求,我们需要扩展或创建自定义角色系统。
创建自定义用户角色和权限:
class User_Role_Manager {
public function add_collaboration_roles() {
// 添加项目经理角色
add_role('project_manager', '项目经理', array(
'read' => true,
'edit_posts' => true,
'delete_posts' => true,
'publish_posts' => true,
'upload_files' => true,
'manage_collab_projects' => true,
'assign_collab_tasks' => true,
'edit_collab_tasks' => true,
'delete_collab_tasks' => false,
));
// 添加团队成员角色
add_role('team_member', '团队成员', array(
'read' => true,
'edit_posts' => true,
'upload_files' => true,
'edit_assigned_tasks' => true,
'update_task_status' => true,
));
}
public function add_capabilities_to_roles() {
// 为管理员添加所有协作权限
$admin_role = get_role('administrator');
$admin_role->add_cap('manage_collab_projects');
$admin_role->add_cap('assign_collab_tasks');
$admin_role->add_cap('edit_collab_tasks');
$admin_role->add_cap('delete_collab_tasks');
$admin_role->add_cap('view_all_tasks');
}
}
看板(Kanban)是团队协作中常用的任务可视化工具。我们将使用HTML5、CSS3和JavaScript(配合Vue.js或React)创建交互式看板界面。
创建看板主模板:
class Task_Kanban {
public function display_kanban_board($project_id = null) {
ob_start();
?>
<div id="task-kanban-app" data-project-id="<?php echo esc_attr($project_id); ?>">
<div class="kanban-header">
<h2>任务看板</h2>
<div class="kanban-actions">
<button class="add-task-btn" @click="showAddTaskModal">+ 添加任务</button>
<button class="filter-btn" @click="toggleFilters">筛选</button>
</div>
</div>
<div class="kanban-filters" v-if="showFilters">
<!-- 筛选条件组件 -->
</div>
<div class="kanban-board">
<div class="kanban-column" v-for="column in columns" :key="column.id">
<div class="column-header">
<h3>{{ column.name }} ({{ column.tasks.length }})</h3>
</div>
<div class="column-body"
@dragover.prevent
@drop="dropTask($event, column.id)">
<div class="task-card"
v-for="task in column.tasks"
:key="task.id"
draggable="true"
@dragstart="dragTask($event, task.id)">
<div class="task-priority" :class="'priority-' + task.priority"></div>
<div class="task-content">
<h4>{{ task.title }}</h4>
<p class="task-description">{{ task.description | truncate(100) }}</p>
<div class="task-meta">
<span class="assignee">{{ task.assignee_name }}</span>
<span class="due-date" :class="{ 'overdue': task.isOverdue }">
{{ task.due_date | formatDate }}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 任务详情模态框 -->
<div class="modal" v-if="showTaskModal">
<!-- 模态框内容 -->
</div>
</div>
<?php
return ob_get_clean();
}
}
实现拖放功能和实时更新是看板系统的核心。我们将使用HTML5 Drag & Drop API和WebSocket或AJAX轮询实现实时同步。
JavaScript拖放实现:
// 在Vue组件中实现拖放逻辑
const TaskKanban = {
data() {
return {
columns: [
{ id: 'todo', name: '待处理', tasks: [] },
{ id: 'in_progress', name: '进行中', tasks: [] },
{ id: 'review', name: '审核中', tasks: [] },
{ id: 'done', name: '已完成', tasks: [] }
],
draggedTaskId: null,
showFilters: false,
showTaskModal: false
};
},
methods: {
dragTask(event, taskId) {
event.dataTransfer.setData('text/plain', taskId);
this.draggedTaskId = taskId;
},
async dropTask(event, columnId) {
event.preventDefault();
const taskId = event.dataTransfer.getData('text/plain');
// 发送AJAX请求更新任务状态
try {
const response = await fetch('/wp-json/collab/v1/tasks/' + taskId, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': collabData.nonce
},
body: JSON.stringify({
status: columnId
})
});
if (response.ok) {
this.moveTaskToColumn(taskId, columnId);
this.showNotification('任务状态已更新', 'success');
}
} catch (error) {
console.error('更新任务失败:', error);
this.showNotification('更新失败,请重试', 'error');
}
},
moveTaskToColumn(taskId, targetColumnId) {
// 在前端移动任务卡片
let task = null;
let sourceColumnIndex = -1;
// 查找任务所在列
this.columns.forEach((column, colIndex) => {
const taskIndex = column.tasks.findIndex(t => t.id == taskId);
if (taskIndex !== -1) {
task = column.tasks[taskIndex];
sourceColumnIndex = colIndex;
column.tasks.splice(taskIndex, 1);
}
});
// 将任务添加到目标列
if (task && sourceColumnIndex !== -1) {
const targetColumn = this.columns.find(col => col.id === targetColumnId);
if (targetColumn) {
task.status = targetColumnId;
targetColumn.tasks.push(task);
}
}
},
// 实时更新任务状态
setupRealTimeUpdates() {
// 使用WebSocket或AJAX轮询
if ('WebSocket' in window) {
this.setupWebSocket();
} else {
this.setupPolling();
}
},
setupWebSocket() {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${protocol}//${window.location.host}/ws/collab`;
this.ws = new WebSocket(wsUrl);
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'task_update') {
this.updateTask(data.task);
} else if (data.type === 'task_created') {
this.addTask(data.task);
}
};
}
},
mounted() {
this.loadTasks();
this.setupRealTimeUpdates();
}
};
团队协作离不开实时沟通。我们将集成一个简单的实时聊天系统,支持一对一和群组聊天。
聊天系统数据库设计:
// 聊天消息表
$chat_messages_sql = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}collab_chat_messages (
id bigint(20) NOT NULL AUTO_INCREMENT,
room_id varchar(100) NOT NULL,
sender_id bigint(20) NOT NULL,
message_type varchar(20) DEFAULT 'text',
content text NOT NULL,
attachment_id bigint(20),
parent_id bigint(20),
is_read tinyint(1) DEFAULT 0,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY room_id (room_id),
KEY sender_id (sender_id),
KEY created_at (created_at)
) $charset_collate;";
// 聊天室表
$chat_rooms_sql = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}collab_chat_rooms (
id varchar(100) NOT NULL,
name varchar(200),
type varchar(20) DEFAULT 'direct', -- direct, group, project
project_id mediumint(9),
created_by bigint(20),
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) $charset_collate;";
// 聊天室成员表
$chat_room_members_sql = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}collab_chat_room_members (
id bigint(20) NOT NULL AUTO_INCREMENT,
room_id varchar(100) NOT NULL,
user_id bigint(20) NOT NULL,
joined_at datetime DEFAULT CURRENT_TIMESTAMP,
last_seen_at datetime,
PRIMARY KEY (id),
UNIQUE KEY room_user (room_id, user_id)
) $charset_collate;";
实时聊天前端实现:
class ChatSystem {
constructor() {
this.socket = null;
this.currentRoom = null;
this.initialize();
}
initialize() {
this.connectWebSocket();
this.bindEvents();
this.loadChatRooms();
}
connectWebSocket() {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${protocol}//${window.location.host}/ws/chat`;
this.socket = new WebSocket(wsUrl);
this.socket.onopen = () => {
console.log('WebSocket连接已建立');
this.authenticate();
};
this.socket.onmessage = (event) => {
this.handleMessage(JSON.parse(event.data));
};
this.socket.onclose = () => {
console.log('WebSocket连接已关闭,尝试重连...');
setTimeout(() => this.connectWebSocket(), 3000);
};
}
authenticate() {
this.send({
type: 'auth',
token: this.getAuthToken()
});
}
sendMessage(content, roomId) {
const message = {
type: 'chat_message',
room_id: roomId,
content: content,
timestamp: new Date().toISOString()
};
this.send(message);
// 本地显示消息
this.displayMessage({
...message,
sender_id: currentUserId,
sender_name: currentUserName,
is_own: true
});
}
handleMessage(data) {
switch (data.type) {
case 'chat_message':
this.displayMessage(data.message);
break;
case 'user_online':
this.updateUserStatus(data.user_id, true);
break;
case 'user_offline':
this.updateUserStatus(data.user_id, false);
break;
case 'typing':
this.showTypingIndicator(data.user_id, data.room_id);
break;
}
}
displayMessage(message) {
const chatContainer = document.querySelector(`.chat-room[data-room-id="${message.room_id}"] .chat-messages`);
const messageElement = document.createElement('div');
messageElement.className = `chat-message ${message.is_own ? 'own-message' : 'other-message'}`;
messageElement.innerHTML = `
<div class="message-sender">${message.sender_name}</div>
<div class="message-content">${this.formatMessageContent(message)}</div>
<div class="message-time">${this.formatTime(message.timestamp)}</div>
`;
chatContainer.appendChild(messageElement);
chatContainer.scrollTop = chatContainer.scrollHeight;
// 播放消息提示音(如果不是自己的消息)
if (!message.is_own) {
this.playNotificationSound();
}
}
}
文件共享是团队协作的重要功能。我们将扩展WordPress媒体库,添加团队共享文件夹和版本控制功能。
文件共享系统实现:
class File_Sharing_System {
class File_Sharing_System {
public function create_team_folders() {
// 为每个项目创建专用文件夹
add_action('project_created', function($project_id) {
$project = $this->get_project($project_id);
$folder_name = sanitize_title($project->name) . '-' . $project_id;
$upload_dir = wp_upload_dir();
$team_folder = $upload_dir['basedir'] . '/team-files/' . $folder_name;
if (!file_exists($team_folder)) {
wp_mkdir_p($team_folder);
// 创建子文件夹结构
$subfolders = ['documents', 'images', 'designs', 'code', 'archive'];
foreach ($subfolders as $subfolder) {
wp_mkdir_p($team_folder . '/' . $subfolder);
}
// 记录文件夹信息到数据库
$this->save_folder_to_db($project_id, $folder_name, $team_folder);
}
});
}
public function handle_file_upload($file, $project_id, $user_id) {
// 验证文件类型和大小
$allowed_types = $this->get_allowed_file_types();
$max_size = 100 * 1024 * 1024; // 100MB
if ($file['size'] > $max_size) {
return new WP_Error('file_too_large', '文件大小不能超过100MB');
}
$file_ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($file_ext, $allowed_types)) {
return new WP_Error('invalid_file_type', '不支持的文件类型');
}
// 生成唯一文件名
$unique_name = wp_unique_filename($this->get_project_upload_dir($project_id), $file['name']);
// 移动文件
$destination = $this->get_project_upload_dir($project_id) . '/' . $unique_name;
if (move_uploaded_file($file['tmp_name'], $destination)) {
// 保存文件信息到数据库
$file_id = $this->save_file_metadata(array(
'project_id' => $project_id,
'user_id' => $user_id,
'original_name' => $file['name'],
'file_name' => $unique_name,
'file_path' => $destination,
'file_size' => $file['size'],
'file_type' => $file_ext,
'version' => 1
));
// 生成缩略图(如果是图片)
if (in_array($file_ext, ['jpg', 'jpeg', 'png', 'gif'])) {
$this->generate_thumbnails($destination, $file_id);
}
return $file_id;
}
return new WP_Error('upload_failed', '文件上传失败');
}
public function create_file_version($file_id, $new_file, $user_id, $comment = '') {
global $wpdb;
// 获取原文件信息
$original = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}collab_files WHERE id = %d", $file_id
));
if (!$original) {
return new WP_Error('file_not_found', '文件不存在');
}
// 创建新版本
$new_version = $original->version + 1;
// 保存旧版本到版本历史
$wpdb->insert("{$wpdb->prefix}collab_file_versions", array(
'file_id' => $file_id,
'version' => $original->version,
'file_name' => $original->file_name,
'file_path' => $original->file_path,
'user_id' => $user_id,
'comment' => $comment,
'created_at' => current_time('mysql')
));
// 更新主文件记录
$wpdb->update("{$wpdb->prefix}collab_files", array(
'file_name' => $new_file['name'],
'file_path' => $new_file['path'],
'file_size' => $new_file['size'],
'version' => $new_version,
'updated_at' => current_time('mysql')
), array('id' => $file_id));
return $new_version;
}
public function get_file_version_history($file_id) {
global $wpdb;
return $wpdb->get_results($wpdb->prepare(
"SELECT v.*, u.display_name as user_name
FROM {$wpdb->prefix}collab_file_versions v
LEFT JOIN {$wpdb->users} u ON v.user_id = u.ID
WHERE v.file_id = %d
ORDER BY v.version DESC",
$file_id
));
}
}
class File_Sharing_System {
public function create_team_folders() {
// 为每个项目创建专用文件夹
add_action('project_created', function($project_id) {
$project = $this->get_project($project_id);
$folder_name = sanitize_title($project->name) . '-' . $project_id;
$upload_dir = wp_upload_dir();
$team_folder = $upload_dir['basedir'] . '/team-files/' . $folder_name;
if (!file_exists($team_folder)) {
wp_mkdir_p($team_folder);
// 创建子文件夹结构
$subfolders = ['documents', 'images', 'designs', 'code', 'archive'];
foreach ($subfolders as $subfolder) {
wp_mkdir_p($team_folder . '/' . $subfolder);
}
// 记录文件夹信息到数据库
$this->save_folder_to_db($project_id, $folder_name, $team_folder);
}
});
}
public function handle_file_upload($file, $project_id, $user_id) {
// 验证文件类型和大小
$allowed_types = $this->get_allowed_file_types();
$max_size = 100 * 1024 * 1024; // 100MB
if ($file['size'] > $max_size) {
return new WP_Error('file_too_large', '文件大小不能超过100MB');
}
$file_ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($file_ext, $allowed_types)) {
return new WP_Error('invalid_file_type', '不支持的文件类型');
}
// 生成唯一文件名
$unique_name = wp_unique_filename($this->get_project_upload_dir($project_id), $file['name']);
// 移动文件
$destination = $this->get_project_upload_dir($project_id) . '/' . $unique_name;
if (move_uploaded_file($file['tmp_name'], $destination)) {
// 保存文件信息到数据库
$file_id = $this->save_file_metadata(array(
'project_id' => $project_id,
'user_id' => $user_id,
'original_name' => $file['name'],
'file_name' => $unique_name,
'file_path' => $destination,
'file_size' => $file['size'],
'file_type' => $file_ext,
'version' => 1
));
// 生成缩略图(如果是图片)
if (in_array($file_ext, ['jpg', 'jpeg', 'png', 'gif'])) {
$this->generate_thumbnails($destination, $file_id);
}
return $file_id;
}
return new WP_Error('upload_failed', '文件上传失败');
}
public function create_file_version($file_id, $new_file, $user_id, $comment = '') {
global $wpdb;
// 获取原文件信息
$original = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}collab_files WHERE id = %d", $file_id
));
if (!$original) {
return new WP_Error('file_not_found', '文件不存在');
}
// 创建新版本
$new_version = $original->version + 1;
// 保存旧版本到版本历史
$wpdb->insert("{$wpdb->prefix}collab_file_versions", array(
'file_id' => $file_id,
'version' => $original->version,
'file_name' => $original->file_name,
'file_path' => $original->file_path,
'user_id' => $user_id,
'comment' => $comment,
'created_at' => current_time('mysql')
));
// 更新主文件记录
$wpdb->update("{$wpdb->prefix}collab_files", array(
'file_name' => $new_file['name'],
'file_path' => $new_file['path'],
'file_size' => $new_file['size'],
'version' => $new_version,
'updated_at' => current_time('mysql')
), array('id' => $file_id));
return $new_version;
}
public function get_file_version_history($file_id) {
global $wpdb;
return $wpdb->get_results($wpdb->prepare(
"SELECT v.*, u.display_name as user_name
FROM {$wpdb->prefix}collab_file_versions v
LEFT JOIN {$wpdb->users} u ON v.user_id = u.ID
WHERE v.file_id = %d
ORDER BY v.version DESC",
$file_id
));
}
}
class Code_Collaboration_Tool {
public function init() {
// 注册代码片段自定义文章类型
add_action('init', array($this, 'register_code_snippet_post_type'));
// 添加代码编辑器短代码
add_shortcode('code_editor', array($this, 'code_editor_shortcode'));
// 注册REST API端点
add_action('rest_api_init', array($this, 'register_code_api'));
}
public function register_code_snippet_post_type() {
$args = array(
'public' => true,
'label' => '代码片段',
'supports' => array('title', 'editor', 'author', 'revisions'),
'show_in_rest' => true,
'capability_type' => 'code_snippet',
'capabilities' => array(
'edit_posts' => 'edit_code_snippets',
'edit_others_posts' => 'edit_others_code_snippets',
'publish_posts' => 'publish_code_snippets',
'read_post' => 'read_code_snippet',
'delete_post' => 'delete_code_snippet'
)
);
register_post_type('code_snippet', $args);
}
public function code_editor_shortcode($atts) {
$atts = shortcode_atts(array(
'language' => 'javascript',
'theme' => 'monokai',
'height' => '400px',
'readonly' => false,
'snippet_id' => 0
), $atts);
ob_start();
?>
<div class="code-collaboration-editor"
data-language="<?php echo esc_attr($atts['language']); ?>"
data-theme="<?php echo esc_attr($atts['theme']); ?>"
data-snippet-id="<?php echo esc_attr($atts['snippet_id']); ?>">
<div class="editor-toolbar">
<select class="language-selector">
<option value="javascript">JavaScript</option>
<option value="php">PHP</option>
<option value="python">Python</option>
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="sql">SQL</option>
</select>
<button class="run-code-btn">运行代码</button>
<button class="save-code-btn">保存</button>
<button class="share-code-btn">分享</button>
<div class="collaborators">
<span class="online-users">在线用户: <span class="count">0</span></span>
</div>
</div>
<div class="editor-container" style="height: <?php echo esc_attr($atts['height']); ?>;">
<div class="code-editor" id="code-editor-<?php echo uniqid(); ?>"></div>
</div>
<div class="output-container">
<div class="output-header">输出结果</div>
<div class="output-content"></div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
initializeCodeEditor('code-editor-<?php echo uniqid(); ?>', {
language: '<?php echo $atts["language"]; ?>',
theme: '<?php echo $atts["theme"]; ?>',
readonly: <?php echo $atts["readonly"] ? 'true' : 'false'; ?>,
snippetId: <?php echo $atts["snippet_id"]; ?>
});
});
</script>
<?php
return ob_get_clean();
}
public function register_code_api() {
register_rest_route('collab/v1', '/code/execute', array(
'methods' => 'POST',
'callback' => array($this, 'execute_code'),
'permission_callback' => function() {
return current_user_can('edit_code_snippets');
}
));
register_rest_route('collab/v1', '/code/save', array(
'methods' => 'POST',
'callback' => array($this, 'save_code_snippet'),
'permission_callback' => function() {
return current_user_can('edit_code_snippets');
}
));
}
public function execute_code($request) {
$code = $request->get_param('code');
$language = $request->get_param('language');
// 安全执行代码(使用沙箱环境)
$result = $this->safe_execute_code($code, $language);
return rest_ensure_response(array(
'success' => true,
'output' => $result['output'],
'error' => $result['error'],
'execution_time' => $result['execution_time']
));
}
}
class Code_Collaboration_Tool {
public function init() {
// 注册代码片段自定义文章类型
add_action('init', array($this, 'register_code_snippet_post_type'));
// 添加代码编辑器短代码
add_shortcode('code_editor', array($this, 'code_editor_shortcode'));
// 注册REST API端点
add_action('rest_api_init', array($this, 'register_code_api'));
}
public function register_code_snippet_post_type() {
$args = array(
'public' => true,
'label' => '代码片段',
'supports' => array('title', 'editor', 'author', 'revisions'),
'show_in_rest' => true,
'capability_type' => 'code_snippet',
'capabilities' => array(
'edit_posts' => 'edit_code_snippets',
'edit_others_posts' => 'edit_others_code_snippets',
'publish_posts' => 'publish_code_snippets',
'read_post' => 'read_code_snippet',
'delete_post' => 'delete_code_snippet'
)
);
register_post_type('code_snippet', $args);
}
public function code_editor_shortcode($atts) {
$atts = shortcode_atts(array(
'language' => 'javascript',
'theme' => 'monokai',
'height' => '400px',
'readonly' => false,
'snippet_id' => 0
), $atts);
ob_start();
?>
<div class="code-collaboration-editor"
data-language="<?php echo esc_attr($atts['language']); ?>"
data-theme="<?php echo esc_attr($atts['theme']); ?>"
data-snippet-id="<?php echo esc_attr($atts['snippet_id']); ?>">
<div class="editor-toolbar">
<select class="language-selector">
<option value="javascript">JavaScript</option>
<option value="php">PHP</option>
<option value="python">Python</option>
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="sql">SQL</option>
</select>
<button class="run-code-btn">运行代码</button>
<button class="save-code-btn">保存</button>
<button class="share-code-btn">分享</button>
<div class="collaborators">
<span class="online-users">在线用户: <span class="count">0</span></span>
</div>
</div>
<div class="editor-container" style="height: <?php echo esc_attr($atts['height']); ?>;">
<div class="code-editor" id="code-editor-<?php echo uniqid(); ?>"></div>
</div>
<div class="output-container">
<div class="output-header">输出结果</div>
<div class="output-content"></div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
initializeCodeEditor('code-editor-<?php echo uniqid(); ?>', {
language: '<?php echo $atts["language"]; ?>',
theme: '<?php echo $atts["theme"]; ?>',
readonly: <?php echo $atts["readonly"] ? 'true' : 'false'; ?>,
snippetId: <?php echo $atts["snippet_id"]; ?>
});
});
</script>
<?php
return ob_get_clean();
}
public function register_code_api() {
register_rest_route('collab/v1', '/code/execute', array(
'methods' => 'POST',
'callback' => array($this, 'execute_code'),
'permission_callback' => function() {
return current_user_can('edit_code_snippets');
}
));
register_rest_route('collab/v1', '/code/save', array(
'methods' => 'POST',
'callback' => array($this, 'save_code_snippet'),
'permission_callback' => function() {
return current_user_can('edit_code_snippets');
}
));
}
public function execute_code($request) {
$code = $request->get_param('code');
$language = $request->get_param('language');
// 安全执行代码(使用沙箱环境)
$result = $this->safe_execute_code($code, $language);
return rest_ensure_response(array(
'success' => true,
'output' => $result['output'],
'error' => $result['error'],
'execution_time' => $result['execution_time']
));
}
}
class API_Testing_Tool {
private $endpoints = array();
public function init() {
add_action('admin_menu', array($this, 'add_api_testing_page'));
add_action('wp_ajax_save_api_endpoint', array($this, 'save_api_endpoint'));
add_action('wp_ajax_test_api_endpoint', array($this, 'test_api_endpoint'));
add_action('wp_ajax_save_webhook', array($this, 'save_webhook'));
}
public function add_api_testing_page() {
add_menu_page(
'API测试工具',
'API测试',
'manage_options',
'api-testing-tool',
array($this, 'render_api_testing_page'),
'dashicons-rest-api',
30
);
}
public function render_api_testing_page() {
?>
<div class="wrap api-testing-tool">
<h1>API测试与Webhook管理</h1>
<div class="api-tool-container">
<!-- API测试界面 -->
<div class="api-tester-section">
<h2>API请求测试</h2>
<div class="request-builder">
<div class="request-method">
<select id="request-method">
<option value="GET">GET</option>
<option value="POST">POST</option>
<option value="PUT">PUT</option>
<option value="DELETE">DELETE</option>
<option value="PATCH">PATCH</option>
</select>
<input type="text" id="request-url" placeholder="https://api.example.com/endpoint" style="width: 60%;">
<button id="send-request" class="button button-primary">发送请求</button>
</div>
<div class="request-tabs">
<ul>
<li><a href="#params-tab">参数</a></li>
<li><a href="#headers-tab">请求头</a></li>
<li><a href="#body-tab">请求体</a></li>
<li><a href="#auth-tab">认证</a></li>
</ul>
<div id="params-tab">
<table class="params-table">
<thead>
<tr>
<th>参数名</th>
<th>值</th>
<th>操作</th>
</tr>
</thead>
<tbody id="params-body">
<tr>
<td><input type="text" class="param-key" placeholder="参数名"></td>
<td><input type="text" class="param-value" placeholder="值"></td>
<td><button class="remove-param button">删除</button></td>
</tr>
</tbody>
</table>
<button id="add-param" class="button">添加参数</button>
</div>
<div id="headers-tab">
<!-- 请求头配置界面 -->
</div>
<div id="body-tab">
<select id="body-type">
<option value="none">无</option>
<option value="form-data">表单数据</option>
<option value="x-www-form-urlencoded">x-www-form-urlencoded</option>
<option value="raw">原始数据</option>
<option value="json">JSON</option>
</select>
<textarea id="request-body" rows="10" style="width: 100%;"></textarea>
</div>
<div id="auth-tab">
<!-- 认证配置界面 -->
</div>
</div>
</div>
<div class="response-section">
<h3>响应结果</h3>
<div class="response-info">
<div class="response-status">
状态码: <span id="response-status">-</span>
响应时间: <span id="response-time">-</span>ms
大小: <span id="response-size">-</span>
</div>
<div class="response-tabs">
<ul>
<li><a href="#response-body-tab">响应体</a></li>
<li><a href="#response-headers-tab">响应头</a></li>
<li><a href="#response-cookies-tab">Cookies</a></li>
</ul>
<div id="response-body-tab">
<pre id="response-body"></pre>
</div>
<div id="response-headers-tab">
<pre id="response-headers"></pre>
</div>
</div>
</div>
</div>
</div>
<!-- Webhook管理界面 -->
<div class="webhook-manager-section">
<h2>Webhook管理</h2>
<button id="add-webhook" class="button button-primary">添加Webhook</button>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th>名称</th>
<th>URL</th>
<th>事件</th>
<th>状态</th>
<th>最后触发</th>
<th>操作</th>
</tr>
</thead>
<tbody id="webhooks-list">
<?php $this->render_webhooks_list(); ?>
</tbody>
</table>
<div class="webhook-details" style="display: none;">
<h3>Webhook详情</h3>
<form id="webhook-form">
<input type="hidden" id="webhook-id">
<table class="form-table">
<tr>
<th><label for="webhook-name">名称</label></th>
<td><input type="text" id="webhook-name" class="regular-text" required></td>
</tr>
<tr>
<th><label for="webhook-url">URL</label></th>
<td><input type="url" id="webhook-url" class="regular-text" required></td>
</tr>
<tr>
<th><label for="webhook-events">触发事件</label></th>
<td>
<select id="webhook-events" multiple style="width: 100%; height: 100px;">
<option value="task_created">任务创建</option>
<option value="task_updated">任务更新</option>
<option value="task_completed">任务完成</option>
<option value="file_uploaded">文件上传</option>
<option value="comment_added">评论添加</option>
<option value="user_joined">用户加入</option>
</select>
</td>
</tr>
<tr>
<th><label for="webhook-secret">签名密钥</label></th>
<td>
<input type="text" id="webhook-secret" class="regular-text">
<button type="button" id="generate-secret" class="button">生成密钥</button>
</td>
</tr>
<tr>
<th><label for="webhook-active">状态</label></th>
<td>
<label>
<input type="checkbox" id="webhook-active" checked> 启用
</label>
</td>
</tr>
</table>
<div class="submit">
<button type="submit" class="button button-primary">保存</button>
<button type="button" id="cancel-webhook" class="button">取消</button>
<button type="button" id="test-webhook" class="button">测试Webhook</button>
</div>
</form>
</div>
</div>
</div>
</div>
<script>
jQuery(document).ready(function($) {
// API测试功能
$('#send-request').on('click', function() {
const method = $('#request-method').val();
const url = $('#request-url').val();
const params = {};
$('#params-body tr').each(function() {
const key = $(this).find('.param-key').val();
class API_Testing_Tool {
private $endpoints = array();
public function init() {
add_action('admin_menu', array($this, 'add_api_testing_page'));
add_action('wp_ajax_save_api_endpoint', array($this, 'save_api_endpoint'));
add_action('wp_ajax_test_api_endpoint', array($this, 'test_api_endpoint'));
add_action('wp_ajax_save_webhook', array($this, 'save_webhook'));
}
public function add_api_testing_page() {
add_menu_page(
'API测试工具',
'API测试',
'manage_options',
'api-testing-tool',
array($this, 'render_api_testing_page'),
'dashicons-rest-api',
30
);
}
public function render_api_testing_page() {
?>
<div class="wrap api-testing-tool">
<h1>API测试与Webhook管理</h1>
<div class="api-tool-container">
<!-- API测试界面 -->
<div class="api-tester-section">
<h2>API请求测试</h2>
<div class="request-builder">
<div class="request-method">
<select id="request-method">
<option value="GET">GET</option>
<option value="POST">POST</option>
<option value="PUT">PUT</option>
<option value="DELETE">DELETE</option>
<option value="PATCH">PATCH</option>
</select>
<input type="text" id="request-url" placeholder="https://api.example.com/endpoint" style="width: 60%;">
<button id="send-request" class="button button-primary">发送请求</button>
</div>
<div class="request-tabs">
<ul>
<li><a href="#params-tab">参数</a></li>
<li><a href="#headers-tab">请求头</a></li>
<li><a href="#body-tab">请求体</a></li>
<li><a href="#auth-tab">认证</a></li>
</ul>
<div id="params-tab">
<table class="params-table">
<thead>
<tr>
<th>参数名</th>
<th>值</th>
<th>操作</th>
</tr>
</thead>
<tbody id="params-body">
<tr>
<td><input type="text" class="param-key" placeholder="参数名"></td>
<td><input type="text" class="param-value" placeholder="值"></td>
<td><button class="remove-param button">删除</button></td>
</tr>
</tbody>
</table>
<button id="add-param" class="button">添加参数</button>
</div>
<div id="headers-tab">
<!-- 请求头配置界面 -->
</div>
<div id="body-tab">
<select id="body-type">
<option value="none">无</option>
<option value="form-data">表单数据</option>
<option value="x-www-form-urlencoded">x-www-form-urlencoded</option>
<option value="raw">原始数据</option>
<option value="json">JSON</option>
</select>
<textarea id="request-body" rows="10" style="width: 100%;"></textarea>
</div>
<div id="auth-tab">
<!-- 认证配置界面 -->
</div>
</div>
</div>
<div class="response-section">
<h3>响应结果</h3>
<div class="response-info">
<div class="response-status">
状态码: <span id="response-status">-</span>
响应时间: <span id="response-time">-</span>ms
大小: <span id="response-size">-</span>
</div>
<div class="response-tabs">
<ul>
<li><a href="#response-body-tab">响应体</a></li>
<li><a href="#response-headers-tab">响应头</a></li>
<li><a href="#response-cookies-tab">Cookies</a></li>
</ul>
<div id="response-body-tab">
<pre id="response-body"></pre>
</div>
<div id="response-headers-tab">
<pre id="response-headers"></pre>
</div>
</div>
</div>
</div>
</div>
<!-- Webhook管理界面 -->
<div class="webhook-manager-section">
<h2>Webhook管理</h2>
<button id="add-webhook" class="button button-primary">添加Webhook</button>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th>名称</th>
<th>URL</th>
<th>事件</th>
<th>状态</th>
<th>最后触发</th>
<th>操作</th>
</tr>
</thead>
<tbody id="webhooks-list">
<?php $this->render_webhooks_list(); ?>
</tbody>
</table>
<div class="webhook-details" style="display: none;">
<h3>Webhook详情</h3>
<form id="webhook-form">
<input type="hidden" id="webhook-id">
<table class="form-table">
<tr>
<th><label for="webhook-name">名称</label></th>
<td><input type="text" id="webhook-name" class="regular-text" required></td>
</tr>
<tr>
<th><label for="webhook-url">URL</label></th>
<td><input type="url" id="webhook-url" class="regular-text" required></td>
</tr>
<tr>
<th><label for="webhook-events">触发事件</label></th>
<td>
<select id="webhook-events" multiple style="width: 100%; height: 100px;">
<option value="task_created">任务创建</option>
<option value="task_updated">任务更新</option>
<option value="task_completed">任务完成</option>
<option value="file_uploaded">文件上传</option>
<option value="comment_added">评论添加</option>
<option value="user_joined">用户加入</option>
</select>
</td>
</tr>
<tr>
<th><label for="webhook-secret">签名密钥</label></th>
<td>
<input type="text" id="webhook-secret" class="regular-text">
<button type="button" id="generate-secret" class="button">生成密钥</button>
</td>
</tr>
<tr>
<th><label for="webhook-active">状态</label></th>
<td>
<label>
<input type="checkbox" id="webhook-active" checked> 启用
</label>
</td>
</tr>
</table>
<div class="submit">
<button type="submit" class="button button-primary">保存</button>
<button type="button" id="cancel-webhook" class="button">取消</button>
<button type="button" id="test-webhook" class="button">测试Webhook</button>
</div>
</form>
</div>
</div>
</div>
</div>
<script>
jQuery(document).ready(function($) {
// API测试功能
$('#send-request').on('click', function() {
const method = $('#request-method').val();
const url = $('#request-url').val();
const params = {};
$('#params-body tr').each(function() {
const key = $(this).find('.param-key').val();


