文章目录[隐藏]
实操指南:实现心愿单与收藏夹接口的3个贴心设计
引言:为什么需要精心设计收藏功能?
在当今的电商和内容平台中,收藏夹与心愿单功能已成为用户留存和转化的重要工具。据统计,拥有完善收藏功能的电商平台,用户复购率平均提升23%,页面停留时间增加35%。对于WordPress开发者而言,实现这些功能不仅是技术挑战,更是提升用户体验的关键机会。
本文将从WordPress开发者的角度,深入探讨如何实现既实用又贴心的收藏功能。我们将聚焦三个核心设计:智能分类与标签系统、跨设备同步与分享机制、以及个性化推荐与提醒功能。每个设计都将附有详细的代码实现和最佳实践建议。
设计一:智能分类与标签系统
1.1 为什么需要智能分类?
传统的收藏夹往往只是一个简单的列表,当用户收藏的项目达到一定数量时,查找特定内容变得异常困难。智能分类系统通过自动或半自动的方式帮助用户组织收藏内容,显著提升用户体验。
1.2 数据库设计
首先,我们需要设计合理的数据库结构。在WordPress中,我们可以利用现有的数据表结构,添加必要的自定义表:
-- 创建心愿单主表
CREATE TABLE wp_wishlist (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
user_id BIGINT(20) UNSIGNED NOT NULL,
name VARCHAR(255) NOT NULL,
is_default TINYINT(1) DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY user_id (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 创建心愿单项目表
CREATE TABLE wp_wishlist_items (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
wishlist_id BIGINT(20) UNSIGNED NOT NULL,
post_id BIGINT(20) UNSIGNED NOT NULL,
quantity INT(11) DEFAULT 1,
notes TEXT,
added_at DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY wishlist_id (wishlist_id),
KEY post_id (post_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 创建标签表
CREATE TABLE wp_wishlist_tags (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
slug VARCHAR(100) NOT NULL,
user_id BIGINT(20) UNSIGNED NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY slug_user (slug, user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 创建项目-标签关联表
CREATE TABLE wp_wishlist_item_tags (
item_id BIGINT(20) UNSIGNED NOT NULL,
tag_id BIGINT(20) UNSIGNED NOT NULL,
PRIMARY KEY (item_id, tag_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
1.3 自动分类算法实现
我们可以基于内容分析和用户行为实现自动分类:
<?php
/**
* 智能分类器类
*/
class SmartWishlistClassifier {
/**
* 根据内容自动分配标签
*/
public function auto_tag_item($post_id, $user_id) {
$post = get_post($post_id);
$content = $post->post_title . ' ' . $post->post_content;
// 提取关键词
$keywords = $this->extract_keywords($content);
// 获取用户现有标签
$user_tags = $this->get_user_tags($user_id);
// 匹配最佳标签
$matched_tags = $this->match_tags($keywords, $user_tags);
// 如果没有匹配的标签,创建新标签
if (empty($matched_tags)) {
$primary_keyword = $this->get_primary_keyword($keywords);
$tag_id = $this->create_tag($primary_keyword, $user_id);
$matched_tags = [$tag_id];
}
return $matched_tags;
}
/**
* 从内容中提取关键词
*/
private function extract_keywords($content) {
// 移除HTML标签和特殊字符
$content = wp_strip_all_tags($content);
$content = preg_replace('/[^p{L}p{N}s]/u', '', $content);
// 分词处理(简化版,实际应使用更复杂的分词算法)
$words = explode(' ', strtolower($content));
// 移除停用词
$stop_words = $this->get_stop_words();
$words = array_diff($words, $stop_words);
// 统计词频
$word_freq = array_count_values($words);
// 按频率排序并返回前10个关键词
arsort($word_freq);
return array_slice(array_keys($word_freq), 0, 10);
}
/**
* 匹配现有标签
*/
private function match_tags($keywords, $user_tags) {
$matched = [];
foreach ($user_tags as $tag) {
$tag_name = strtolower($tag->name);
foreach ($keywords as $keyword) {
// 使用相似度算法(这里使用简单的字符串包含)
if (strpos($tag_name, $keyword) !== false ||
strpos($keyword, $tag_name) !== false) {
$matched[] = $tag->id;
break;
}
}
}
return array_unique($matched);
}
/**
* 获取停用词列表
*/
private function get_stop_words() {
return ['the', 'and', 'or', 'a', 'an', 'in', 'on', 'at', 'to', 'for', 'of', 'with'];
}
}
1.4 用户界面实现
在前端,我们需要提供直观的标签管理界面:
<?php
/**
* 心愿单标签管理界面
*/
function render_wishlist_tags_ui($user_id, $item_id = null) {
$tags = get_user_wishlist_tags($user_id);
$item_tags = $item_id ? get_item_tags($item_id) : [];
ob_start();
?>
<div class="wishlist-tags-container">
<h4>管理标签</h4>
<!-- 现有标签 -->
<div class="existing-tags">
<?php foreach ($tags as $tag): ?>
<label class="tag-checkbox">
<input type="checkbox"
name="wishlist_tags[]"
value="<?php echo esc_attr($tag->id); ?>"
<?php echo in_array($tag->id, $item_tags) ? 'checked' : ''; ?>>
<span class="tag-label"><?php echo esc_html($tag->name); ?></span>
</label>
<?php endforeach; ?>
</div>
<!-- 添加新标签 -->
<div class="add-tag-form">
<input type="text"
class="new-tag-input"
placeholder="添加新标签...">
<button type="button" class="add-tag-btn">添加</button>
</div>
<!-- 智能建议 -->
<div class="tag-suggestions">
<p>智能建议:</p>
<div class="suggested-tags">
<!-- 通过AJAX加载建议标签 -->
</div>
</div>
</div>
<script>
jQuery(document).ready(function($) {
// 添加新标签
$('.add-tag-btn').click(function() {
var tagName = $('.new-tag-input').val().trim();
if (tagName) {
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'add_wishlist_tag',
tag_name: tagName,
user_id: <?php echo $user_id; ?>,
nonce: '<?php echo wp_create_nonce("add_tag_nonce"); ?>'
},
success: function(response) {
if (response.success) {
location.reload();
}
}
});
}
});
// 标签自动完成
$('.new-tag-input').on('input', function() {
var query = $(this).val();
if (query.length > 2) {
$.get(ajaxurl, {
action: 'search_tags',
query: query,
user_id: <?php echo $user_id; ?>
}, function(suggestions) {
$('.suggested-tags').html(suggestions);
});
}
});
});
</script>
<?php
return ob_get_clean();
}
设计二:跨设备同步与分享机制
2.1 同步架构设计
跨设备同步是现代应用的基本要求。我们需要设计一个可靠的数据同步机制:
<?php
/**
* 同步管理器类
*/
class WishlistSyncManager {
private $user_id;
private $last_sync_time;
public function __construct($user_id) {
$this->user_id = $user_id;
$this->last_sync_time = get_user_meta($user_id, 'wishlist_last_sync', true);
}
/**
* 获取需要同步的更改
*/
public function get_changes_since($timestamp) {
global $wpdb;
$changes = [
'added' => [],
'removed' => [],
'modified' => []
];
// 查询新增的项目
$added_items = $wpdb->get_results($wpdb->prepare(
"SELECT wi.*, w.name as wishlist_name
FROM {$wpdb->prefix}wishlist_items wi
JOIN {$wpdb->prefix}wishlist w ON wi.wishlist_id = w.id
WHERE w.user_id = %d AND wi.added_at > %s
ORDER BY wi.added_at DESC",
$this->user_id, $timestamp
));
// 查询修改的项目(包括标签变更)
$modified_items = $wpdb->get_results($wpdb->prepare(
"SELECT wi.*,
GROUP_CONCAT(wt.name) as tags,
w.name as wishlist_name
FROM {$wpdb->prefix}wishlist_items wi
JOIN {$wpdb->prefix}wishlist w ON wi.wishlist_id = w.id
LEFT JOIN {$wpdb->prefix}wishlist_item_tags wit ON wi.id = wit.item_id
LEFT JOIN {$wpdb->prefix}wishlist_tags wt ON wit.tag_id = wt.id
WHERE w.user_id = %d AND wi.updated_at > %s
GROUP BY wi.id",
$this->user_id, $timestamp
));
// 转换数据结构
foreach ($added_items as $item) {
$changes['added'][] = $this->format_item($item);
}
foreach ($modified_items as $item) {
$changes['modified'][] = $this->format_item($item);
}
return $changes;
}
/**
* 处理来自客户端的同步请求
*/
public function process_sync($client_changes, $device_id) {
$results = [
'server_changes' => $this->get_changes_since($client_changes['last_sync']),
'client_changes_processed' => []
];
// 处理客户端的新增项目
if (!empty($client_changes['added'])) {
foreach ($client_changes['added'] as $item) {
$item_id = $this->add_item_from_client($item, $device_id);
if ($item_id) {
$results['client_changes_processed']['added'][] = $item_id;
}
}
}
// 处理客户端的删除请求
if (!empty($client_changes['removed'])) {
foreach ($client_changes['removed'] as $item_id) {
if ($this->remove_item($item_id, $device_id)) {
$results['client_changes_processed']['removed'][] = $item_id;
}
}
}
// 更新同步时间
$this->update_sync_time();
return $results;
}
/**
* 生成分享链接
*/
public function generate_share_link($wishlist_id, $options = []) {
$defaults = [
'expires' => '+30 days',
'password' => '',
'allow_edit' => false
];
$options = wp_parse_args($options, $defaults);
// 生成唯一令牌
$token = wp_generate_password(32, false);
// 存储分享信息
$share_data = [
'wishlist_id' => $wishlist_id,
'created_by' => $this->user_id,
'expires' => strtotime($options['expires']),
'password' => $options['password'],
'allow_edit' => $options['allow_edit']
];
set_transient("wishlist_share_{$token}", $share_data, DAY_IN_SECONDS * 30);
// 返回分享链接
return add_query_arg(['share_token' => $token], home_url('/wishlist/shared/'));
}
}
2.2 REST API 端点设计
为了实现跨平台同步,我们需要提供完善的REST API:
<?php
/**
* 注册心愿单REST API端点
*/
add_action('rest_api_init', function() {
// 获取用户心愿单
register_rest_route('wishlist/v1', '/wishlists', [
'methods' => 'GET',
'callback' => 'get_user_wishlists_api',
'permission_callback' => 'is_user_logged_in'
]);
// 同步数据
register_rest_route('wishlist/v1', '/sync', [
'methods' => 'POST',
'callback' => 'sync_wishlist_data',
'permission_callback' => 'is_user_logged_in'
]);
// 分享相关端点
register_rest_route('wishlist/v1', '/share', [
'methods' => 'POST',
'callback' => 'create_share_link',
'permission_callback' => 'is_user_logged_in'
]);
register_rest_route('wishlist/v1', '/shared/(?P<token>[a-zA-Z0-9]+)', [
'methods' => 'GET',
'callback' => 'get_shared_wishlist',
'permission_callback' => '__return_true'
]);
});
/**
* 同步API处理函数
*/
function sync_wishlist_data(WP_REST_Request $request) {
$user_id = get_current_user_id();
$sync_manager = new WishlistSyncManager($user_id);
$client_data = $request->get_json_params();
$device_id = sanitize_text_field($request->get_header('X-Device-ID'));
try {
$result = $sync_manager->process_sync($client_data, $device_id);
return new WP_REST_Response([
'success' => true,
'data' => $result,
'server_time' => current_time('mysql')
], 200);
} catch (Exception $e) {
return new WP_REST_Response([
'success' => false,
'message' => $e->getMessage()
], 500);
}
}
2.3 离线支持与冲突解决
<?php
/**
* 离线支持管理器
*/
class OfflineSupportManager {
/**
* 为客户端生成离线数据包
*/
public function generate_offline_package($user_id) {
global $wpdb;
// 获取用户所有心愿单数据
$wishlists = $wpdb->get_results($wpdb->prepare(
"SELECT w.*,
COUNT(wi.id) as item_count
FROM {$wpdb->prefix}wishlist w
LEFT JOIN {$wpdb->prefix}wishlist_items wi ON w.id = wi.wishlist_id
WHERE w.user_id = %d
GROUP BY w.id",
$user_id
));
$package = [
'wishlists' => [],
'last_updated' => current_time('mysql'),
'version' => '1.0'
];
foreach ($wishlists as $wishlist) {
$items = $this->get_wishlist_items($wishlist->id);
$package['wishlists'][] = [
'id' => $wishlist->id,
'name' => $wishlist->name,
'items' => $items,
'is_default' => (bool)$wishlist->is_default
];
}
return $package;
}
/**
* 解决数据冲突
*/
public function resolve_conflict($local_item, $server_item) {
$resolution_strategy = get_user_meta(
get_current_user_id(),
'wishlist_sync_strategy',
true
) ?: 'server_wins';
switch ($resolution_strategy) {
case 'server_wins':
return $server_item;
case 'client_wins':
return $local_item;
case 'merge':
return $this->merge_items($local_item, $server_item);
case 'newest_wins':
$local_time = strtotime($local_item['updated_at']);
$server_time = strtotime($server_item['updated_at']);
return $local_time > $server_time ? $local_item : $server_item;
}
}
/**
* 合并项目数据
*/
private function merge_items($item1, $item2) {
$merged = array_merge($item1, $item2);
// 合并标签(去重)
if (!empty($item1['tags']) && !empty($item2['tags'])) {
$merged['tags'] = array_unique(
array_merge(
(array)$item1['tags'],
(array)$item2['tags']
)
);
}
// 合并备注
if (!empty($item1['notes']) && !empty($item2['notes'])) {
if ($item1['notes'] !== $item2['notes']) {
$merged['notes'] = $item1['notes'] . "n---n" . $item2['notes'];
}
}
return $merged;
}
}
设计三:个性化推荐与智能提醒
3.1 推荐引擎设计
基于用户收藏行为提供个性化推荐:
<?php
/**
* 心愿单推荐引擎
*/
class WishlistRecommendationEngine {
private $user_id;
private $min_similarity_score = 0.3;
public function __construct($user_id) {
$this->user_id = $user_id;
}
/**
* 获取个性化推荐
*/
public function get_recommendations($limit = 10, $source = 'mixed') {
$recommendations = [];
// 基于用户收藏内容的协同过滤
if ($source === 'collaborative' || $source === 'mixed') {
$collaborative_recs = $this->get_collaborative_recommendations($limit);
$recommendations = array_merge($recommendations, $collaborative_recs);
}
// 基于内容相似度的推荐
if ($source === 'content' || $source === 'mixed') {
$content_recs = $this->get_content_based_recommendations($limit);
$recommendations = array_merge($recommendations, $content_recs);
}
// 基于标签的推荐
if ($source === 'tags' || $source === 'mixed') {
$tag_recs = $this->get_tag_based_recommendations($limit);
$recommendations = array_merge($recommendations, $tag_recs);
}
// 去重、排序并限制数量
$recommendations = $this->deduplicate_and_sort($recommendations, $limit);
return $recommendations;
}
/**
* 协同过滤推荐
*/
private function get_collaborative_recommendations($limit) {
global $wpdb;
// 获取与当前用户收藏相似的其他用户
$similar_users = $wpdb->get_results($wpdb->prepare(
"SELECT other.user_id,
COUNT(DISTINCT other.post_id) as common_items,
COUNT(DISTINCT other.user_id) as total_items
FROM {$wpdb->prefix}wishlist_items current
INNER JOIN {$wpdb->prefix}wishlist_items other
ON current.post_id = other.post_id
INNER JOIN {$wpdb->prefix}wishlist w1 ON current.wishlist_id = w1.id
INNER JOIN {$wpdb->prefix}wishlist w2 ON other.wishlist_id = w2.id
WHERE w1.user_id = %d
AND w2.user_id != %d
AND current.post_id IS NOT NULL
GROUP BY other.user_id
HAVING common_items >= 2
ORDER BY common_items DESC
LIMIT 20",
$this->user_id, $this->user_id
));
$recommendations = [];
foreach ($similar_users as $similar_user) {
// 计算相似度分数
$similarity_score = $this->calculate_similarity_score($similar_user);
if ($similarity_score >= $this->min_similarity_score) {
// 获取相似用户收藏但当前用户未收藏的内容
$user_recs = $wpdb->get_results($wpdb->prepare(
"SELECT DISTINCT p.ID, p.post_title,
'collaborative' as source_type,
%f as score
FROM {$wpdb->prefix}posts p
INNER JOIN {$wpdb->prefix}wishlist_items wi ON p.ID = wi.post_id
INNER JOIN {$wpdb->prefix}wishlist w ON wi.wishlist_id = w.id
WHERE w.user_id = %d
AND p.post_status = 'publish'
AND p.ID NOT IN (
SELECT wi2.post_id
FROM {$wpdb->prefix}wishlist_items wi2
INNER JOIN {$wpdb->prefix}wishlist w2 ON wi2.wishlist_id = w2.id
WHERE w2.user_id = %d
)
ORDER BY wi.added_at DESC
LIMIT 5",
$similarity_score,
$similar_user->user_id,
$this->user_id
));
$recommendations = array_merge($recommendations, $user_recs);
}
}
return $recommendations;
}
/**
* 基于内容的推荐
*/
private function get_content_based_recommendations($limit) {
global $wpdb;
// 获取用户最近收藏的内容
$user_items = $wpdb->get_results($wpdb->prepare(
"SELECT p.ID, p.post_content, p.post_title
FROM {$wpdb->prefix}posts p
INNER JOIN {$wpdb->prefix}wishlist_items wi ON p.ID = wi.post_id
INNER JOIN {$wpdb->prefix}wishlist w ON wi.wishlist_id = w.id
WHERE w.user_id = %d
AND p.post_status = 'publish'
ORDER BY wi.added_at DESC
LIMIT 20",
$this->user_id
));
if (empty($user_items)) {
return [];
}
// 提取用户兴趣关键词
$user_keywords = $this->extract_user_keywords($user_items);
// 基于关键词查找相似内容
$recommendations = $wpdb->get_results($wpdb->prepare(
"SELECT p.ID, p.post_title,
MATCH(p.post_title, p.post_content)
AGAINST (%s IN NATURAL LANGUAGE MODE) as relevance,
'content' as source_type,
(MATCH(p.post_title, p.post_content)
AGAINST (%s IN NATURAL LANGUAGE MODE)) as score
FROM {$wpdb->prefix}posts p
WHERE p.post_status = 'publish'
AND p.ID NOT IN (
SELECT wi.post_id
FROM {$wpdb->prefix}wishlist_items wi
INNER JOIN {$wpdb->prefix}wishlist w ON wi.wishlist_id = w.id
WHERE w.user_id = %d
)
AND MATCH(p.post_title, p.post_content)
AGAINST (%s IN NATURAL LANGUAGE MODE) > 0
ORDER BY relevance DESC
LIMIT %d",
implode(' ', $user_keywords),
implode(' ', $user_keywords),
$this->user_id,
implode(' ', $user_keywords),
$limit * 2
));
return $recommendations;
}
/**
* 基于标签的推荐
*/
private function get_tag_based_recommendations($limit) {
global $wpdb;
// 获取用户常用标签
$user_tags = $wpdb->get_results($wpdb->prepare(
"SELECT wt.id, wt.name, COUNT(wit.item_id) as usage_count
FROM {$wpdb->prefix}wishlist_tags wt
INNER JOIN {$wpdb->prefix}wishlist_item_tags wit ON wt.id = wit.tag_id
INNER JOIN {$wpdb->prefix}wishlist_items wi ON wit.item_id = wi.id
INNER JOIN {$wpdb->prefix}wishlist w ON wi.wishlist_id = w.id
WHERE w.user_id = %d
GROUP BY wt.id
ORDER BY usage_count DESC
LIMIT 10",
$this->user_id
));
if (empty($user_tags)) {
return [];
}
$tag_ids = wp_list_pluck($user_tags, 'id');
$tag_ids_placeholder = implode(',', array_fill(0, count($tag_ids), '%d'));
// 查找具有相同标签的内容
$recommendations = $wpdb->get_results($wpdb->prepare(
"SELECT p.ID, p.post_title,
COUNT(DISTINCT wt.id) as common_tags,
'tags' as source_type,
(COUNT(DISTINCT wt.id) / %d) as score
FROM {$wpdb->prefix}posts p
INNER JOIN {$wpdb->prefix}term_relationships tr ON p.ID = tr.object_id
INNER JOIN {$wpdb->prefix}term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
INNER JOIN {$wpdb->prefix}terms t ON tt.term_id = t.term_id
INNER JOIN {$wpdb->prefix}wishlist_tags wt ON t.name = wt.name
WHERE p.post_status = 'publish'
AND tt.taxonomy IN ('post_tag', 'category')
AND wt.id IN ($tag_ids_placeholder)
AND p.ID NOT IN (
SELECT wi.post_id
FROM {$wpdb->prefix}wishlist_items wi
INNER JOIN {$wpdb->prefix}wishlist w ON wi.wishlist_id = w.id
WHERE w.user_id = %d
)
GROUP BY p.ID
HAVING common_tags > 0
ORDER BY common_tags DESC
LIMIT %d",
count($tag_ids),
...array_merge($tag_ids, [$this->user_id, $limit * 2])
));
return $recommendations;
}
/**
* 计算用户相似度分数
*/
private function calculate_similarity_score($similar_user) {
// 使用Jaccard相似度系数
$common_items = $similar_user->common_items;
$total_current_items = $this->get_user_item_count();
$total_other_items = $similar_user->total_items;
if ($total_current_items + $total_other_items - $common_items == 0) {
return 0;
}
return $common_items / ($total_current_items + $total_other_items - $common_items);
}
/**
* 提取用户关键词
*/
private function extract_user_keywords($items, $max_keywords = 15) {
$all_content = '';
foreach ($items as $item) {
$all_content .= ' ' . $item->post_title . ' ' . wp_strip_all_tags($item->post_content);
}
// 简单的关键词提取(实际项目中可以使用更复杂的NLP处理)
$words = str_word_count(strtolower($all_content), 1);
$stop_words = ['the', 'and', 'or', 'a', 'an', 'in', 'on', 'at', 'to', 'for'];
$words = array_diff($words, $stop_words);
$word_freq = array_count_values($words);
arsort($word_freq);
return array_slice(array_keys($word_freq), 0, $max_keywords);
}
/**
* 去重和排序推荐结果
*/
private function deduplicate_and_sort($recommendations, $limit) {
$unique_recommendations = [];
foreach ($recommendations as $rec) {
$post_id = $rec->ID;
if (!isset($unique_recommendations[$post_id])) {
$unique_recommendations[$post_id] = $rec;
} else {
// 如果已存在,保留分数较高的
if ($rec->score > $unique_recommendations[$post_id]->score) {
$unique_recommendations[$post_id] = $rec;
}
}
}
// 按分数排序
usort($unique_recommendations, function($a, $b) {
return $b->score <=> $a->score;
});
return array_slice($unique_recommendations, 0, $limit);
}
}
3.2 智能提醒系统
<?php
/**
* 智能提醒系统
*/
class WishlistNotificationSystem {
/**
* 检查并发送相关提醒
*/
public function check_and_send_notifications() {
$this->check_price_drops();
$this->check_back_in_stock();
$this->check_abandoned_wishlist();
$this->check_recommendation_updates();
}
/**
* 价格下降提醒
*/
private function check_price_drops() {
global $wpdb;
// 获取设置了价格提醒的商品
$price_alerts = $wpdb->get_results(
"SELECT wi.id, wi.post_id, wi.user_id,
pa.original_price, pa.desired_price,
u.user_email, p.post_title
FROM {$wpdb->prefix}wishlist_items wi
INNER JOIN {$wpdb->prefix}price_alerts pa ON wi.id = pa.item_id
INNER JOIN {$wpdb->prefix}users u ON wi.user_id = u.ID
INNER JOIN {$wpdb->prefix}posts p ON wi.post_id = p.ID
WHERE pa.is_active = 1
AND pa.last_checked < DATE_SUB(NOW(), INTERVAL 1 HOUR)"
);
foreach ($price_alerts as $alert) {
$current_price = $this->get_current_price($alert->post_id);
if ($current_price && $current_price <= $alert->desired_price) {
$this->send_price_drop_notification($alert, $current_price);
// 更新最后检查时间
$wpdb->update(
"{$wpdb->prefix}price_alerts",
['last_checked' => current_time('mysql')],
['item_id' => $alert->id]
);
}
}
}
/**
* 库存恢复提醒
*/
private function check_back_in_stock() {
global $wpdb;
$out_of_stock_items = $wpdb->get_results(
"SELECT wi.id, wi.post_id, wi.user_id,
u.user_email, p.post_title
FROM {$wpdb->prefix}wishlist_items wi
INNER JOIN {$wpdb->prefix}stock_alerts sa ON wi.id = sa.item_id
INNER JOIN {$wpdb->prefix}users u ON wi.user_id = u.ID
INNER JOIN {$wpdb->prefix}posts p ON wi.post_id = p.ID
WHERE sa.is_active = 1
AND sa.last_checked < DATE_SUB(NOW(), INTERVAL 30 MINUTE)"
);
foreach ($item as $out_of_stock_items) {
$is_in_stock = $this->check_stock_status($item->post_id);
if ($is_in_stock) {
$this->send_back_in_stock_notification($item);
// 停用该提醒
$wpdb->update(
"{$wpdb->prefix}stock_alerts",
['is_active' => 0],
['item_id' => $item->id]
);
}
// 更新最后检查时间
$wpdb->update(
"{$wpdb->prefix}stock_alerts",
['last_checked' => current_time('mysql')],
['item_id' => $item->id]
);
}
}
/**
* 心愿单放弃提醒
*/
private function check_abandoned_wishlist() {
global $wpdb;
// 查找30天未访问但有活跃心愿单的用户
$abandoned_users = $wpdb->get_results(
"SELECT u.ID, u.user_email,
COUNT(wi.id) as item_count,
MAX(wi.added_at) as last_added
FROM {$wpdb->prefix}users u
INNER JOIN {$wpdb->prefix}wishlist w ON u.ID = w.user_id
INNER JOIN {$wpdb->prefix}wishlist_items wi ON w.id = wi.wishlist_id
WHERE u.last_activity < DATE_SUB(NOW(), INTERVAL 30 DAY)
AND w.is_default = 1
GROUP BY u.ID
HAVING item_count > 0"
);
foreach ($user as $abandoned_users) {
$this->send_abandoned_wishlist_notification($user);
}
}
/**
* 发送价格下降通知
*/
private function send_price_drop_notification($alert, $current_price) {
$subject = sprintf('价格提醒:%s 已降价', $alert->post_title);
$message = sprintf(
"您好!nn您关注的商品《%s》价格已下降!nn" .
"原价:¥%.2fn" .
"当前价:¥%.2fn" .
"目标价:¥%.2fnn" .
"立即查看:%snn" .
"祝您购物愉快!",
$alert->post_title,
$alert->original_price,
$current_price,
$alert->desired_price,
get_permalink($alert->post_id)
);
wp_mail($alert->user_email, $subject, $message);
}
/**
* 获取商品当前价格
*/
private function get_current_price($post_id) {
// 这里需要根据实际的价格获取逻辑来实现
// 如果是WooCommerce商品
if (function_exists('wc_get_product')) {
$product = wc_get_product($post_id);
if ($product) {
return $product->get_price();
}
}
// 自定义价格字段
$price = get_post_meta($post_id, '_price', true);
if ($price) {
return floatval($price);
}
