实战教学:为WordPress网站添加基于AR的虚拟产品摆放与场景体验功能
引言:AR技术如何重塑电商体验
在当今数字化时代,增强现实(AR)技术正以前所未有的速度改变着消费者的购物体验。想象一下,当用户访问您的网站时,他们不仅能看到产品的平面图片,还能通过手机摄像头将虚拟产品"放置"在自己的真实环境中,从各个角度查看产品细节,甚至与产品进行互动。这种沉浸式体验不仅显著提升用户参与度,还能大幅降低退货率,提高转化率。
根据最新市场研究,采用AR技术的电商平台平均转化率提升了40%,客户互动时间增加了近一倍。对于WordPress网站所有者来说,集成AR功能不再是遥不可及的高科技梦想,而是可以通过代码二次开发实现的实用功能。
本教程将详细指导您如何为WordPress网站添加基于AR的虚拟产品摆放与场景体验功能,通过实用的代码示例和分步指南,帮助您打造前沿的交互式购物体验。
第一部分:AR技术基础与准备工作
1.1 AR技术原理简介
增强现实(AR)是一种将虚拟信息叠加到真实世界中的技术,通过设备摄像头捕捉现实场景,并在其上叠加计算机生成的图像、视频或3D模型。在电商领域,AR主要应用于:
- 虚拟试穿/试戴:用户可以看到产品穿戴在身上的效果
- 虚拟摆放:将家具、装饰品等放置在实际环境中查看效果
- 产品交互:允许用户旋转、缩放、自定义虚拟产品
1.2 技术选型与工具准备
在开始开发前,我们需要选择合适的AR技术方案:
方案一:基于Web的AR(WebAR)
- 优点:无需安装应用,跨平台兼容性好
- 技术栈:A-Frame、AR.js、Three.js
- 适合:轻量级AR体验,快速部署
方案二:原生AR SDK集成
- 优点:性能更好,功能更丰富
- 技术栈:ARKit(iOS)、ARCore(Android)
- 适合:高性能要求的复杂AR体验
方案三:混合方案
- 结合WebAR和原生SDK的优势
- 使用WebXR Device API
对于WordPress网站,我们推荐使用WebAR方案,因为它具有最好的兼容性和部署便利性。
开发环境准备:
- WordPress开发环境(本地或测试服务器)
- 代码编辑器(VS Code、Sublime Text等)
- 基础的前端开发知识(HTML、CSS、JavaScript)
- 3D模型处理工具(如Blender,用于准备产品模型)
1.3 3D模型准备与优化
AR体验的核心是3D模型,我们需要为每个产品准备高质量的3D模型:
-
模型格式选择:
- GLTF/GLB:推荐格式,体积小,加载快
- OBJ+MTL:通用格式,但文件较大
- FBX:功能丰富,但需要转换
-
模型优化技巧:
- 减少多边形数量(在保持质量的前提下)
- 压缩纹理图像
- 使用合理的LOD(细节层次)系统
- 确保模型尺寸与实际产品一致
-
模型创建流程:
产品测量 → 3D建模 → 纹理贴图 → 模型优化 → 格式转换 → 测试验证
第二部分:WordPress环境配置与基础架构
2.1 创建自定义插件框架
首先,我们需要创建一个WordPress插件来管理所有AR相关功能:
<?php
/**
* Plugin Name: AR Product Viewer for WordPress
* Plugin URI: https://yourwebsite.com/
* Description: 为WordPress网站添加AR产品查看和虚拟摆放功能
* Version: 1.0.0
* Author: Your Name
* License: GPL v2 or later
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('ARPV_VERSION', '1.0.0');
define('ARPV_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('ARPV_PLUGIN_URL', plugin_dir_url(__FILE__));
// 初始化插件
class AR_Product_Viewer {
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() {
// 后台初始化
add_action('admin_init', array($this, 'admin_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'));
// 添加短代码
add_shortcode('ar_product_viewer', array($this, 'ar_product_viewer_shortcode'));
// 为产品添加自定义字段
add_action('add_meta_boxes', array($this, 'add_product_ar_meta_box'));
add_action('save_post', array($this, 'save_product_ar_meta'));
}
// 更多方法将在后续章节实现...
}
// 启动插件
AR_Product_Viewer::get_instance();
?>
2.2 数据库设计与模型管理
我们需要扩展WordPress数据库来存储AR相关数据:
// 在插件激活时创建数据库表
register_activation_hook(__FILE__, 'arpv_create_database_tables');
function arpv_create_database_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_name = $wpdb->prefix . 'arpv_models';
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
product_id bigint(20) NOT NULL,
model_name varchar(255) NOT NULL,
model_file_url varchar(500) NOT NULL,
model_type varchar(50) DEFAULT 'glb',
model_size int(11) DEFAULT 0,
scale_x float DEFAULT 1.0,
scale_y float DEFAULT 1.0,
scale_z float DEFAULT 1.0,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY product_id (product_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
// 添加版本选项
add_option('arpv_db_version', '1.0');
}
2.3 后台管理界面设计
创建用户友好的后台界面来管理AR模型:
// 添加管理菜单
public function add_admin_menu() {
add_menu_page(
'AR产品查看器',
'AR产品查看器',
'manage_options',
'ar-product-viewer',
array($this, 'render_admin_page'),
'dashicons-visibility',
30
);
add_submenu_page(
'ar-product-viewer',
'模型管理',
'模型管理',
'manage_options',
'arpv-model-manager',
array($this, 'render_model_manager_page')
);
add_submenu_page(
'ar-product-viewer',
'AR设置',
'设置',
'manage_options',
'arpv-settings',
array($this, 'render_settings_page')
);
}
// 渲染模型管理页面
public function render_model_manager_page() {
?>
<div class="wrap">
<h1>AR模型管理</h1>
<div class="arpv-admin-container">
<div class="arpv-admin-header">
<button id="arpv-add-model" class="button button-primary">添加新模型</button>
<div class="arpv-search-box">
<input type="text" id="arpv-model-search" placeholder="搜索模型...">
</div>
</div>
<div class="arpv-model-list">
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th>ID</th>
<th>产品名称</th>
<th>模型名称</th>
<th>文件类型</th>
<th>文件大小</th>
<th>操作</th>
</tr>
</thead>
<tbody id="arpv-model-table-body">
<!-- 通过AJAX动态加载 -->
</tbody>
</table>
</div>
<!-- 模型上传模态框 -->
<div id="arpv-upload-modal" class="arpv-modal" style="display:none;">
<div class="arpv-modal-content">
<span class="arpv-close-modal">×</span>
<h2>上传3D模型</h2>
<form id="arpv-upload-form">
<div class="arpv-form-group">
<label for="arpv-product-select">关联产品</label>
<select id="arpv-product-select" required>
<option value="">选择产品...</option>
<?php
$products = get_posts(array(
'post_type' => 'product',
'posts_per_page' => -1,
'post_status' => 'publish'
));
foreach ($products as $product) {
echo '<option value="' . $product->ID . '">' . $product->post_title . '</option>';
}
?>
</select>
</div>
<div class="arpv-form-group">
<label for="arpv-model-name">模型名称</label>
<input type="text" id="arpv-model-name" required>
</div>
<div class="arpv-form-group">
<label for="arpv-model-file">模型文件</label>
<input type="file" id="arpv-model-file" accept=".glb,.gltf,.fbx,.obj" required>
<p class="description">支持GLB, GLTF, FBX, OBJ格式,建议使用GLB格式以获得最佳性能</p>
</div>
<div class="arpv-form-group">
<label for="arpv-model-scale">模型缩放比例</label>
<input type="number" id="arpv-model-scale" step="0.1" value="1.0" min="0.1" max="10">
</div>
<button type="submit" class="button button-primary">上传模型</button>
</form>
</div>
</div>
</div>
</div>
<?php
}
第三部分:WebAR核心功能实现
3.1 集成AR.js与Three.js框架
首先,我们需要在前端加载必要的AR和3D渲染库:
// 前端资源加载
public function enqueue_frontend_assets() {
// 只在需要AR功能的页面加载
if ($this->should_load_ar_assets()) {
// Three.js - 3D渲染引擎
wp_enqueue_script('three-js', 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js', array(), 'r128', true);
// AR.js - WebAR框架
wp_enqueue_script('ar-js', 'https://cdn.jsdelivr.net/npm/ar.js@latest/aframe/build/aframe-ar.min.js', array('three-js'), null, true);
// GLTF加载器
wp_enqueue_script('gltf-loader', ARPV_PLUGIN_URL . 'assets/js/loaders/GLTFLoader.js', array('three-js'), '1.0', true);
// 自定义AR控制器
wp_enqueue_script('arpv-ar-controller', ARPV_PLUGIN_URL . 'assets/js/ar-controller.js', array('three-js', 'ar-js', 'gltf-loader'), ARPV_VERSION, true);
// AR样式
wp_enqueue_style('arpv-ar-style', ARPV_PLUGIN_URL . 'assets/css/ar-style.css', array(), ARPV_VERSION);
// 传递数据到前端
wp_localize_script('arpv-ar-controller', 'arpv_ajax', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('arpv_nonce')
));
}
}
// 判断是否需要加载AR资源
private function should_load_ar_assets() {
// 检查是否在产品页面
if (is_product() || has_shortcode(get_post()->post_content, 'ar_product_viewer')) {
return true;
}
// 检查是否在支持AR的页面模板
$template = get_page_template_slug();
if ($template === 'template-ar-product.php') {
return true;
}
return false;
}
3.2 创建AR查看器组件
实现核心的AR查看器组件:
// assets/js/ar-controller.js
class ARProductViewer {
constructor(options) {
this.options = {
containerId: 'ar-viewer-container',
productId: 0,
modelUrl: '',
modelScale: 1.0,
...options
};
this.scene = null;
this.camera = null;
this.renderer = null;
this.controls = null;
this.model = null;
this.arToolkitSource = null;
this.arToolkitContext = null;
this.init();
}
init() {
this.createARScene();
this.loadProductModel();
this.setupEventListeners();
this.animate();
}
createARScene() {
// 创建场景
this.scene = new THREE.Scene();
// 创建相机
this.camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.01, 20);
// 创建渲染器
this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.outputEncoding = THREE.sRGBEncoding;
// 添加到容器
const container = document.getElementById(this.options.containerId);
if (container) {
container.appendChild(this.renderer.domElement);
}
// 添加光源
const ambientLight = new THREE.AmbientLight(0xffffff, 0.8);
this.scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(0, 10, 5);
this.scene.add(directionalLight);
// 初始化AR.js
this.initARToolkit();
}
initARToolkit() {
// 创建AR.js源
this.arToolkitSource = new THREEx.ArToolkitSource({
sourceType: 'webcam',
sourceWidth: 1280,
sourceHeight: 720,
displayWidth: window.innerWidth,
displayHeight: window.innerHeight
});
// 初始化源
this.arToolkitSource.init(() => {
// 调整渲染器大小
this.onResize();
});
// 创建AR.js上下文
this.arToolkitContext = new THREEx.ArToolkitContext({
cameraParametersUrl: ARPV_PLUGIN_URL + 'assets/data/camera_para.dat',
detectionMode: 'mono',
maxDetectionRate: 30,
canvasWidth: this.arToolkitSource.domElement.clientWidth,
canvasHeight: this.arToolkitSource.domElement.clientHeight
});
// 初始化上下文
this.arToolkitContext.init(() => {
// 相机投影矩阵将根据AR上下文更新
this.camera.projectionMatrix.copy(this.arToolkitContext.getProjectionMatrix());
});
// 创建AR标记
const markerRoot = new THREE.Group();
this.scene.add(markerRoot);
// 创建标记控制器
const markerControls = new THREEx.ArMarkerControls(this.arToolkitContext, markerRoot, {
type: 'pattern',
patternUrl: ARPV_PLUGIN_URL + 'assets/data/patt.hiro',
changeMatrixMode: 'cameraTransformMatrix'
});
// 将模型添加到标记根组
this.modelContainer = markerRoot;
}
async loadProductModel() {
if (!this.options.modelUrl) {
console.error('未提供模型URL');
return;
}
try {
const loader = new THREE.GLTFLoader();
loader.load(
this.options.modelUrl,
(gltf) => {
this.model = gltf.scene;
// 调整模型大小和位置
const box = new THREE.Box3().setFromObject(this.model);
const size = box.getSize(new THREE.Vector3());
const maxDim = Math.max(size.x, size.y, size.z);
const scale = this.options.modelScale / maxDim;
this.model.scale.set(scale, scale, scale);
this.model.position.set(0, 0, 0);
// 添加到场景
if (this.modelContainer) {
this.modelContainer.add(this.model);
} else {
this.scene.add(this.model);
}
// 触发模型加载完成事件
this.dispatchEvent('modelLoaded', { model: this.model });
console.log('模型加载成功');
},
(progress) => {
// 加载进度
const percent = (progress.loaded / progress.total * 100).toFixed(2);
this.dispatchEvent('modelLoading', { percent });
},
(error) => {
console.error('模型加载失败:', error);
this.dispatchEvent('modelError', { error });
}
);
} catch (error) {
console.error('加载模型时出错:', error);
}
3.3 实现模型交互控制
// 继续 assets/js/ar-controller.js
setupEventListeners() {
// 窗口大小调整
window.addEventListener('resize', () => this.onResize());
// 触摸/鼠标事件
this.setupInteractionEvents();
// 键盘控制
window.addEventListener('keydown', (e) => this.onKeyDown(e));
// 自定义事件监听
this.eventListeners = {};
}
setupInteractionEvents() {
const canvas = this.renderer.domElement;
let isDragging = false;
let previousMousePosition = { x: 0, y: 0 };
// 触摸事件
canvas.addEventListener('touchstart', (e) => {
e.preventDefault();
if (e.touches.length === 1) {
// 单指触摸 - 旋转
isDragging = true;
previousMousePosition = {
x: e.touches[0].clientX,
y: e.touches[0].clientY
};
} else if (e.touches.length === 2) {
// 双指触摸 - 缩放
this.startPinchDistance = this.getPinchDistance(e);
}
});
canvas.addEventListener('touchmove', (e) => {
e.preventDefault();
if (e.touches.length === 1 && isDragging && this.model) {
// 单指拖动 - 旋转模型
const currentMousePosition = {
x: e.touches[0].clientX,
y: e.touches[0].clientY
};
const delta = {
x: currentMousePosition.x - previousMousePosition.x,
y: currentMousePosition.y - previousMousePosition.y
};
// 根据拖动距离旋转模型
this.rotateModel(delta.x * 0.01, delta.y * 0.01);
previousMousePosition = currentMousePosition;
} else if (e.touches.length === 2 && this.startPinchDistance && this.model) {
// 双指捏合 - 缩放模型
const currentPinchDistance = this.getPinchDistance(e);
const scaleFactor = currentPinchDistance / this.startPinchDistance;
this.scaleModel(scaleFactor);
this.startPinchDistance = currentPinchDistance;
}
});
canvas.addEventListener('touchend', (e) => {
isDragging = false;
this.startPinchDistance = null;
});
// 鼠标事件(桌面设备)
canvas.addEventListener('mousedown', (e) => {
if (e.button === 0) { // 左键
isDragging = true;
previousMousePosition = { x: e.clientX, y: e.clientY };
}
});
canvas.addEventListener('mousemove', (e) => {
if (isDragging && this.model) {
const currentMousePosition = { x: e.clientX, y: e.clientY };
const delta = {
x: currentMousePosition.x - previousMousePosition.x,
y: currentMousePosition.y - previousMousePosition.y
};
this.rotateModel(delta.x * 0.01, delta.y * 0.01);
previousMousePosition = currentMousePosition;
}
});
canvas.addEventListener('mouseup', () => {
isDragging = false;
});
// 鼠标滚轮缩放
canvas.addEventListener('wheel', (e) => {
e.preventDefault();
if (this.model) {
const scaleFactor = e.deltaY > 0 ? 0.9 : 1.1;
this.scaleModel(scaleFactor);
}
});
}
getPinchDistance(e) {
const dx = e.touches[0].clientX - e.touches[1].clientX;
const dy = e.touches[0].clientY - e.touches[1].clientY;
return Math.sqrt(dx * dx + dy * dy);
}
rotateModel(deltaX, deltaY) {
if (!this.model) return;
// 限制旋转角度
this.model.rotation.y += deltaX;
this.model.rotation.x = Math.max(-Math.PI/2, Math.min(Math.PI/2, this.model.rotation.x + deltaY));
}
scaleModel(factor) {
if (!this.model) return;
// 限制缩放范围
const currentScale = this.model.scale.x;
const newScale = Math.max(0.1, Math.min(5, currentScale * factor));
this.model.scale.set(newScale, newScale, newScale);
}
onKeyDown(e) {
if (!this.model) return;
switch(e.key) {
case 'r': // 重置模型位置和旋转
this.model.rotation.set(0, 0, 0);
this.model.scale.set(1, 1, 1);
break;
case '+': // 放大
this.scaleModel(1.1);
break;
case '-': // 缩小
this.scaleModel(0.9);
break;
case ' ': // 空格键 - 切换AR模式
this.toggleARMode();
break;
}
}
toggleARMode() {
// 切换AR模式和普通3D查看模式
this.isARMode = !this.isARMode;
if (this.isARMode) {
this.enterARMode();
} else {
this.exitARMode();
}
}
enterARMode() {
// 启动摄像头
this.arToolkitSource.init(() => {
this.arToolkitContext.arController.play();
});
this.dispatchEvent('arModeEntered');
}
exitARMode() {
// 停止摄像头
this.arToolkitContext.arController.stop();
this.dispatchEvent('arModeExited');
}
onResize() {
if (this.arToolkitSource) {
this.arToolkitSource.onResizeElement();
this.arToolkitSource.copyElementSizeTo(this.renderer.domElement);
}
if (this.camera) {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
}
this.renderer.setSize(window.innerWidth, window.innerHeight);
}
animate() {
requestAnimationFrame(() => this.animate());
// 更新AR上下文
if (this.arToolkitSource && this.arToolkitSource.ready) {
this.arToolkitContext.update(this.arToolkitSource.domElement);
}
// 渲染场景
this.renderer.render(this.scene, this.camera);
}
// 事件系统
addEventListener(event, callback) {
if (!this.eventListeners[event]) {
this.eventListeners[event] = [];
}
this.eventListeners[event].push(callback);
}
removeEventListener(event, callback) {
if (this.eventListeners[event]) {
const index = this.eventListeners[event].indexOf(callback);
if (index > -1) {
this.eventListeners[event].splice(index, 1);
}
}
}
dispatchEvent(event, data) {
if (this.eventListeners[event]) {
this.eventListeners[event].forEach(callback => {
callback(data);
});
}
}
// 销毁清理
destroy() {
window.removeEventListener('resize', this.onResize);
if (this.model && this.scene) {
this.scene.remove(this.model);
}
if (this.renderer) {
this.renderer.dispose();
this.renderer.forceContextLoss();
}
if (this.arToolkitContext) {
this.arToolkitContext.arController.stop();
}
}
}
// 全局访问
window.ARProductViewer = ARProductViewer;
3.4 创建产品页面集成短代码
// 在插件主类中添加短代码处理
public function ar_product_viewer_shortcode($atts) {
$atts = shortcode_atts(array(
'product_id' => 0,
'width' => '100%',
'height' => '500px',
'mode' => 'both' // '3d', 'ar', 'both'
), $atts, 'ar_product_viewer');
// 获取产品信息
$product_id = $atts['product_id'] ?: get_the_ID();
$model_data = $this->get_product_model_data($product_id);
if (!$model_data) {
return '<p class="arpv-error">该产品暂无AR模型</p>';
}
// 生成唯一ID
$viewer_id = 'arpv-' . uniqid();
ob_start();
?>
<div class="arpv-product-viewer-container">
<div id="<?php echo esc_attr($viewer_id); ?>"
class="arpv-viewer"
style="width: <?php echo esc_attr($atts['width']); ?>;
height: <?php echo esc_attr($atts['height']); ?>;">
</div>
<div class="arpv-controls">
<div class="arpv-control-group">
<button class="arpv-btn arpv-btn-rotate" title="旋转">
<span class="dashicons dashicons-image-rotate"></span>
</button>
<button class="arpv-btn arpv-btn-zoom-in" title="放大">
<span class="dashicons dashicons-plus"></span>
</button>
<button class="arpv-btn arpv-btn-zoom-out" title="缩小">
<span class="dashicons dashicons-minus"></span>
</button>
<button class="arpv-btn arpv-btn-reset" title="重置">
<span class="dashicons dashicons-image-rotate"></span>
</button>
</div>
<?php if ($atts['mode'] !== '3d') : ?>
<div class="arpv-control-group">
<button class="arpv-btn arpv-btn-ar arpv-btn-primary" title="AR模式">
<span class="dashicons dashicons-camera"></span>
<span>在您的空间中查看</span>
</button>
</div>
<?php endif; ?>
<div class="arpv-control-group arpv-instructions">
<p class="arpv-hint">
<span class="dashicons dashicons-info"></span>
提示:使用鼠标拖动旋转,滚轮缩放,或点击AR按钮在真实环境中查看
</p>
</div>
</div>
<div class="arpv-ar-overlay" style="display: none;">
<div class="arpv-ar-header">
<button class="arpv-btn arpv-btn-close-ar">返回</button>
<h3>AR模式</h3>
<p>将相机对准平面表面,等待模型出现</p>
</div>
<div class="arpv-ar-hint">
<p>移动设备:单指旋转模型,双指缩放</p>
</div>
</div>
</div>
<script type="text/javascript">
jQuery(document).ready(function($) {
// 初始化AR查看器
const viewer = new ARProductViewer({
containerId: '<?php echo esc_js($viewer_id); ?>',
productId: <?php echo intval($product_id); ?>,
modelUrl: '<?php echo esc_js($model_data['url']); ?>',
modelScale: <?php echo floatval($model_data['scale']); ?>
});
// 绑定控制按钮
$('.arpv-btn-rotate').on('click', function() {
// 自动旋转动画
viewer.startAutoRotate();
});
$('.arpv-btn-zoom-in').on('click', function() {
viewer.scaleModel(1.2);
});
$('.arpv-btn-zoom-out').on('click', function() {
viewer.scaleModel(0.8);
});
$('.arpv-btn-reset').on('click', function() {
viewer.resetModel();
});
$('.arpv-btn-ar').on('click', function() {
$('.arpv-ar-overlay').show();
viewer.enterARMode();
});
$('.arpv-btn-close-ar').on('click', function() {
$('.arpv-ar-overlay').hide();
viewer.exitARMode();
});
// 处理模型加载事件
viewer.addEventListener('modelLoaded', function(data) {
console.log('模型加载完成', data);
$('.arpv-hint').fadeOut();
});
viewer.addEventListener('modelLoading', function(data) {
console.log('模型加载进度:', data.percent + '%');
});
});
</script>
<?php
return ob_get_clean();
}
private function get_product_model_data($product_id) {
global $wpdb;
$table_name = $wpdb->prefix . 'arpv_models';
$model = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $table_name WHERE product_id = %d ORDER BY id DESC LIMIT 1",
$product_id
));
if ($model) {
return array(
'url' => $model->model_file_url,
'scale' => $model->scale_x,
'name' => $model->model_name
);
}
return false;
}
第四部分:高级功能与优化
4.1 多模型场景与产品搭配
// 添加多模型支持
public function add_scene_builder_meta_box() {
add_meta_box(
'arpv_scene_builder',
'AR场景构建器',
array($this, 'render_scene_builder_meta_box'),
'product',
'normal',
'high'
);
}
public function render_scene_builder_meta_box($post) {
wp_nonce_field('arpv_scene_builder', 'arpv_scene_builder_nonce');
$scene_data = get_post_meta($post->ID, '_arpv_scene_data', true);
$scene_data = $scene_data ? json_decode($scene_data, true) : array();
?>
<div class="arpv-scene-builder">
<div class="arpv-scene-controls">
<button type="button" class="button arpv-add-to-scene">添加产品到场景</button>
<button type="button" class="button arpv-save-scene">保存场景</button>
<button type="button" class="button arpv-reset-scene">重置场景</button>
</div>
<div class="arpv-scene-preview">
<div id="arpv-scene-viewer" style="width: 100%; height: 400px; background: #f5f5f5;">
<!-- 3D场景预览 -->
</div>
</div>
<div class="arpv-scene-items">
<h3>场景中的产品</h3>
<ul id="arpv-scene-list">
<?php if (!empty($scene_data['items'])) : ?>
<?php foreach ($scene_data['items'] as $item) : ?>
<li data-product-id="<?php echo esc_attr($item['product_id']); ?>">
<span class="arpv-item-name"><?php echo esc_html($item['name']); ?></span>
<button type="button" class="button arpv-remove-item">移除</button>
</li>
<?php endforeach; ?>
<?php endif; ?>
</ul>
</div>
<input type="hidden" id="arpv-scene-data" name="arpv_scene_data"
value="<?php echo esc_attr(json_encode($scene_data)); ?>">
</div>
<script type="text/javascript">
jQuery(document).ready(function($) {
let sceneViewer = null;
let sceneItems = <?php echo $scene_data ? json_encode($scene_data['items']) : '[]'; ?>;
// 初始化场景查看器
function initSceneViewer() {
sceneViewer = new ARSceneViewer({
containerId: 'arpv-scene-viewer',
items: sceneItems
});
}
// 添加产品到场景
$('.arpv-add-to-scene').on('click', function() {
// 打开产品选择模态框
$('#arpv-product-selector').show();
});
// 保存场景
$('.arpv-save-scene').on('click', function() {
const sceneData = {
items: sceneItems,
camera_position: sceneViewer ? sceneViewer.getCameraPosition() : null,
lighting: sceneViewer ? sceneViewer.getLightingSettings() : null
};
$('#arpv-scene-data').val(JSON.stringify(sceneData));
alert('场景已保存');
});
// 初始化
initSceneViewer();
});
</script>
<?php
}
4.2 性能优化与缓存策略
// 实现模型缓存和CDN集成
class ARPV_Cache_Manager {
private static $instance = null;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public function get_model_url($model_id, $use_cache = true) {
$cache_key = 'arpv_model_' . $model_id;
if ($use_cache) {
$cached_url = get_transient($cache_key);
if ($cached_url !== false) {
return $cached_url;
}
}
// 从数据库获取模型信息
global $wpdb;
$table_name = $wpdb->prefix . 'arpv_models';
$model = $wpdb->get_row($wpdb->prepare(
