文章目录[隐藏]
WordPress集成教程:连接酒店预订API实现房源查询与在线预订功能
引言:WordPress作为多功能开发平台的潜力
在当今数字化时代,酒店和住宿行业正经历着前所未有的转型。随着在线预订成为主流,拥有一个功能齐全、用户友好的网站对于酒店经营者至关重要。WordPress作为全球最受欢迎的内容管理系统,早已超越了简单的博客平台定位,通过其强大的可扩展性,可以转变为功能丰富的业务管理工具。
本教程将深入探讨如何通过WordPress代码二次开发,连接酒店预订API,实现专业的房源查询与在线预订功能。我们将从基础概念讲起,逐步深入到实际代码实现,最终打造一个完整的酒店预订系统。无论您是WordPress开发者、酒店经营者还是对网站集成感兴趣的技术爱好者,本教程都将为您提供实用的指导和解决方案。
第一部分:准备工作与环境搭建
1.1 理解酒店预订API的基本原理
酒店预订API(应用程序编程接口)是连接您的网站与酒店库存管理系统之间的桥梁。它允许您的WordPress网站实时访问房型信息、价格、可用性,并处理预订请求。常见的酒店API提供商包括Booking.com、Expedia、Hotelbeds等,也有许多专门为中小型酒店设计的API服务。
API通常通过RESTful架构或SOAP协议工作,使用JSON或XML格式传输数据。在开始集成前,您需要:
- 注册并获取API密钥和访问令牌
- 了解API的端点(Endpoints)、请求方法和参数
- 熟悉API的响应数据结构和错误处理机制
1.2 WordPress开发环境配置
为了顺利进行二次开发,您需要搭建合适的开发环境:
- 本地开发环境:使用XAMPP、MAMP或Local by Flywheel搭建本地WordPress环境
- 代码编辑器:推荐使用VS Code、PHPStorm或Sublime Text
-
必备插件:
- Advanced Custom Fields(用于自定义字段管理)
- Custom Post Type UI(创建自定义文章类型)
- Query Monitor(调试数据库查询和API请求)
-
启用WordPress调试模式:在wp-config.php中添加以下代码:
define('WP_DEBUG', true); define('WP_DEBUG_LOG', true); define('WP_DEBUG_DISPLAY', false);
1.3 创建自定义文章类型管理房源
在WordPress中,我们可以使用自定义文章类型(Custom Post Type)来管理酒店房源:
// 在主题的functions.php文件中添加以下代码
function register_hotel_room_post_type() {
$labels = array(
'name' => '酒店房源',
'singular_name' => '房源',
'menu_name' => '酒店管理',
'name_admin_bar' => '房源',
'add_new' => '添加新房源',
'add_new_item' => '添加新房源',
'new_item' => '新房源',
'edit_item' => '编辑房源',
'view_item' => '查看房源',
'all_items' => '所有房源',
'search_items' => '搜索房源',
'parent_item_colon' => '父房源:',
'not_found' => '未找到房源',
'not_found_in_trash' => '回收站中未找到房源'
);
$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'query_var' => true,
'rewrite' => array('slug' => 'hotel-room'),
'capability_type' => 'post',
'has_archive' => true,
'hierarchical' => false,
'menu_position' => 5,
'menu_icon' => 'dashicons-building',
'supports' => array('title', 'editor', 'thumbnail', 'excerpt')
);
register_post_type('hotel_room', $args);
}
add_action('init', 'register_hotel_room_post_type');
第二部分:酒店预订API集成核心实现
2.1 API连接类设计与实现
创建一个专门的类来处理与酒店预订API的通信:
class Hotel_API_Connector {
private $api_key;
private $api_secret;
private $base_url;
private $access_token;
private $token_expiry;
public function __construct($api_key, $api_secret, $base_url) {
$this->api_key = $api_key;
$this->api_secret = $api_secret;
$this->base_url = $base_url;
$this->access_token = $this->get_stored_token();
}
// 获取访问令牌
private function authenticate() {
$response = wp_remote_post($this->base_url . '/auth', array(
'body' => json_encode(array(
'api_key' => $this->api_key,
'api_secret' => $this->api_secret
)),
'headers' => array('Content-Type' => 'application/json'),
'timeout' => 30
));
if (is_wp_error($response)) {
error_log('酒店API认证失败: ' . $response->get_error_message());
return false;
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if (isset($data['access_token'])) {
$this->access_token = $data['access_token'];
$this->token_expiry = time() + $data['expires_in'];
// 存储令牌到数据库
update_option('hotel_api_token', array(
'token' => $this->access_token,
'expiry' => $this->token_expiry
));
return true;
}
return false;
}
// 获取存储的令牌
private function get_stored_token() {
$token_data = get_option('hotel_api_token', array());
if (!empty($token_data) && isset($token_data['expiry']) && $token_data['expiry'] > time()) {
return $token_data['token'];
}
return null;
}
// 发送API请求
public function make_request($endpoint, $method = 'GET', $params = array()) {
// 检查令牌有效性
if (!$this->access_token || $this->token_expiry <= time()) {
if (!$this->authenticate()) {
return new WP_Error('auth_failed', 'API认证失败');
}
}
$url = $this->base_url . $endpoint;
$args = array(
'method' => $method,
'headers' => array(
'Authorization' => 'Bearer ' . $this->access_token,
'Content-Type' => 'application/json'
),
'timeout' => 30
);
if (!empty($params)) {
if ($method === 'GET') {
$url = add_query_arg($params, $url);
} else {
$args['body'] = json_encode($params);
}
}
$response = wp_remote_request($url, $args);
if (is_wp_error($response)) {
error_log('酒店API请求失败: ' . $response->get_error_message());
return $response;
}
$response_code = wp_remote_retrieve_response_code($response);
$response_body = wp_remote_retrieve_body($response);
if ($response_code >= 400) {
error_log('酒店API错误响应: ' . $response_body);
return new WP_Error('api_error', 'API返回错误: ' . $response_code, $response_body);
}
return json_decode($response_body, true);
}
// 搜索可用房源
public function search_rooms($check_in, $check_out, $guests = 2, $rooms = 1) {
$endpoint = '/api/v1/rooms/search';
$params = array(
'check_in' => $check_in,
'check_out' => $check_out,
'guests' => $guests,
'rooms' => $rooms
);
return $this->make_request($endpoint, 'GET', $params);
}
// 获取房源详情
public function get_room_details($room_id) {
$endpoint = '/api/v1/rooms/' . $room_id;
return $this->make_request($endpoint);
}
// 创建预订
public function create_booking($room_id, $check_in, $check_out, $guest_info, $payment_info) {
$endpoint = '/api/v1/bookings';
$params = array(
'room_id' => $room_id,
'check_in' => $check_in,
'check_out' => $check_out,
'guest_info' => $guest_info,
'payment_info' => $payment_info
);
return $this->make_request($endpoint, 'POST', $params);
}
// 取消预订
public function cancel_booking($booking_id) {
$endpoint = '/api/v1/bookings/' . $booking_id . '/cancel';
return $this->make_request($endpoint, 'POST');
}
}
2.2 房源数据同步机制
为了确保WordPress中的房源信息与API数据同步,我们需要建立定期同步机制:
class Hotel_Room_Sync {
private $api_connector;
public function __construct($api_connector) {
$this->api_connector = $api_connector;
$this->init_hooks();
}
private function init_hooks() {
// 每天凌晨同步房源数据
if (!wp_next_scheduled('daily_hotel_room_sync')) {
wp_schedule_event(strtotime('02:00:00'), 'daily', 'daily_hotel_room_sync');
}
add_action('daily_hotel_room_sync', array($this, 'sync_all_rooms'));
// 手动同步触发器
add_action('admin_post_sync_hotel_rooms', array($this, 'handle_manual_sync'));
}
// 同步所有房源
public function sync_all_rooms() {
// 获取API中的所有房源
$api_rooms = $this->api_connector->make_request('/api/v1/rooms');
if (is_wp_error($api_rooms)) {
error_log('同步房源失败: ' . $api_rooms->get_error_message());
return false;
}
$synced_count = 0;
$updated_count = 0;
foreach ($api_rooms as $api_room) {
$room_id = $this->sync_single_room($api_room);
if ($room_id) {
if (get_post_meta($room_id, '_last_api_sync', true) == $api_room['updated_at']) {
$synced_count++;
} else {
$updated_count++;
}
}
}
// 记录同步结果
update_option('last_room_sync', array(
'time' => current_time('mysql'),
'synced' => $synced_count,
'updated' => $updated_count,
'total' => count($api_rooms)
));
return true;
}
// 同步单个房源
private function sync_single_room($api_room) {
// 检查是否已存在
$existing_posts = get_posts(array(
'post_type' => 'hotel_room',
'meta_key' => '_api_room_id',
'meta_value' => $api_room['id'],
'posts_per_page' => 1
));
$post_data = array(
'post_title' => $api_room['name'],
'post_content' => $api_room['description'],
'post_type' => 'hotel_room',
'post_status' => 'publish'
);
if (!empty($existing_posts)) {
$post_data['ID'] = $existing_posts[0]->ID;
$post_id = wp_update_post($post_data);
} else {
$post_id = wp_insert_post($post_data);
}
if (is_wp_error($post_id) || $post_id == 0) {
error_log('创建/更新房源失败: ' . print_r($post_id, true));
return false;
}
// 更新自定义字段
update_post_meta($post_id, '_api_room_id', $api_room['id']);
update_post_meta($post_id, '_room_type', $api_room['type']);
update_post_meta($post_id, '_max_guests', $api_room['max_guests']);
update_post_meta($post_id, '_base_price', $api_room['base_price']);
update_post_meta($post_id, '_amenities', $api_room['amenities']);
update_post_meta($post_id, '_last_api_sync', $api_room['updated_at']);
// 处理房源图片
if (!empty($api_room['images'])) {
$this->sync_room_images($post_id, $api_room['images']);
}
return $post_id;
}
// 同步房源图片
private function sync_room_images($post_id, $images) {
$attachment_ids = array();
foreach ($images as $index => $image_url) {
// 下载并设置特色图片
$attachment_id = $this->upload_image_from_url($image_url, $post_id);
if ($attachment_id && $index === 0) {
set_post_thumbnail($post_id, $attachment_id);
}
if ($attachment_id) {
$attachment_ids[] = $attachment_id;
}
}
// 保存到图库
if (!empty($attachment_ids)) {
update_post_meta($post_id, '_room_gallery', $attachment_ids);
}
}
// 从URL上传图片
private function upload_image_from_url($image_url, $post_id) {
require_once(ABSPATH . 'wp-admin/includes/media.php');
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/image.php');
// 检查是否已存在相同图片
$existing_attachment = $this->get_attachment_by_url($image_url);
if ($existing_attachment) {
return $existing_attachment;
}
// 下载图片
$tmp = download_url($image_url);
if (is_wp_error($tmp)) {
error_log('下载图片失败: ' . $tmp->get_error_message());
return false;
}
// 准备文件数据
$file_array = array(
'name' => basename($image_url),
'tmp_name' => $tmp
);
// 上传到媒体库
$attachment_id = media_handle_sideload($file_array, $post_id);
if (is_wp_error($attachment_id)) {
@unlink($file_array['tmp_name']);
error_log('上传图片失败: ' . $attachment_id->get_error_message());
return false;
}
// 保存原始URL以便后续识别
update_post_meta($attachment_id, '_original_image_url', $image_url);
return $attachment_id;
}
// 根据URL获取已存在的附件
private function get_attachment_by_url($url) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_original_image_url' AND meta_value = %s",
$url
);
$attachment_id = $wpdb->get_var($query);
return $attachment_id ? intval($attachment_id) : false;
}
}
第三部分:前端功能实现与用户界面
3.1 房源搜索与筛选功能
创建一个短代码来显示房源搜索表单:
// 搜索表单短代码
function hotel_search_form_shortcode($atts) {
ob_start();
?>
<div class="hotel-search-form">
<form id="hotel-search-form" method="GET" action="<?php echo esc_url(get_permalink(get_option('hotel_search_results_page'))); ?>">
<div class="search-row">
<div class="form-group">
<label for="check-in">入住日期</label>
<input type="date" id="check-in" name="check_in"
value="<?php echo isset($_GET['check_in']) ? esc_attr($_GET['check_in']) : date('Y-m-d'); ?>"
min="<?php echo date('Y-m-d'); ?>" required>
</div>
<div class="form-group">
<label for="check-out">退房日期</label>
<input type="date" id="check-out" name="check_out"
value="<?php echo isset($_GET['check_out']) ? esc_attr($_GET['check_out']) : date('Y-m-d', strtotime('+1 day')); ?>"
min="<?php echo date('Y-m-d', strtotime('+1 day')); ?>" required>
</div>
<div class="form-group">
<label for="guests">入住人数</label>
<select id="guests" name="guests">
<?php for ($i = 1; $i <= 10; $i++): ?>
<option value="<?php echo $i; ?>" <?php selected(isset($_GET['guests']) ? $_GET['guests'] : 2, $i); ?>>
<?php echo $i; ?> 人
</option>
<?php endfor; ?>
</select>
</div>
<div class="form-group">
<label for="rooms">房间数</label>
<select id="rooms" name="rooms">
<?php for ($i = 1; $i <= 5; $i++): ?>
<option value="<?php echo $i; ?>" <?php selected(isset($_GET['rooms']) ? $_GET['rooms'] : 1, $i); ?>>
<?php echo $i; ?> 间
</option>
<?php endfor; ?>
</select>
</div>
</div>
<div class="search-row">
<div class="form-group">
<label for="room-type">房型</label>
<select id="room-type" name="room_type">
<option value="">所有房型</option>
<option value="single" <?php selected(isset($_GET['room_type']) ? $_GET['room_type'] : '', 'single'); ?>>单人间</option>
<option value="double" <?php selected(isset($_GET['room_type']) ? $_GET['room_type'] : '', 'double'); ?>>双人间</option>
<option value="suite" <?php selected(isset($_GET['room_type']) ? $_GET['room_type'] : '', 'suite'); ?>>套房</option>
<option value="family" <?php selected(isset($_GET['room_type']) ? $_GET['room_type'] : '', 'family'); ?>>家庭房</option>
</select>
</div>
<div class="form-group">
<label for="price-min">价格范围</label>
<div class="price-range">
<input type="number" id="price-min" name="price_min"
placeholder="最低价" value="<?php echo isset($_GET['price_min']) ? esc_attr($_GET['price_min']) : ''; ?>">
<span>至</span>
<input type="number" id="price-max" name="price_max"
placeholder="最高价" value="<?php echo isset($_GET['price_max']) ? esc_attr($_GET['price_max']) : ''; ?>">
</div>
</div>
<div class="form-group">
<label for="amenities">设施</label>
<select id="amenities" name="amenities[]" multiple class="multi-select">
<option value="wifi" <?php selected(in_array('wifi', isset($_GET['amenities']) ? (array)$_GET['amenities'] : array()), true); ?>>WiFi</option>
<option value="breakfast" <?php selected(in_array('breakfast', isset($_GET['amenities']) ? (array)$_GET['amenities'] : array()), true); ?>>早餐</option>
<option value="parking" <?php selected(in_array('parking', isset($_GET['amenities']) ? (array)$_GET['amenities'] : array()), true); ?>>停车</option>
<option value="pool" <?php selected(in_array('pool', isset($_GET['amenities']) ? (array)$_GET['amenities'] : array()), true); ?>>泳池</option>
<option value="gym" <?php selected(in_array('gym', isset($_GET['amenities']) ? (array)$_GET['amenities'] : array()), true); ?>>健身房</option>
</select>
</div>
</div>
<div class="form-submit">
<button type="submit" class="search-button">搜索房源</button>
<button type="button" class="reset-button" onclick="resetSearchForm()">重置条件</button>
</div>
</form>
</div>
<script>
function resetSearchForm() {
document.getElementById('hotel-search-form').reset();
// 重置日期为默认值
document.getElementById('check-in').value = '<?php echo date("Y-m-d"); ?>';
document.getElementById('check-out').value = '<?php echo date("Y-m-d", strtotime("+1 day")); ?>';
}
// 日期验证
document.getElementById('check-in').addEventListener('change', function() {
var checkIn = new Date(this.value);
var checkOut = new Date(document.getElementById('check-out').value);
if (checkIn >= checkOut) {
var nextDay = new Date(checkIn);
nextDay.setDate(nextDay.getDate() + 1);
document.getElementById('check-out').value = nextDay.toISOString().split('T')[0];
}
// 设置退房日期的最小值
document.getElementById('check-out').min = this.value;
});
</script>
<style>
.hotel-search-form {
background: #f8f9fa;
padding: 25px;
border-radius: 10px;
box-shadow: 0 2px 15px rgba(0,0,0,0.1);
margin: 20px 0;
}
.search-row {
display: flex;
flex-wrap: wrap;
gap: 20px;
margin-bottom: 20px;
}
.form-group {
flex: 1;
min-width: 200px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #333;
}
.form-group input,
.form-group select {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 14px;
}
.price-range {
display: flex;
align-items: center;
gap: 10px;
}
.price-range input {
flex: 1;
}
.multi-select {
height: 100px;
}
.form-submit {
text-align: center;
margin-top: 20px;
}
.search-button,
.reset-button {
padding: 12px 30px;
border: none;
border-radius: 5px;
font-size: 16px;
cursor: pointer;
transition: all 0.3s ease;
}
.search-button {
background: #007cba;
color: white;
margin-right: 10px;
}
.search-button:hover {
background: #005a87;
}
.reset-button {
background: #6c757d;
color: white;
}
.reset-button:hover {
background: #545b62;
}
@media (max-width: 768px) {
.search-row {
flex-direction: column;
}
.form-group {
min-width: 100%;
}
}
</style>
<?php
return ob_get_clean();
}
add_shortcode('hotel_search', 'hotel_search_form_shortcode');
3.2 房源搜索结果展示
创建搜索结果页面模板:
// 搜索结果处理函数
function display_hotel_search_results() {
if (!isset($_GET['check_in']) || !isset($_GET['check_out'])) {
return '<div class="hotel-search-message">请先选择入住和退房日期</div>';
}
$check_in = sanitize_text_field($_GET['check_in']);
$check_out = sanitize_text_field($_GET['check_out']);
$guests = isset($_GET['guests']) ? intval($_GET['guests']) : 2;
$rooms = isset($_GET['rooms']) ? intval($_GET['rooms']) : 1;
// 获取API连接实例
$api_connector = new Hotel_API_Connector(
get_option('hotel_api_key'),
get_option('hotel_api_secret'),
get_option('hotel_api_base_url')
);
// 搜索可用房源
$search_params = array(
'check_in' => $check_in,
'check_out' => $check_out,
'guests' => $guests,
'rooms' => $rooms
);
// 添加筛选条件
if (!empty($_GET['room_type'])) {
$search_params['room_type'] = sanitize_text_field($_GET['room_type']);
}
if (!empty($_GET['price_min'])) {
$search_params['price_min'] = floatval($_GET['price_min']);
}
if (!empty($_GET['price_max'])) {
$search_params['price_max'] = floatval($_GET['price_max']);
}
if (!empty($_GET['amenities'])) {
$search_params['amenities'] = array_map('sanitize_text_field', (array)$_GET['amenities']);
}
$available_rooms = $api_connector->search_rooms($check_in, $check_out, $guests, $rooms);
if (is_wp_error($available_rooms)) {
return '<div class="hotel-search-error">搜索失败:' . esc_html($available_rooms->get_error_message()) . '</div>';
}
if (empty($available_rooms)) {
return '<div class="hotel-search-empty">未找到符合条件的房源,请尝试调整搜索条件。</div>';
}
ob_start();
?>
<div class="hotel-search-results">
<div class="search-summary">
<h3>搜索结果</h3>
<p>入住:<?php echo date('Y年m月d日', strtotime($check_in)); ?> -
退房:<?php echo date('Y年m月d日', strtotime($check_out)); ?> |
共 <?php echo count($available_rooms); ?> 个房源可选</p>
</div>
<div class="results-controls">
<div class="sort-options">
<label>排序:</label>
<select id="sort-results" onchange="sortRooms(this.value)">
<option value="price_asc">价格从低到高</option>
<option value="price_desc">价格从高到低</option>
<option value="rating_desc">评分从高到低</option>
<option value="name_asc">名称A-Z</option>
</select>
</div>
<div class="view-options">
<button class="view-btn active" onclick="changeView('grid')" title="网格视图">
<span class="dashicons dashicons-grid-view"></span>
</button>
<button class="view-btn" onclick="changeView('list')" title="列表视图">
<span class="dashicons dashicons-list-view"></span>
</button>
</div>
</div>
<div class="rooms-container grid-view">
<?php foreach ($available_rooms as $room): ?>
<div class="room-card" data-price="<?php echo $room['price_per_night']; ?>"
data-rating="<?php echo $room['rating'] ?? 0; ?>"
data-name="<?php echo esc_attr($room['name']); ?>">
<div class="room-image">
<?php if (!empty($room['image'])): ?>
<img src="<?php echo esc_url($room['image']); ?>" alt="<?php echo esc_attr($room['name']); ?>">
<?php else: ?>
<div class="no-image">暂无图片</div>
<?php endif; ?>
<?php if (isset($room['discount']) && $room['discount'] > 0): ?>
<span class="discount-badge">-<?php echo $room['discount']; ?>%</span>
<?php endif; ?>
</div>
<div class="room-info">
<h3 class="room-title">
<a href="<?php echo get_permalink(); ?>?room_id=<?php echo $room['id']; ?>&check_in=<?php echo $check_in; ?>&check_out=<?php echo $check_out; ?>">
<?php echo esc_html($room['name']); ?>
</a>
</h3>
<div class="room-meta">
<span class="room-type"><?php echo esc_html($room['type']); ?></span>
<span class="room-guests">最多 <?php echo $room['max_guests']; ?> 人</span>
<span class="room-size"><?php echo $room['size'] ?? '--'; ?> ㎡</span>
</div>
<div class="room-amenities">
<?php if (!empty($room['amenities'])): ?>
<?php
$amenities_display = array_slice($room['amenities'], 0, 3);
foreach ($amenities_display as $amenity): ?>
<span class="amenity-tag"><?php echo esc_html($amenity); ?></span>
<?php endforeach; ?>
<?php if (count($room['amenities']) > 3): ?>
<span class="amenity-more">+<?php echo count($room['amenities']) - 3; ?> 更多</span>
<?php endif; ?>
<?php endif; ?>
</div>
<div class="room-rating">
<?php if (isset($room['rating'])): ?>
<div class="stars">
<?php
$full_stars = floor($room['rating']);
$half_star = ($room['rating'] - $full_stars) >= 0.5;
for ($i = 1; $i <= 5; $i++):
if ($i <= $full_stars): ?>
<span class="dashicons dashicons-star-filled"></span>
<?php elseif ($half_star && $i == $full_stars + 1): ?>
<span class="dashicons dashicons-star-half"></span>
<?php else: ?>
<span class="dashicons dashicons-star-empty"></span>
<?php endif;
endfor; ?>
</div>
<span class="rating-score"><?php echo number_format($room['rating'], 1); ?></span>
<?php endif; ?>
</div>
<div class="room-price">
<div class="price-main">
<span class="currency">¥</span>
<span class="amount"><?php echo number_format($room['price_per_night'], 0); ?></span>
<span class="period">/晚</span>
</div>
<?php if (isset($room['original_price']) && $room['original_price'] > $room['price_per_night']): ?>
<div class="price-original">
¥<?php echo number_format($room['original_price'], 0); ?>
</div>
<?php endif; ?>
<div class="price-total">
总计:¥<?php echo number_format($room['total_price'], 0); ?>
</div>
</div>
<div class="room-actions">
<a href="<?php echo get_permalink(); ?>?room_id=<?php echo $room['id']; ?>&check_in=<?php echo $check_in; ?>&check_out=<?php echo $check_out; ?>&action=book"
class="book-button">
立即预订
</a>
<button class="view-details"
onclick="showRoomDetails('<?php echo $room['id']; ?>')">
查看详情
</button>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<!-- 分页 -->
<?php if (count($available_rooms) > 12): ?>
<div class="pagination">
<button class="page-btn prev" disabled>上一页</button>
<span class="page-numbers">1 / <?php echo ceil(count($available_rooms) / 12); ?></span>
<button class="page-btn next">下一页</button>
</div>
<?php endif; ?>
</div>
<!-- 房源详情模态框 -->
<div id="room-details-modal" class="modal">
<div class="modal-content">
<span class="close-modal">×</span>
<div id="room-details-content"></div>
</div>
</div>
<script>
// 排序功能
function sortRooms(sortBy) {
const container = document.querySelector('.rooms-container');
const rooms = Array.from(container.querySelectorAll('.room-card'));
rooms.sort((a, b) => {
let aValue, bValue;
switch(sortBy) {
case 'price_asc':
aValue = parseFloat(a.dataset.price);
bValue = parseFloat(b.dataset.price);
return aValue - bValue;
case 'price_desc':
aValue = parseFloat(a.dataset.price);
bValue = parseFloat(b.dataset.price);
return bValue - aValue;
case 'rating_desc':
aValue = parseFloat(a.dataset.rating);
bValue = parseFloat(b.dataset.rating);
return bValue - aValue;
case 'name_asc':
aValue = a.dataset.name.toLowerCase();
bValue = b.dataset.name.toLowerCase();
return aValue.localeCompare(bValue);
default:
return 0;
}
});
// 重新排列DOM元素
rooms.forEach(room => container.appendChild(room));
}
// 切换视图
function changeView(viewType) {
const container = document.querySelector('.rooms-container');
const buttons = document.querySelectorAll('.view-btn');
buttons.forEach(btn => btn.classList.remove('active'));
event.target.classList.add('active');
container.classList.remove('grid-view', 'list-view');
container.classList.add(viewType + '-view');
}
// 显示房源详情
function showRoomDetails(roomId) {
// 使用AJAX获取房源详情
fetch('<?php echo admin_url('admin-ajax.php'); ?>', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'action=get_room_details&room_id=' + roomId +
'&check_in=<?php echo $check_in; ?>' +
