文章目录[隐藏]
WordPress小批量定制插件支持AR预览功能的集成教程
一、AR预览功能概述与准备工作
增强现实(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 # 卸载脚本
二、创建插件主文件与基础配置
首先创建插件的主文件,这是插件的入口点:
<?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模型处理类实现
创建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预览组件开发
创建前端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按钮样式 /
ar-button {
transition: all 0.3s ease;
}
ar-button:hover {
transform: translateX(-50%) scale(1.05);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
}
ar-button:active {
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;
