文章目录[隐藏]
WordPress小批量定制插件:3D模型上传功能开发教程
一、项目概述与准备工作
在当今数字化时代,3D内容展示已成为网站增强用户体验的重要手段。本教程将指导您开发一个WordPress定制插件,使网站能够支持3D模型上传和展示功能。这个插件特别适合需要小批量处理3D模型的企业网站、产品展示平台或教育类网站。
开发环境要求
- WordPress 5.0+
- PHP 7.2+
- 支持WebGL的现代浏览器
- 基础的WordPress开发知识
插件功能规划
- 3D模型文件上传(支持.glb、.gltf格式)
- 前端3D模型查看器
- 模型管理后台界面
- 短代码支持,方便内容嵌入
二、创建插件基础结构
首先,在WordPress的wp-content/plugins/目录下创建插件文件夹3d-model-uploader,并创建以下基础文件:
<?php
/**
* Plugin Name: 3D模型上传器
* Plugin URI: https://yourwebsite.com/
* Description: 为WordPress添加3D模型上传和展示功能
* Version: 1.0.0
* Author: 您的名称
* License: GPL v2 or later
* Text Domain: 3d-model-uploader
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('DMU_VERSION', '1.0.0');
define('DMU_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('DMU_PLUGIN_URL', plugin_dir_url(__FILE__));
define('DMU_UPLOAD_DIR', '3d-models');
// 初始化插件
class ThreeDModelUploader {
private static $instance = null;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$this->init_hooks();
}
private function init_hooks() {
// 激活/停用钩子
register_activation_hook(__FILE__, array($this, 'activate'));
register_deactivation_hook(__FILE__, array($this, 'deactivate'));
// 初始化
add_action('init', array($this, 'init'));
// 管理菜单
add_action('admin_menu', array($this, 'add_admin_menu'));
// 前端资源
add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_assets'));
// 管理端资源
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));
}
public function activate() {
// 创建必要的数据库表
$this->create_database_table();
// 创建上传目录
$upload_dir = wp_upload_dir();
$model_dir = $upload_dir['basedir'] . '/' . DMU_UPLOAD_DIR;
if (!file_exists($model_dir)) {
wp_mkdir_p($model_dir);
}
}
public function deactivate() {
// 清理临时数据
// 注意:这里不删除上传的模型文件,以防误删
}
public function init() {
// 注册短代码
add_shortcode('show_3d_model', array($this, 'render_3d_model_shortcode'));
}
// 其他方法将在后续章节实现
}
// 启动插件
ThreeDModelUploader::get_instance();
?>
三、创建数据库表结构
在插件激活时,我们需要创建一个数据库表来存储3D模型的信息:
// 在ThreeDModelUploader类中添加以下方法
private function create_database_table() {
global $wpdb;
$table_name = $wpdb->prefix . '3d_models';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
title varchar(255) NOT NULL,
description text,
file_path varchar(500) NOT NULL,
file_size int(11) DEFAULT 0,
upload_date datetime DEFAULT CURRENT_TIMESTAMP,
user_id bigint(20) NOT NULL,
views int(11) DEFAULT 0,
status varchar(20) DEFAULT 'publish',
PRIMARY KEY (id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
四、实现3D模型上传功能
4.1 添加上传表单页面
// 在ThreeDModelUploader类中添加以下方法
public function add_admin_menu() {
add_menu_page(
'3D模型管理',
'3D模型',
'manage_options',
'3d-model-manager',
array($this, 'render_admin_page'),
'dashicons-format-gallery',
30
);
add_submenu_page(
'3d-model-manager',
'上传新模型',
'上传模型',
'manage_options',
'3d-model-upload',
array($this, 'render_upload_page')
);
}
public function render_upload_page() {
?>
<div class="wrap">
<h1>上传3D模型</h1>
<?php
// 处理表单提交
if (isset($_POST['submit_3d_model']) && wp_verify_nonce($_POST['_wpnonce'], 'upload_3d_model')) {
$this->handle_model_upload();
}
?>
<div class="card">
<h2>上传新模型</h2>
<form method="post" enctype="multipart/form-data">
<?php wp_nonce_field('upload_3d_model'); ?>
<table class="form-table">
<tr>
<th><label for="model_title">模型标题</label></th>
<td>
<input type="text" id="model_title" name="model_title"
class="regular-text" required>
</td>
</tr>
<tr>
<th><label for="model_description">描述</label></th>
<td>
<textarea id="model_description" name="model_description"
rows="4" class="large-text"></textarea>
</td>
</tr>
<tr>
<th><label for="model_file">选择模型文件</label></th>
<td>
<input type="file" id="model_file" name="model_file"
accept=".glb,.gltf" required>
<p class="description">支持格式: .glb, .gltf (最大文件大小: 50MB)</p>
</td>
</tr>
</table>
<p class="submit">
<input type="submit" name="submit_3d_model"
class="button button-primary" value="上传模型">
</p>
</form>
</div>
</div>
<?php
}
private function handle_model_upload() {
// 检查文件上传错误
if ($_FILES['model_file']['error'] !== UPLOAD_ERR_OK) {
echo '<div class="error"><p>文件上传失败,请重试。</p></div>';
return;
}
// 验证文件类型
$allowed_types = array('glb', 'gltf');
$file_ext = strtolower(pathinfo($_FILES['model_file']['name'], PATHINFO_EXTENSION));
if (!in_array($file_ext, $allowed_types)) {
echo '<div class="error"><p>不支持的文件格式。请上传.glb或.gltf文件。</p></div>';
return;
}
// 检查文件大小(限制为50MB)
$max_size = 50 * 1024 * 1024; // 50MB
if ($_FILES['model_file']['size'] > $max_size) {
echo '<div class="error"><p>文件太大。最大允许50MB。</p></div>';
return;
}
// 准备上传目录
$upload_dir = wp_upload_dir();
$model_dir = $upload_dir['basedir'] . '/' . DMU_UPLOAD_DIR;
$model_url = $upload_dir['baseurl'] . '/' . DMU_UPLOAD_DIR;
// 生成唯一文件名
$filename = sanitize_file_name($_FILES['model_file']['name']);
$filename = wp_unique_filename($model_dir, $filename);
$destination = $model_dir . '/' . $filename;
// 移动上传的文件
if (move_uploaded_file($_FILES['model_file']['tmp_name'], $destination)) {
// 保存到数据库
global $wpdb;
$table_name = $wpdb->prefix . '3d_models';
$data = array(
'title' => sanitize_text_field($_POST['model_title']),
'description' => sanitize_textarea_field($_POST['model_description']),
'file_path' => $model_url . '/' . $filename,
'file_size' => $_FILES['model_file']['size'],
'user_id' => get_current_user_id(),
'status' => 'publish'
);
$wpdb->insert($table_name, $data);
echo '<div class="updated"><p>模型上传成功!</p></div>';
} else {
echo '<div class="error"><p>文件保存失败。</p></div>';
}
}
五、集成3D模型查看器
5.1 引入Three.js库
// 在ThreeDModelUploader类中添加资源加载方法
public function enqueue_frontend_assets() {
// 引入Three.js库
wp_enqueue_script(
'three-js',
'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js',
array(),
'r128',
true
);
// 引入GLTF加载器
wp_enqueue_script(
'three-gltf-loader',
'https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/loaders/GLTFLoader.js',
array('three-js'),
'0.128.0',
true
);
// 引入OrbitControls
wp_enqueue_script(
'three-orbit-controls',
'https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js',
array('three-js'),
'0.128.0',
true
);
// 引入插件自定义脚本
wp_enqueue_script(
'dmu-viewer',
DMU_PLUGIN_URL . 'assets/js/model-viewer.js',
array('three-js', 'three-gltf-loader', 'three-orbit-controls'),
DMU_VERSION,
true
);
// 引入样式
wp_enqueue_style(
'dmu-styles',
DMU_PLUGIN_URL . 'assets/css/style.css',
array(),
DMU_VERSION
);
}
5.2 创建3D模型查看器JavaScript
// 创建文件:assets/js/model-viewer.js
(function($) {
'use strict';
// 3D模型查看器类
class ModelViewer {
constructor(containerId, modelUrl) {
this.containerId = containerId;
this.modelUrl = modelUrl;
this.scene = null;
this.camera = null;
this.renderer = null;
this.controls = null;
this.model = null;
this.init();
}
init() {
// 创建场景
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(0xf0f0f0);
// 创建相机
this.camera = new THREE.PerspectiveCamera(
45, // 视野角度
this.getContainerAspectRatio(), // 宽高比
0.1, // 近平面
1000 // 远平面
);
this.camera.position.set(5, 5, 5);
// 创建渲染器
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.renderer.setSize(
this.getContainerWidth(),
this.getContainerHeight()
);
this.renderer.shadowMap.enabled = true;
// 添加到容器
const container = document.getElementById(this.containerId);
container.appendChild(this.renderer.domElement);
// 添加光源
this.addLights();
// 添加轨道控制
this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
this.controls.enableDamping = true;
this.controls.dampingFactor = 0.05;
// 加载模型
this.loadModel();
// 开始动画循环
this.animate();
// 处理窗口大小变化
window.addEventListener('resize', () => this.onWindowResize());
}
getContainerWidth() {
const container = document.getElementById(this.containerId);
return container.clientWidth;
}
getContainerHeight() {
const container = document.getElementById(this.containerId);
return container.clientHeight;
}
getContainerAspectRatio() {
return this.getContainerWidth() / this.getContainerHeight();
}
addLights() {
// 环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
this.scene.add(ambientLight);
// 方向光
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(10, 20, 15);
directionalLight.castShadow = true;
this.scene.add(directionalLight);
// 辅助光
const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x444444, 0.3);
this.scene.add(hemisphereLight);
}
loadModel() {
const loader = new THREE.GLTFLoader();
loader.load(
this.modelUrl,
(gltf) => {
this.model = gltf.scene;
// 调整模型位置和缩放
const box = new THREE.Box3().setFromObject(this.model);
const center = box.getCenter(new THREE.Vector3());
const size = box.getSize(new THREE.Vector3());
// 居中模型
this.model.position.x += (this.model.position.x - center.x);
this.model.position.y += (this.model.position.y - center.y);
this.model.position.z += (this.model.position.z - center.z);
// 缩放以适应视图
const maxDim = Math.max(size.x, size.y, size.z);
const scale = 5 / maxDim;
this.model.scale.multiplyScalar(scale);
this.scene.add(this.model);
// 更新相机位置
this.camera.position.set(10, 10, 10);
this.controls.update();
},
(xhr) => {
// 加载进度
const progress = (xhr.loaded / xhr.total * 100);
console.log(`模型加载进度: ${progress.toFixed(2)}%`);
},
(error) => {
console.error('模型加载失败:', error);
this.showError('模型加载失败,请检查控制台获取详细信息。');
}
);
}
animate() {
requestAnimationFrame(() => this.animate());
if (this.controls) {
this.controls.update();
}
if (this.renderer && this.scene && this.camera) {
this.renderer.render(this.scene, this.camera);
}
}
onWindowResize() {
this.camera.aspect = this.getContainerAspectRatio();
this.camera.updateProjectionMatrix();
this.renderer.setSize(this.getContainerWidth(), this.getContainerHeight());
}
showError(message) {
const container = document.getElementById(this.containerId);
container.innerHTML = `<div class="model-error">${message}</div>`;
}
}
// 初始化所有3D模型查看器
$(document).ready(function() {
$('.dmu-model-container').each(function() {
const containerId = $(this).attr('id');
const modelUrl = $(this).data('model-url');
if (containerId && modelUrl) {
new ModelViewer(containerId, modelUrl);
}
});
});
})(jQuery);
六、创建短代码和前端展示
6.1 实现短代码功能
// 在ThreeDModelUploader类中添加短代码方法
public function render_3d_model_shortcode($atts) {
// 解析短代码属性
$atts = shortcode_atts(array(
'id' => 0,
'width' => '100%',
'height' => '500px',
'title' => ''
), $atts, 'show_3d_model');
$model_id = intval($atts['id']);
if ($model_id <= 0) {
return '<p>错误:未指定有效的模型ID。</p>';
}
// 从数据库获取模型信息
global $wpdb;
$table_name = $wpdb->prefix . '3d_models';
$model = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $table_name WHERE id = %d AND status = 'publish'",
$model_id
));
if (!$model) {
return '<p>错误:找不到指定的3D模型。</p>';
}
// 更新查看次数
$wpdb->update(
$table_name,
array('views' => $model->views + 1),
model_id)
);
// 生成唯一容器ID
$container_id = 'dmu-model-' . uniqid();
// 构建HTML输出
$output = '<div class="dmu-model-wrapper">';
if (!empty($atts['title'])) {
$output .= '<h3 class="dmu-model-title">' . esc_html($atts['title']) . '</h3>';
} else {
$output .= '<h3 class="dmu-model-title">' . esc_html($model->title) . '</h3>';
}
if (!empty($model->description)) {
$output .= '<p class="dmu-model-description">' . esc_html($model->description) . '</p>';
}
$output .= '<div class="dmu-model-container" id="' . $container_id . '"
data-model-url="' . esc_url($model->file_path) . '"
style="width: ' . esc_attr($atts['width']) . ';
height: ' . esc_attr($atts['height']) . ';
border: 1px solid #ddd;
border-radius: 4px;
overflow: hidden;"></div>';
$output .= '<div class="dmu-model-meta">';
$output .= '<span class="dmu-model-views">查看次数: ' . intval($model->views + 1) . '</span>';
$output .= '<span class="dmu-model-upload-date">上传时间: ' .
date_i18n(get_option('date_format'), strtotime($model->upload_date)) . '</span>';
$output .= '</div>';
$output .= '</div>';
return $output;
}
### 6.2 创建模型管理页面
// 在ThreeDModelUploader类中添加管理页面方法
public function render_admin_page() {
global $wpdb;
$table_name = $wpdb->prefix . '3d_models';
// 处理删除请求
if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['model_id'])) {
$this->delete_model(intval($_GET['model_id']));
}
// 获取所有模型
$models = $wpdb->get_results("SELECT * FROM $table_name ORDER BY upload_date DESC");
?>
<div class="wrap">
<h1>3D模型管理</h1>
<div class="card">
<h2>模型列表</h2>
<?php if (empty($models)): ?>
<p>暂无3D模型,请先<a href="<?php echo admin_url('admin.php?page=3d-model-upload'); ?>">上传模型</a>。</p>
<?php else: ?>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th>ID</th>
<th>标题</th>
<th>文件大小</th>
<th>查看次数</th>
<th>上传时间</th>
<th>短代码</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php foreach ($models as $model): ?>
<tr>
<td><?php echo intval($model->id); ?></td>
<td>
<strong><?php echo esc_html($model->title); ?></strong>
<?php if (!empty($model->description)): ?>
<p class="description"><?php echo esc_html($model->description); ?></p>
<?php endif; ?>
</td>
<td><?php echo size_format($model->file_size, 2); ?></td>
<td><?php echo intval($model->views); ?></td>
<td><?php echo date_i18n(get_option('date_format'), strtotime($model->upload_date)); ?></td>
<td>
<input type="text" readonly value="[show_3d_model id="<?php echo $model->id; ?>"]"
class="regular-text" onclick="this.select();">
</td>
<td>
<a href="<?php echo admin_url('admin.php?page=3d-model-manager&action=delete&model_id=' . $model->id); ?>"
class="button button-small button-danger"
onclick="return confirm('确定要删除这个模型吗?')">删除</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
<div class="card">
<h2>使用说明</h2>
<ol>
<li>使用短代码 <code>[show_3d_model id="模型ID"]</code> 在文章或页面中嵌入3D模型</li>
<li>可选参数:<code>width</code> (宽度), <code>height</code> (高度), <code>title</code> (自定义标题)</li>
<li>示例:<code>[show_3d_model id="1" width="800px" height="600px" title="我的3D模型"]</code></li>
</ol>
</div>
</div>
<?php
}
private function delete_model($model_id) {
global $wpdb;
$table_name = $wpdb->prefix . '3d_models';
// 获取文件路径
$model = $wpdb->get_row($wpdb->prepare(
"SELECT file_path FROM $table_name WHERE id = %d",
$model_id
));
if ($model) {
// 从URL转换为本地路径
$upload_dir = wp_upload_dir();
$base_url = $upload_dir['baseurl'];
$base_dir = $upload_dir['basedir'];
$file_path = str_replace($base_url, $base_dir, $model->file_path);
// 删除文件
if (file_exists($file_path)) {
unlink($file_path);
}
// 删除数据库记录
$wpdb->delete($table_name, array('id' => $model_id));
echo '<div class="updated"><p>模型已删除。</p></div>';
}
}
## 七、添加CSS样式
/ 创建文件:assets/css/style.css /
/ 3D模型容器样式 /
.dmu-model-wrapper {
margin: 20px 0;
padding: 15px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.dmu-model-title {
margin-top: 0;
margin-bottom: 10px;
color: #333;
font-size: 1.5em;
}
.dmu-model-description {
color: #666;
margin-bottom: 15px;
line-height: 1.6;
}
.dmu-model-container {
position: relative;
background: #f8f9fa;
}
.dmu-model-meta {
margin-top: 10px;
padding-top: 10px;
border-top: 1px solid #eee;
font-size: 0.9em;
color: #777;
}
.dmu-model-views,
.dmu-model-upload-date {
margin-right: 15px;
}
.dmu-model-views:before {
content: "👁️ ";
}
.dmu-model-upload-date:before {
content: "📅 ";
}
/ 加载状态 /
.dmu-model-loading {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
color: #666;
}
.dmu-model-loading:after {
content: "加载3D模型中...";
animation: dmu-pulse 1.5s infinite;
}
@keyframes dmu-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
/ 错误状态 /
.model-error {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
color: #d63638;
background: #fcf0f1;
padding: 20px;
text-align: center;
}
/ 响应式设计 /
@media (max-width: 768px) {
.dmu-model-container {
height: 300px !important;
}
.dmu-model-title {
font-size: 1.2em;
}
}
/ 管理界面样式 /
.button-danger {
background: #d63638;
border-color: #d63638;
color: white;
}
.button-danger:hover {
background: #b32d2e;
border-color: #b32d2e;
}
.wp-list-table .description {
color: #666;
font-size: 0.9em;
margin-top: 5px;
}
## 八、插件优化和扩展建议
### 8.1 添加模型预览图功能
// 在ThreeDModelUploader类中添加缩略图生成方法
private function generate_model_thumbnail($model_path, $model_id) {
// 这里可以集成截图功能
// 注意:这需要服务器支持WebGL或使用外部服务
// 暂时返回占位符
return DMU_PLUGIN_URL . 'assets/images/placeholder.jpg';
}
// 修改handle_model_upload方法,添加缩略图生成
private function handle_model_upload() {
// ... 现有的上传代码 ...
// 生成缩略图
$thumbnail_url = $this->generate_model_thumbnail($destination, $wpdb->insert_id);
// 更新数据库,添加缩略图字段
$wpdb->update(
$table_name,
array('thumbnail' => $thumbnail_url),
array('id' => $wpdb->insert_id)
);
}
### 8.2 添加批量上传功能
// 添加上传页面的批量上传选项
public function render_upload_page() {
?>
<!-- 在现有表单后添加批量上传选项 -->
<div class="card" style="margin-top: 20px;">
<h2>批量上传(高级功能)</h2>
<form method="post" enctype="multipart/form-data" id="batch-upload-form">
<?php wp_nonce_field('batch_upload_models'); ?>
<input type="file" name="batch_files[]" multiple accept=".glb,.gltf" id="batch-files">
<p class="description">按住Ctrl键可选择多个文件(最多10个)</p>
<p class="submit">
<input type="submit" name="submit_batch_models"
class="button button-secondary" value="批量上传"
id="batch-submit" disabled>
</p>
</form>
</div>
<script>
jQuery(document).ready(function($) {
$('#batch-files').on('change', function() {
var files = this.files;
$('#batch-submit').prop('disabled', files.length === 0 || files.length > 10);
});
});
</script>
<?php
}
### 8.3 添加模型分类功能
// 创建模型分类表
private function create_category_table() {
global $wpdb;
$table_name = $wpdb->prefix . '3d_model_categories';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
slug varchar(255) NOT NULL,
description text,
parent_id mediumint(9) DEFAULT 0,
count mediumint(9) DEFAULT 0,
PRIMARY KEY (id),
UNIQUE KEY slug (slug)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
## 九、插件部署和使用
### 9.1 完整插件结构
3d-model-uploader/
├── 3d-model-uploader.php # 主插件文件
├── assets/
│ ├── css/
│ │ └── style.css # 样式文件
│ ├── js/
│ │ └── model-viewer.js # 3D查看器脚本
│ └── images/
│ └── placeholder.jpg # 占位图片
├── includes/
│ └── class-database.php # 数据库操作类(可选)
└── README.md # 使用说明
### 9.2 使用步骤
1. 将插件文件夹上传到 `/wp-content/plugins/`
2. 在WordPress后台激活插件
3. 进入"3D模型"菜单,上传您的3D模型文件
4. 在文章或页面中使用短代码 `[show_3d_model id="1"]` 嵌入模型
5. 可通过参数自定义显示尺寸和标题
### 9.3 注意事项
- 确保服务器有足够的上传文件大小限制(建议50MB以上)
- 使用现代浏览器以获得最佳3D渲染效果
- 大型模型可能需要较长的加载时间,建议优化模型文件大小
- 定期备份上传的模型文件
## 十、总结
通过本教程,您已经成功创建了一个功能完整的WordPress 3D模型上传插件。这个插件提供了:
1. **完整的后端管理界面**:模型上传、管理和删除
2. **强大的前端展示**:基于Three.js的3D模型查看器
3. **灵活的短代码系统**:方便在内容中嵌入3D模型
4. **响应式设计**:适配各种设备屏幕
您可以根据实际需求进一步扩展插件功能,例如:
- 添加用户权限控制
- 实现模型搜索和筛选
- 集成更多3D文件格式支持
- 添加模型动画控制
- 实现AR/VR查看功能
