文章目录
-
- 增强现实(AR)技术正在改变用户与数字内容的交互方式。在WordPress电商或展示类网站中,集成AR预览功能可以让用户通过手机摄像头查看产品在真实环境中的效果,显著提升用户体验和转化率。本教程将指导您开发一个支持AR预览的WordPress定制插件。
- 首先创建插件的主文件,这是插件的入口点: <?php /** * Plugin Name: WordPress AR预览插件 * Plugin URI: https://yourwebsite.com/ * Description: 为WordPress产品添加AR预览功能 * Version: 1.0.0 * Author: 您的名称 * License: GPL v2 or later * Text Domain: wp-ar-preview */ // 防止直接访问 if (!defined('ABSPATH')) { exit; } // 定义插件常量 define('WP_AR_PREVIEW_VERSION', '1.0.0'); define('WP_AR_PREVIEW_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('WP_AR_PREVIEW_PLUGIN_URL', plugin_dir_url(__FILE__)); define('WP_AR_PREVIEW_MODEL_DIR', WP_AR_PREVIEW_PLUGIN_DIR . 'assets/models/'); // 自动加载类文件 spl_autoload_register(function ($class_name) { $prefix = 'WP_AR_Preview_'; $base_dir = WP_AR_PREVIEW_PLUGIN_DIR . 'includes/'; $len = strlen($prefix); if (strncmp($prefix, $class_name, $len) !== 0) { return; } $relative_class = substr($class_name, $len); $file = $base_dir . 'class-' . str_replace('_', '-', strtolower($relative_class)) . '.php'; if (file_exists($file)) { require_once $file; } }); // 初始化插件 function wp_ar_preview_init() { // 检查WordPress版本 if (version_compare(get_bloginfo('version'), '5.0', '<')) { add_action('admin_notices', function() { echo '<div class="notice notice-error"><p>'; echo __('AR预览插件需要WordPress 5.0或更高版本', 'wp-ar-preview'); echo '</p></div>'; }); return; } // 初始化各个组件 WP_AR_Preview_Admin::get_instance(); WP_AR_Preview_Shortcode::get_instance(); WP_AR_Preview_Model::get_instance(); } add_action('plugins_loaded', 'wp_ar_preview_init'); // 激活插件时的操作 register_activation_hook(__FILE__, function() { // 创建必要的目录 if (!file_exists(WP_AR_PREVIEW_MODEL_DIR)) { wp_mkdir_p(WP_AR_PREVIEW_MODEL_DIR); } // 添加默认选项 add_option('wp_ar_preview_settings', array( 'enable_ar' => '1', 'default_model_scale' => '1', 'ar_button_text' => '在您的空间中查看', 'supported_formats' => array('glb', 'gltf') )); }); // 停用插件时的清理操作 register_deactivation_hook(__FILE__, function() { // 清理临时数据 delete_transient('wp_ar_preview_cache'); });
- 创建AR模型处理类,负责处理3D模型的上传、验证和存储: <?php /** * AR模型处理类 * 负责处理3D模型文件的上传、验证和管理 */ class WP_AR_Preview_Model { private static $instance = null; private $allowed_types = array('glb', 'gltf'); public static function get_instance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } private function __construct() { add_action('wp_ajax_upload_ar_model', array($this, 'handle_model_upload')); add_action('wp_ajax_nopriv_upload_ar_model', array($this, 'handle_model_upload')); } /** * 处理模型上传 */ public function handle_model_upload() { // 验证nonce if (!wp_verify_nonce($_POST['nonce'], 'wp_ar_preview_upload')) { wp_die('安全验证失败'); } // 检查文件上传 if (!isset($_FILES['model_file'])) { wp_send_json_error('没有上传文件'); } $file = $_FILES['model_file']; // 验证文件类型 $file_ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); if (!in_array($file_ext, $this->allowed_types)) { wp_send_json_error('不支持的文件格式。请上传GLB或GLTF文件。'); } // 验证文件大小(限制为50MB) $max_size = 50 * 1024 * 1024; if ($file['size'] > $max_size) { wp_send_json_error('文件太大。最大允许50MB。'); } // 生成唯一文件名 $filename = uniqid('model_') . '.' . $file_ext; $destination = WP_AR_PREVIEW_MODEL_DIR . $filename; // 移动上传的文件 if (move_uploaded_file($file['tmp_name'], $destination)) { // 保存到数据库 $model_id = $this->save_model_to_db(array( 'filename' => $filename, 'original_name' => $file['name'], 'file_size' => $file['size'], 'upload_date' => current_time('mysql') )); wp_send_json_success(array( 'model_id' => $model_id, 'filename' => $filename, 'url' => WP_AR_PREVIEW_PLUGIN_URL . 'assets/models/' . $filename )); } else { wp_send_json_error('文件上传失败'); } } /** * 保存模型信息到数据库 */ private function save_model_to_db($data) { global $wpdb; $table_name = $wpdb->prefix . 'ar_models'; // 创建表(如果不存在) $this->create_models_table(); $wpdb->insert($table_name, $data); return $wpdb->insert_id; } /** * 创建模型表 */ private function create_models_table() { global $wpdb; $table_name = $wpdb->prefix . 'ar_models'; $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE IF NOT EXISTS $table_name ( id mediumint(9) NOT NULL AUTO_INCREMENT, filename varchar(255) NOT NULL, original_name varchar(255) NOT NULL, file_size bigint(20) NOT NULL, upload_date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, PRIMARY KEY (id) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); } /** * 获取模型URL */ public function get_model_url($model_id) { global $wpdb; $table_name = $wpdb->prefix . 'ar_models'; $filename = $wpdb->get_var($wpdb->prepare( "SELECT filename FROM $table_name WHERE id = %d", $model_id )); if ($filename) { return WP_AR_PREVIEW_PLUGIN_URL . 'assets/models/' . $filename; } return false; } }
- 创建前端AR预览组件,使用WebXR和Three.js实现AR功能: /** * AR预览组件 - 前端JavaScript实现 * 使用WebXR API和Three.js实现AR预览功能 */ class ARPreview { constructor(containerId, modelUrl, options = {}) { this.container = document.getElementById(containerId); this.modelUrl = modelUrl; this.options = Object.assign({ scale: 1.0, autoRotate: true, arScale: 'fixed', cameraControls: true }, options); this.scene = null; this.camera = null; this.renderer = null; this.model = null; this.xrSession = null; this.init(); } /** * 初始化AR场景 */ async init() { // 检查WebXR支持 if (!navigator.xr) { this.showError('您的浏览器不支持WebXR。请使用最新版的Chrome或Edge。'); return; } // 创建Three.js场景 this.scene = new THREE.Scene(); this.scene.background = new THREE.Color(0xffffff); // 创建相机 this.camera = new THREE.PerspectiveCamera( 60, this.container.clientWidth / this.container.clientHeight, 0.1, 1000 ); // 创建渲染器 this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); this.renderer.setSize( this.container.clientWidth, this.container.clientHeight ); this.renderer.xr.enabled = true; this.container.appendChild(this.renderer.domElement); // 添加光源 const ambientLight = new THREE.AmbientLight(0xffffff, 0.8); this.scene.add(ambientLight); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.6); directionalLight.position.set(1, 1, 1); this.scene.add(directionalLight); // 加载3D模型 await this.loadModel(); // 添加AR按钮 this.createARButton(); // 开始渲染循环 this.renderer.setAnimationLoop(() => { this.render(); }); // 处理窗口大小变化 window.addEventListener('resize', () => this.onWindowResize()); } /** * 加载3D模型 */ async loadModel() { return new Promise((resolve, reject) => { const loader = new THREE.GLTFLoader(); loader.load( this.modelUrl, (gltf) => { this.model = gltf.scene; this.model.scale.set( this.options.scale, this.options.scale, this.options.scale ); // 居中模型 const box = new THREE.Box3().setFromObject(this.model); const center = box.getCenter(new THREE.Vector3()); this.model.position.sub(center); this.scene.add(this.model); resolve(); }, (progress) => { // 加载进度回调 console.log(`模型加载进度: ${(progress.loaded / progress.total * 100).toFixed(2)}%`); }, (error) => { console.error('模型加载失败:', error); reject(error); } ); }); } /** * 创建AR按钮 */ createARButton() { const button = document.createElement('button'); button.id = 'ar-button'; button.textContent = '👁️ AR预览'; button.style.cssText = ` position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); padding: 12px 24px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; border-radius: 30px; font-size: 16px; cursor: pointer; z-index: 1000; box-shadow: 0 4px 15px rgba(0,0,0,0.2); `; button.addEventListener('click', () => this.enterAR()); this.container.appendChild(button); } /** * 进入AR模式 */ async enterAR() { try { // 请求AR会话 const session = await navigator.xr.requestSession('immersive-ar', { requiredFeatures: ['hit-test'], optionalFeatures: ['dom-overlay'], domOverlay: { root: this.container } }); this.xrSession = session; this.renderer.xr.setSession(session); // 创建AR控制器 this.controller = this.renderer.xr.getController(0); this.scene.add(this.controller); // 添加点击事件放置模型 this.controller.addEventListener('select', () => this.placeModel()); // 会话结束事件 session.addEventListener('end', () => { this.xrSession = null; }); } catch (error) { console.error('无法启动AR会话:', error); this.showError('无法启动AR功能。请确保设备支持AR并已授予相机权限。'); } } /** * 放置模型到AR空间 */ placeModel() { if (!this.model || !this.controller) return; // 创建模型副本 const modelClone = this.model.clone(); // 使用控制器位置 modelClone.position.copy(this.controller.position); // 随机旋转 modelClone.rotation.y = Math.random() * Math.PI * 2; this.scene.add(modelClone); } /** * 渲染循环 */ render() { if (this.model && this.options.autoRotate && !this.xrSession) { this.model.rotation.y += 0.005; } this.renderer.render(this.scene, this.camera); } /** * 窗口大小变化处理 */ onWindowResize() { this.camera.aspect = this.container.clientWidth / this.container.clientHeight; this.camera.updateProjectionMatrix(); this.renderer.setSize( this.container.clientWidth, this.container.clientHeight ); } /** * 显示错误信息 */ showError(message) { const errorDiv = document.createElement('div'); errorDiv.style.cssText = ` padding: 20px; background: #fee; border: 1px solid #f99; border-radius: 5px; margin: 10px 0; color: #c00; `; errorDiv.textContent = message; this.container.appendChild(errorDiv); } } // 导出到全局作用域 window.ARPreview = ARPreview;
- 创建短码系统和后台管理界面: <?php /** * 短码处理类 * 提供[ar_preview]短码用于在文章和页面中插入AR预览 */ class WP_AR_Preview_Shortcode { private static $instance = null; public static function get_instance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } private function __construct() { add_shortcode('ar_preview', array($this, 'render_shortcode')); add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts')); } /** * 渲染AR预览短码 */ public function render_shortcode($atts) { $atts = shortcode_atts(array( 'model_id' => 0, 'width' => '100%', 'height' => '500px', 'scale' => '1', 'auto_rotate' => 'true', 'title' => 'AR预览' ), $atts, 'ar_preview'); // 验证模型ID $model_id = intval($atts['model_id']); if ($model_id <= 0) { return '<div class="ar-error">请提供有效的模型ID</div>'; } // 获取模型URL $model_manager = WP_AR_Preview_Model::get_instance(); $model_url = $model_manager->get_model_url($model_id); if (!$model_url) { return '<div class="ar-error">找不到指定的3D模型</div>'; } // 生成唯一容器ID $container_id = 'ar-container-' . uniqid(); // 输出HTML结构 ob_start(); ?> <div class="ar-preview-wrapper"> <h3 class="ar-title"><?php echo esc_html($atts['title']); ?></h3> <div id="<?php echo esc_attr($container_id); ?>" class="ar-viewer" style="width: <?php echo esc_attr($atts['width']); ?>; height: <?php echo esc_attr($atts['height']); ?>; position: relative; border-radius: 8px; overflow: hidden; background: #f5f5f5;"> </div> <div class="ar-instructions" style="margin-top: 10px; font-size: 14px; color: #666;"> <p>💡 提示:点击"AR预览"按钮,使用手机摄像头在真实环境中查看模型</p> </div> </div> <script type="module"> document.addEventListener('DOMContentLoaded', function() { // 等待Three.js和相关依赖加载完成 if (typeof THREE !== 'undefined' && typeof ARPreview !== 'undefined') { new ARPreview('<?php echo esc_js($container_id); ?>', '<?php echo esc_js($model_url); ?>', { scale: <?php echo floatval($atts['scale']); ?>, autoRotate: <?php echo $atts['auto_rotate'] === 'true' ? 'true' : 'false'; ?>, arScale: 'fixed' }); } else { console.error('AR预览组件依赖未正确加载'); } }); </script> <?php return ob_get_clean(); } /** * 加载前端脚本和样式 */ public function enqueue_scripts() { // 只在需要时加载 if (!has_shortcode(get_post()->post_content, 'ar_preview')) { return; } // 加载Three.js wp_enqueue_script( 'three-js', 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js', array(), 'r128', true ); // 加载GLTFLoader wp_enqueue_script( 'three-gltf-loader', WP_AR_PREVIEW_PLUGIN_URL . 'assets/js/GLTFLoader.js', array('three-js'), '1.0.0', true ); // 加载WebXR polyfill(如果需要) wp_enqueue_script( 'webxr-polyfill', 'https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js', array(), '1.0.0', true ); // 加载主AR脚本 wp_enqueue_script( 'wp-ar-preview-frontend', WP_AR_PREVIEW_PLUGIN_URL . 'assets/js/ar-preview.js', array('three-js', 'three-gltf-loader'), WP_AR_PREVIEW_VERSION, true ); // 加载样式 wp_enqueue_style( 'wp-ar-preview-style', WP_AR_PREVIEW_PLUGIN_URL . 'assets/css/ar-style.css', array(), WP_AR_PREVIEW_VERSION ); } } ## 六、后台管理界面开发 创建后台管理界面,允许用户上传和管理3D模型: <?php/** 后台管理类 提供插件设置页面和模型管理功能 */ class WP_AR_Preview_Admin { private static $instance = null; public static function get_instance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } private function __construct() { add_action('admin_menu', array($this, 'add_admin_menu')); add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts')); add_action('wp_ajax_get_models_list', array($this, 'ajax_get_models_list')); } /** * 添加管理菜单 */ public function add_admin_menu() { add_menu_page( 'AR预览设置', 'AR预览', 'manage_options', 'wp-ar-preview', array($this, 'render_admin_page'), 'dashicons-visibility', 30 ); add_submenu_page( 'wp-ar-preview', '模型管理', '模型管理', 'manage_options', 'wp-ar-models', array($this, 'render_models_page') ); } /** * 渲染设置页面 */ public function render_admin_page() { $settings = get_option('wp_ar_preview_settings', array()); ?> <div class="wrap"> <h1>AR预览插件设置</h1> <form method="post" action="options.php"> <?php settings_fields('wp_ar_preview_settings_group'); ?> <table class="form-table"> <tr> <th scope="row">启用AR功能</th> <td> <label> <input type="checkbox" name="wp_ar_preview_settings[enable_ar]" value="1" <?php checked(1, $settings['enable_ar'] ?? 1); ?>> 启用增强现实预览功能 </label> </td> </tr> <tr> <th scope="row">默认模型缩放</th> <td> <input type="number" name="wp_ar_preview_settings[default_model_scale]" value="<?php echo esc_attr($settings['default_model_scale'] ?? 1); ?>" step="0.1" min="0.1" max="10"> <p class="description">设置3D模型的默认显示大小</p> </td> </tr> <tr> <th scope="row">AR按钮文字</th> <td> <input type="text" name="wp_ar_preview_settings[ar_button_text]" value="<?php echo esc_attr($settings['ar_button_text'] ?? '在您的空间中查看'); ?>" class="regular-text"> </td> </tr> <tr> <th scope="row">支持的格式</th> <td> <label> <input type="checkbox" name="wp_ar_preview_settings[supported_formats][]" value="glb" <?php echo in_array('glb', $settings['supported_formats'] ?? ['glb', 'gltf']) ? 'checked' : ''; ?>> .glb (二进制GLTF) </label><br> <label> <input type="checkbox" name="wp_ar_preview_settings[supported_formats][]" value="gltf" <?php echo in_array('gltf', $settings['supported_formats'] ?? ['glb', 'gltf']) ? 'checked' : ''; ?>> .gltf (JSON格式) </label> </td> </tr> </table> <?php submit_button(); ?> </form> <div class="card"> <h2>使用说明</h2> <ol> <li>在"模型管理"页面上传3D模型文件(支持.glb和.gltf格式)</li> <li>在文章或页面中使用短码:[ar_preview model_id="1"]</li> <li>短码参数说明: <ul> <li><code>model_id</code>: 模型ID(必填)</li> <li><code>width</code>: 预览区宽度,默认100%</li> <li><code>height</code>: 预览区高度,默认500px</li> <li><code>scale</code>: 模型缩放比例,默认1</li> <li><code>title</code>: 预览标题</li> </ul> </li> </ol> </div> </div> <?php } /** * 渲染模型管理页面 */ public function render_models_page() { // 处理模型上传 if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['ar_model'])) { $this->handle_model_upload(); } // 处理模型删除 if (isset($_GET['delete_model'])) { $this->handle_model_delete(intval($_GET['delete_model'])); } ?> <div class="wrap"> <h1>3D模型管理</h1> <!-- 上传表单 --> <div class="card" style="margin-bottom: 20px;"> <h2>上传新模型</h2> <form method="post" enctype="multipart/form-data"> <?php wp_nonce_field('wp_ar_preview_upload', 'ar_upload_nonce'); ?> <table class="form-table"> <tr> <th scope="row">选择模型文件</th> <td> <input type="file" name="ar_model" accept=".glb,.gltf" required> <p class="description">支持GLB和GLTF格式,最大50MB</p> </td> </tr> <tr> <th scope="row">模型名称</th> <td> <input type="text" name="model_name" class="regular-text" placeholder="例如:沙发模型" required> </td> </tr> <tr> <th scope="row">模型描述</th> <td> <textarea name="model_description" rows="3" class="large-text"></textarea> </td> </tr> </table> <?php submit_button('上传模型'); ?> </form> </div> <!-- 模型列表 --> <div class="card"> <h2>已上传的模型</h2> <?php $this->render_models_table(); ?> </div> </div> <?php } /** * 渲染模型表格 */ private function render_models_table() { global $wpdb; $table_name = $wpdb->prefix . 'ar_models'; $models = $wpdb->get_results("SELECT * FROM $table_name ORDER BY upload_date DESC"); if (empty($models)) { echo '<p>暂无模型,请先上传。</p>'; return; } ?> <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 $model->id; ?></td> <td><?php echo esc_html($model->filename); ?></td> <td><?php echo esc_html($model->original_name); ?></td> <td><?php echo size_format($model->file_size); ?></td> <td><?php echo date('Y-m-d H:i', strtotime($model->upload_date)); ?></td> <td> <code>[ar_preview model_id="<?php echo $model->id; ?>"]</code> <button type="button" class="button button-small copy-shortcode" data-shortcode='[ar_preview model_id="<?php echo $model->id; ?>"]'> 复制 </button> </td> <td> <a href="<?php echo WP_AR_PREVIEW_PLUGIN_URL . 'assets/models/' . $model->filename; ?>" class="button" download>下载</a> <a href="?page=wp-ar-models&delete_model=<?php echo $model->id; ?>" class="button button-link-delete" onclick="return confirm('确定要删除这个模型吗?')">删除</a> </td> </tr> <?php endforeach; ?> </tbody> </table> <script> jQuery(document).ready(function($) { $('.copy-shortcode').click(function() { var shortcode = $(this).data('shortcode'); navigator.clipboard.writeText(shortcode).then(function() { alert('短码已复制到剪贴板!'); }); }); }); </script> <?php } /** * 处理模型上传 */ private function handle_model_upload() { if (!wp_verify_nonce($_POST['ar_upload_nonce'], 'wp_ar_preview_upload')) { wp_die('安全验证失败'); } if (!current_user_can('upload_files')) { wp_die('您没有上传文件的权限'); } $model_manager = WP_AR_Preview_Model::get_instance(); // 模拟$_FILES结构 $file = array( 'name' => $_FILES['ar_model']['name'], 'type' => $_FILES['ar_model']['type'], 'tmp_name' => $_FILES['ar_model']['tmp_name'], 'error' => $_FILES['ar_model']['error'], 'size' => $_FILES['ar_model']['size'] ); $_FILES['model_file'] = $file; // 调用模型处理类的上传方法 $model_manager->handle_model_upload(); } /** * 处理模型删除 */ private function handle_model_delete($model_id) { global $wpdb; $table_name = $wpdb->prefix . 'ar_models'; // 获取文件名 $filename = $wpdb->get_var($wpdb->prepare( "SELECT filename FROM $table_name WHERE id = %d", $model_id )); if ($filename) { // 删除文件 $file_path = WP_AR_PREVIEW_MODEL_DIR . $filename; if (file_exists($file_path)) { unlink($file_path); } // 删除数据库记录 $wpdb->delete($table_name, array('id' => $model_id)); echo '<div class="notice notice-success"><p>模型已删除</p></div>'; } } /** * 加载后台脚本 */ public function enqueue_admin_scripts($hook) { if (strpos($hook, 'wp-ar-preview') === false) { return; } wp_enqueue_script( 'wp-ar-preview-admin', WP_AR_PREVIEW_PLUGIN_URL . 'assets/js/admin.js', array('jquery'), WP_AR_PREVIEW_VERSION, true ); wp_enqueue_style( 'wp-ar-preview-admin-style', WP_AR_PREVIEW_PLUGIN_URL . 'assets/css/admin.css', array(), WP_AR_PREVIEW_VERSION ); } } ## 七、CSS样式文件 创建前端样式文件,美化AR预览界面: / assets/css/ar-style.css / / AR预览容器样式 /.ar-preview-wrapper { margin: 20px 0; border: 1px solid #e0e0e0; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); background: white; } .ar-title { padding: 15px 20px; margin: 0; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; font-size: 18px; font-weight: 600; } .ar-viewer { position: relative; min-height: 400px; } / 加载状态 /.ar-loading { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: #666; } .ar-loading-spinner { display: inline-block; width: 40px; height: 40px; border: 3px solid #f3f3f3; border-top: 3px solid #667eea; border-radius: 50%; animation: ar-spin 1s linear infinite; margin-bottom: 10px; } @keyframes ar-spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } / AR按钮样式 /
- transition: all 0.3s ease; }
- transform: translateX(-50%) scale(1.05); box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25); }
- transform: translateX(-50%) scale(0.95); } / 错误提示 /.ar-error { padding: 20px; background: #fff5f5; border: 1px solid #feb2b2; border-radius: 8px; color: #c53030; text-align: center; } / 响应式设计 /@media (max-width: 768px) { .ar-preview-wrapper { margin: 10px 0; border-radius: 8px; } .ar-title { padding: 12px 15px; font-size: 16px; } .ar-viewer { min-height: 300px; } } / 模型控制面板 /.ar-controls { position: absolute; bottom: 70px; left: 20px; display: flex; gap: 10px; z-index: 100; } .control-button { width: 40px; height: 40px; border-radius: 50%; background: white; border: none; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 18px;
增强现实(AR)技术正在改变用户与数字内容的交互方式。在WordPress电商或展示类网站中,集成AR预览功能可以让用户通过手机摄像头查看产品在真实环境中的效果,显著提升用户体验和转化率。本教程将指导您开发一个支持AR预览的WordPress定制插件。
-
环境要求:
- WordPress 5.0+
- PHP 7.4+
- 支持HTTPS的服务器(AR功能需要安全连接)
-
技术选型:
- 使用WebXR API进行AR功能开发
- Three.js作为3D渲染引擎
- Model-Viewer组件用于快速集成
-
插件基础结构:
wp-ar-preview/
├── wp-ar-preview.php # 主插件文件
├── includes/
│ ├── class-ar-model.php # AR模型处理类
│ ├── class-shortcode.php # 短码处理类
│ └── class-admin.php # 后台管理类
├── assets/
│ ├── js/
│ ├── css/
│ └── models/ # 3D模型存储目录
├── templates/ # 前端模板
└── uninstall.php # 卸载脚本
环境要求:
- WordPress 5.0+
- PHP 7.4+
- 支持HTTPS的服务器(AR功能需要安全连接)
技术选型:
- 使用WebXR API进行AR功能开发
- Three.js作为3D渲染引擎
- Model-Viewer组件用于快速集成
插件基础结构:
wp-ar-preview/
├── wp-ar-preview.php # 主插件文件
├── includes/
│ ├── class-ar-model.php # AR模型处理类
│ ├── class-shortcode.php # 短码处理类
│ └── class-admin.php # 后台管理类
├── assets/
│ ├── js/
│ ├── css/
│ └── models/ # 3D模型存储目录
├── templates/ # 前端模板
└── uninstall.php # 卸载脚本
首先创建插件的主文件,这是插件的入口点:
<?php
/**
* Plugin Name: WordPress AR预览插件
* Plugin URI: https://yourwebsite.com/
* Description: 为WordPress产品添加AR预览功能
* Version: 1.0.0
* Author: 您的名称
* License: GPL v2 or later
* Text Domain: wp-ar-preview
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('WP_AR_PREVIEW_VERSION', '1.0.0');
define('WP_AR_PREVIEW_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('WP_AR_PREVIEW_PLUGIN_URL', plugin_dir_url(__FILE__));
define('WP_AR_PREVIEW_MODEL_DIR', WP_AR_PREVIEW_PLUGIN_DIR . 'assets/models/');
// 自动加载类文件
spl_autoload_register(function ($class_name) {
$prefix = 'WP_AR_Preview_';
$base_dir = WP_AR_PREVIEW_PLUGIN_DIR . 'includes/';
$len = strlen($prefix);
if (strncmp($prefix, $class_name, $len) !== 0) {
return;
}
$relative_class = substr($class_name, $len);
$file = $base_dir . 'class-' . str_replace('_', '-', strtolower($relative_class)) . '.php';
if (file_exists($file)) {
require_once $file;
}
});
// 初始化插件
function wp_ar_preview_init() {
// 检查WordPress版本
if (version_compare(get_bloginfo('version'), '5.0', '<')) {
add_action('admin_notices', function() {
echo '<div class="notice notice-error"><p>';
echo __('AR预览插件需要WordPress 5.0或更高版本', 'wp-ar-preview');
echo '</p></div>';
});
return;
}
// 初始化各个组件
WP_AR_Preview_Admin::get_instance();
WP_AR_Preview_Shortcode::get_instance();
WP_AR_Preview_Model::get_instance();
}
add_action('plugins_loaded', 'wp_ar_preview_init');
// 激活插件时的操作
register_activation_hook(__FILE__, function() {
// 创建必要的目录
if (!file_exists(WP_AR_PREVIEW_MODEL_DIR)) {
wp_mkdir_p(WP_AR_PREVIEW_MODEL_DIR);
}
// 添加默认选项
add_option('wp_ar_preview_settings', array(
'enable_ar' => '1',
'default_model_scale' => '1',
'ar_button_text' => '在您的空间中查看',
'supported_formats' => array('glb', 'gltf')
));
});
// 停用插件时的清理操作
register_deactivation_hook(__FILE__, function() {
// 清理临时数据
delete_transient('wp_ar_preview_cache');
});
创建AR模型处理类,负责处理3D模型的上传、验证和存储:
<?php
/**
* AR模型处理类
* 负责处理3D模型文件的上传、验证和管理
*/
class WP_AR_Preview_Model {
private static $instance = null;
private $allowed_types = array('glb', 'gltf');
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
add_action('wp_ajax_upload_ar_model', array($this, 'handle_model_upload'));
add_action('wp_ajax_nopriv_upload_ar_model', array($this, 'handle_model_upload'));
}
/**
* 处理模型上传
*/
public function handle_model_upload() {
// 验证nonce
if (!wp_verify_nonce($_POST['nonce'], 'wp_ar_preview_upload')) {
wp_die('安全验证失败');
}
// 检查文件上传
if (!isset($_FILES['model_file'])) {
wp_send_json_error('没有上传文件');
}
$file = $_FILES['model_file'];
// 验证文件类型
$file_ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($file_ext, $this->allowed_types)) {
wp_send_json_error('不支持的文件格式。请上传GLB或GLTF文件。');
}
// 验证文件大小(限制为50MB)
$max_size = 50 * 1024 * 1024;
if ($file['size'] > $max_size) {
wp_send_json_error('文件太大。最大允许50MB。');
}
// 生成唯一文件名
$filename = uniqid('model_') . '.' . $file_ext;
$destination = WP_AR_PREVIEW_MODEL_DIR . $filename;
// 移动上传的文件
if (move_uploaded_file($file['tmp_name'], $destination)) {
// 保存到数据库
$model_id = $this->save_model_to_db(array(
'filename' => $filename,
'original_name' => $file['name'],
'file_size' => $file['size'],
'upload_date' => current_time('mysql')
));
wp_send_json_success(array(
'model_id' => $model_id,
'filename' => $filename,
'url' => WP_AR_PREVIEW_PLUGIN_URL . 'assets/models/' . $filename
));
} else {
wp_send_json_error('文件上传失败');
}
}
/**
* 保存模型信息到数据库
*/
private function save_model_to_db($data) {
global $wpdb;
$table_name = $wpdb->prefix . 'ar_models';
// 创建表(如果不存在)
$this->create_models_table();
$wpdb->insert($table_name, $data);
return $wpdb->insert_id;
}
/**
* 创建模型表
*/
private function create_models_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'ar_models';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
filename varchar(255) NOT NULL,
original_name varchar(255) NOT NULL,
file_size bigint(20) NOT NULL,
upload_date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
PRIMARY KEY (id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
/**
* 获取模型URL
*/
public function get_model_url($model_id) {
global $wpdb;
$table_name = $wpdb->prefix . 'ar_models';
$filename = $wpdb->get_var($wpdb->prepare(
"SELECT filename FROM $table_name WHERE id = %d",
$model_id
));
if ($filename) {
return WP_AR_PREVIEW_PLUGIN_URL . 'assets/models/' . $filename;
}
return false;
}
}
创建前端AR预览组件,使用WebXR和Three.js实现AR功能:
/**
* AR预览组件 - 前端JavaScript实现
* 使用WebXR API和Three.js实现AR预览功能
*/
class ARPreview {
constructor(containerId, modelUrl, options = {}) {
this.container = document.getElementById(containerId);
this.modelUrl = modelUrl;
this.options = Object.assign({
scale: 1.0,
autoRotate: true,
arScale: 'fixed',
cameraControls: true
}, options);
this.scene = null;
this.camera = null;
this.renderer = null;
this.model = null;
this.xrSession = null;
this.init();
}
/**
* 初始化AR场景
*/
async init() {
// 检查WebXR支持
if (!navigator.xr) {
this.showError('您的浏览器不支持WebXR。请使用最新版的Chrome或Edge。');
return;
}
// 创建Three.js场景
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(0xffffff);
// 创建相机
this.camera = new THREE.PerspectiveCamera(
60,
this.container.clientWidth / this.container.clientHeight,
0.1,
1000
);
// 创建渲染器
this.renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
this.renderer.setSize(
this.container.clientWidth,
this.container.clientHeight
);
this.renderer.xr.enabled = true;
this.container.appendChild(this.renderer.domElement);
// 添加光源
const ambientLight = new THREE.AmbientLight(0xffffff, 0.8);
this.scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.6);
directionalLight.position.set(1, 1, 1);
this.scene.add(directionalLight);
// 加载3D模型
await this.loadModel();
// 添加AR按钮
this.createARButton();
// 开始渲染循环
this.renderer.setAnimationLoop(() => {
this.render();
});
// 处理窗口大小变化
window.addEventListener('resize', () => this.onWindowResize());
}
/**
* 加载3D模型
*/
async loadModel() {
return new Promise((resolve, reject) => {
const loader = new THREE.GLTFLoader();
loader.load(
this.modelUrl,
(gltf) => {
this.model = gltf.scene;
this.model.scale.set(
this.options.scale,
this.options.scale,
this.options.scale
);
// 居中模型
const box = new THREE.Box3().setFromObject(this.model);
const center = box.getCenter(new THREE.Vector3());
this.model.position.sub(center);
this.scene.add(this.model);
resolve();
},
(progress) => {
// 加载进度回调
console.log(`模型加载进度: ${(progress.loaded / progress.total * 100).toFixed(2)}%`);
},
(error) => {
console.error('模型加载失败:', error);
reject(error);
}
);
});
}
/**
* 创建AR按钮
*/
createARButton() {
const button = document.createElement('button');
button.id = 'ar-button';
button.textContent = '👁️ AR预览';
button.style.cssText = `
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
padding: 12px 24px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 30px;
font-size: 16px;
cursor: pointer;
z-index: 1000;
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
`;
button.addEventListener('click', () => this.enterAR());
this.container.appendChild(button);
}
/**
* 进入AR模式
*/
async enterAR() {
try {
// 请求AR会话
const session = await navigator.xr.requestSession('immersive-ar', {
requiredFeatures: ['hit-test'],
optionalFeatures: ['dom-overlay'],
domOverlay: { root: this.container }
});
this.xrSession = session;
this.renderer.xr.setSession(session);
// 创建AR控制器
this.controller = this.renderer.xr.getController(0);
this.scene.add(this.controller);
// 添加点击事件放置模型
this.controller.addEventListener('select', () => this.placeModel());
// 会话结束事件
session.addEventListener('end', () => {
this.xrSession = null;
});
} catch (error) {
console.error('无法启动AR会话:', error);
this.showError('无法启动AR功能。请确保设备支持AR并已授予相机权限。');
}
}
/**
* 放置模型到AR空间
*/
placeModel() {
if (!this.model || !this.controller) return;
// 创建模型副本
const modelClone = this.model.clone();
// 使用控制器位置
modelClone.position.copy(this.controller.position);
// 随机旋转
modelClone.rotation.y = Math.random() * Math.PI * 2;
this.scene.add(modelClone);
}
/**
* 渲染循环
*/
render() {
if (this.model && this.options.autoRotate && !this.xrSession) {
this.model.rotation.y += 0.005;
}
this.renderer.render(this.scene, this.camera);
}
/**
* 窗口大小变化处理
*/
onWindowResize() {
this.camera.aspect = this.container.clientWidth / this.container.clientHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(
this.container.clientWidth,
this.container.clientHeight
);
}
/**
* 显示错误信息
*/
showError(message) {
const errorDiv = document.createElement('div');
errorDiv.style.cssText = `
padding: 20px;
background: #fee;
border: 1px solid #f99;
border-radius: 5px;
margin: 10px 0;
color: #c00;
`;
errorDiv.textContent = message;
this.container.appendChild(errorDiv);
}
}
// 导出到全局作用域
window.ARPreview = ARPreview;
创建短码系统和后台管理界面:
<?php
/**
* 短码处理类
* 提供[ar_preview]短码用于在文章和页面中插入AR预览
*/
class WP_AR_Preview_Shortcode {
private static $instance = null;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
add_shortcode('ar_preview', array($this, 'render_shortcode'));
add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'));
}
/**
* 渲染AR预览短码
*/
public function render_shortcode($atts) {
$atts = shortcode_atts(array(
'model_id' => 0,
'width' => '100%',
'height' => '500px',
'scale' => '1',
'auto_rotate' => 'true',
'title' => 'AR预览'
), $atts, 'ar_preview');
// 验证模型ID
$model_id = intval($atts['model_id']);
if ($model_id <= 0) {
return '<div class="ar-error">请提供有效的模型ID</div>';
}
// 获取模型URL
$model_manager = WP_AR_Preview_Model::get_instance();
$model_url = $model_manager->get_model_url($model_id);
if (!$model_url) {
return '<div class="ar-error">找不到指定的3D模型</div>';
}
// 生成唯一容器ID
$container_id = 'ar-container-' . uniqid();
// 输出HTML结构
ob_start();
?>
<div class="ar-preview-wrapper">
<h3 class="ar-title"><?php echo esc_html($atts['title']); ?></h3>
<div id="<?php echo esc_attr($container_id); ?>"
class="ar-viewer"
style="width: <?php echo esc_attr($atts['width']); ?>;
height: <?php echo esc_attr($atts['height']); ?>;
position: relative;
border-radius: 8px;
overflow: hidden;
background: #f5f5f5;">
</div>
<div class="ar-instructions" style="margin-top: 10px; font-size: 14px; color: #666;">
<p>💡 提示:点击"AR预览"按钮,使用手机摄像头在真实环境中查看模型</p>
</div>
</div>
<script type="module">
document.addEventListener('DOMContentLoaded', function() {
// 等待Three.js和相关依赖加载完成
if (typeof THREE !== 'undefined' && typeof ARPreview !== 'undefined') {
new ARPreview('<?php echo esc_js($container_id); ?>', '<?php echo esc_js($model_url); ?>', {
scale: <?php echo floatval($atts['scale']); ?>,
autoRotate: <?php echo $atts['auto_rotate'] === 'true' ? 'true' : 'false'; ?>,
arScale: 'fixed'
});
} else {
console.error('AR预览组件依赖未正确加载');
}
});
</script>
<?php
return ob_get_clean();
}
/**
* 加载前端脚本和样式
*/
public function enqueue_scripts() {
// 只在需要时加载
if (!has_shortcode(get_post()->post_content, 'ar_preview')) {
return;
}
// 加载Three.js
wp_enqueue_script(
'three-js',
'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js',
array(),
'r128',
true
);
// 加载GLTFLoader
wp_enqueue_script(
'three-gltf-loader',
WP_AR_PREVIEW_PLUGIN_URL . 'assets/js/GLTFLoader.js',
array('three-js'),
'1.0.0',
true
);
// 加载WebXR polyfill(如果需要)
wp_enqueue_script(
'webxr-polyfill',
'https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js',
array(),
'1.0.0',
true
);
// 加载主AR脚本
wp_enqueue_script(
'wp-ar-preview-frontend',
WP_AR_PREVIEW_PLUGIN_URL . 'assets/js/ar-preview.js',
array('three-js', 'three-gltf-loader'),
WP_AR_PREVIEW_VERSION,
true
);
// 加载样式
wp_enqueue_style(
'wp-ar-preview-style',
WP_AR_PREVIEW_PLUGIN_URL . 'assets/css/ar-style.css',
array(),
WP_AR_PREVIEW_VERSION
);
}
}
## 六、后台管理界面开发
创建后台管理界面,允许用户上传和管理3D模型:
<?php
/**
- 后台管理类
- 提供插件设置页面和模型管理功能
*/
class WP_AR_Preview_Admin {
private static $instance = null;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
add_action('admin_menu', array($this, 'add_admin_menu'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
add_action('wp_ajax_get_models_list', array($this, 'ajax_get_models_list'));
}
/**
* 添加管理菜单
*/
public function add_admin_menu() {
add_menu_page(
'AR预览设置',
'AR预览',
'manage_options',
'wp-ar-preview',
array($this, 'render_admin_page'),
'dashicons-visibility',
30
);
add_submenu_page(
'wp-ar-preview',
'模型管理',
'模型管理',
'manage_options',
'wp-ar-models',
array($this, 'render_models_page')
);
}
/**
* 渲染设置页面
*/
public function render_admin_page() {
$settings = get_option('wp_ar_preview_settings', array());
?>
<div class="wrap">
<h1>AR预览插件设置</h1>
<form method="post" action="options.php">
<?php settings_fields('wp_ar_preview_settings_group'); ?>
<table class="form-table">
<tr>
<th scope="row">启用AR功能</th>
<td>
<label>
<input type="checkbox" name="wp_ar_preview_settings[enable_ar]"
value="1" <?php checked(1, $settings['enable_ar'] ?? 1); ?>>
启用增强现实预览功能
</label>
</td>
</tr>
<tr>
<th scope="row">默认模型缩放</th>
<td>
<input type="number" name="wp_ar_preview_settings[default_model_scale]"
value="<?php echo esc_attr($settings['default_model_scale'] ?? 1); ?>"
step="0.1" min="0.1" max="10">
<p class="description">设置3D模型的默认显示大小</p>
</td>
</tr>
<tr>
<th scope="row">AR按钮文字</th>
<td>
<input type="text" name="wp_ar_preview_settings[ar_button_text]"
value="<?php echo esc_attr($settings['ar_button_text'] ?? '在您的空间中查看'); ?>"
class="regular-text">
</td>
</tr>
<tr>
<th scope="row">支持的格式</th>
<td>
<label>
<input type="checkbox" name="wp_ar_preview_settings[supported_formats][]"
value="glb" <?php echo in_array('glb', $settings['supported_formats'] ?? ['glb', 'gltf']) ? 'checked' : ''; ?>>
.glb (二进制GLTF)
</label><br>
<label>
<input type="checkbox" name="wp_ar_preview_settings[supported_formats][]"
value="gltf" <?php echo in_array('gltf', $settings['supported_formats'] ?? ['glb', 'gltf']) ? 'checked' : ''; ?>>
.gltf (JSON格式)
</label>
</td>
</tr>
</table>
<?php submit_button(); ?>
</form>
<div class="card">
<h2>使用说明</h2>
<ol>
<li>在"模型管理"页面上传3D模型文件(支持.glb和.gltf格式)</li>
<li>在文章或页面中使用短码:[ar_preview model_id="1"]</li>
<li>短码参数说明:
<ul>
<li><code>model_id</code>: 模型ID(必填)</li>
<li><code>width</code>: 预览区宽度,默认100%</li>
<li><code>height</code>: 预览区高度,默认500px</li>
<li><code>scale</code>: 模型缩放比例,默认1</li>
<li><code>title</code>: 预览标题</li>
</ul>
</li>
</ol>
</div>
</div>
<?php
}
/**
* 渲染模型管理页面
*/
public function render_models_page() {
// 处理模型上传
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['ar_model'])) {
$this->handle_model_upload();
}
// 处理模型删除
if (isset($_GET['delete_model'])) {
$this->handle_model_delete(intval($_GET['delete_model']));
}
?>
<div class="wrap">
<h1>3D模型管理</h1>
<!-- 上传表单 -->
<div class="card" style="margin-bottom: 20px;">
<h2>上传新模型</h2>
<form method="post" enctype="multipart/form-data">
<?php wp_nonce_field('wp_ar_preview_upload', 'ar_upload_nonce'); ?>
<table class="form-table">
<tr>
<th scope="row">选择模型文件</th>
<td>
<input type="file" name="ar_model" accept=".glb,.gltf" required>
<p class="description">支持GLB和GLTF格式,最大50MB</p>
</td>
</tr>
<tr>
<th scope="row">模型名称</th>
<td>
<input type="text" name="model_name" class="regular-text"
placeholder="例如:沙发模型" required>
</td>
</tr>
<tr>
<th scope="row">模型描述</th>
<td>
<textarea name="model_description" rows="3" class="large-text"></textarea>
</td>
</tr>
</table>
<?php submit_button('上传模型'); ?>
</form>
</div>
<!-- 模型列表 -->
<div class="card">
<h2>已上传的模型</h2>
<?php $this->render_models_table(); ?>
</div>
</div>
<?php
}
/**
* 渲染模型表格
*/
private function render_models_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'ar_models';
$models = $wpdb->get_results("SELECT * FROM $table_name ORDER BY upload_date DESC");
if (empty($models)) {
echo '<p>暂无模型,请先上传。</p>';
return;
}
?>
<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 $model->id; ?></td>
<td><?php echo esc_html($model->filename); ?></td>
<td><?php echo esc_html($model->original_name); ?></td>
<td><?php echo size_format($model->file_size); ?></td>
<td><?php echo date('Y-m-d H:i', strtotime($model->upload_date)); ?></td>
<td>
<code>[ar_preview model_id="<?php echo $model->id; ?>"]</code>
<button type="button" class="button button-small copy-shortcode"
data-shortcode='[ar_preview model_id="<?php echo $model->id; ?>"]'>
复制
</button>
</td>
<td>
<a href="<?php echo WP_AR_PREVIEW_PLUGIN_URL . 'assets/models/' . $model->filename; ?>"
class="button" download>下载</a>
<a href="?page=wp-ar-models&delete_model=<?php echo $model->id; ?>"
class="button button-link-delete"
onclick="return confirm('确定要删除这个模型吗?')">删除</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<script>
jQuery(document).ready(function($) {
$('.copy-shortcode').click(function() {
var shortcode = $(this).data('shortcode');
navigator.clipboard.writeText(shortcode).then(function() {
alert('短码已复制到剪贴板!');
});
});
});
</script>
<?php
}
/**
* 处理模型上传
*/
private function handle_model_upload() {
if (!wp_verify_nonce($_POST['ar_upload_nonce'], 'wp_ar_preview_upload')) {
wp_die('安全验证失败');
}
if (!current_user_can('upload_files')) {
wp_die('您没有上传文件的权限');
}
$model_manager = WP_AR_Preview_Model::get_instance();
// 模拟$_FILES结构
$file = array(
'name' => $_FILES['ar_model']['name'],
'type' => $_FILES['ar_model']['type'],
'tmp_name' => $_FILES['ar_model']['tmp_name'],
'error' => $_FILES['ar_model']['error'],
'size' => $_FILES['ar_model']['size']
);
$_FILES['model_file'] = $file;
// 调用模型处理类的上传方法
$model_manager->handle_model_upload();
}
/**
* 处理模型删除
*/
private function handle_model_delete($model_id) {
global $wpdb;
$table_name = $wpdb->prefix . 'ar_models';
// 获取文件名
$filename = $wpdb->get_var($wpdb->prepare(
"SELECT filename FROM $table_name WHERE id = %d",
$model_id
));
if ($filename) {
// 删除文件
$file_path = WP_AR_PREVIEW_MODEL_DIR . $filename;
if (file_exists($file_path)) {
unlink($file_path);
}
// 删除数据库记录
$wpdb->delete($table_name, array('id' => $model_id));
echo '<div class="notice notice-success"><p>模型已删除</p></div>';
}
}
/**
* 加载后台脚本
*/
public function enqueue_admin_scripts($hook) {
if (strpos($hook, 'wp-ar-preview') === false) {
return;
}
wp_enqueue_script(
'wp-ar-preview-admin',
WP_AR_PREVIEW_PLUGIN_URL . 'assets/js/admin.js',
array('jquery'),
WP_AR_PREVIEW_VERSION,
true
);
wp_enqueue_style(
'wp-ar-preview-admin-style',
WP_AR_PREVIEW_PLUGIN_URL . 'assets/css/admin.css',
array(),
WP_AR_PREVIEW_VERSION
);
}
}
## 七、CSS样式文件
创建前端样式文件,美化AR预览界面:
/ assets/css/ar-style.css /
/ AR预览容器样式 /
.ar-preview-wrapper {
margin: 20px 0;
border: 1px solid #e0e0e0;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
background: white;
}
.ar-title {
padding: 15px 20px;
margin: 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
font-size: 18px;
font-weight: 600;
}
.ar-viewer {
position: relative;
min-height: 400px;
}
/ 加载状态 /
.ar-loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
color: #666;
}
.ar-loading-spinner {
display: inline-block;
width: 40px;
height: 40px;
border: 3px solid #f3f3f3;
border-top: 3px solid #667eea;
border-radius: 50%;
animation: ar-spin 1s linear infinite;
margin-bottom: 10px;
}
@keyframes ar-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/ AR按钮样式 /
transition: all 0.3s ease;
transition: all 0.3s ease;
}
transform: translateX(-50%) scale(1.05);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
transform: translateX(-50%) scale(1.05);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
}
transform: translateX(-50%) scale(0.95);
transform: translateX(-50%) scale(0.95);
}
/ 错误提示 /
.ar-error {
padding: 20px;
background: #fff5f5;
border: 1px solid #feb2b2;
border-radius: 8px;
color: #c53030;
text-align: center;
}
/ 响应式设计 /
@media (max-width: 768px) {
.ar-preview-wrapper {
margin: 10px 0;
border-radius: 8px;
}
.ar-title {
padding: 12px 15px;
font-size: 16px;
}
.ar-viewer {
min-height: 300px;
}
}
/ 模型控制面板 /
.ar-controls {
position: absolute;
bottom: 70px;
left: 20px;
display: flex;
gap: 10px;
z-index: 100;
}
.control-button {
width: 40px;
height: 40px;
border-radius: 50%;
background: white;
border: none;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;


