如何在$wpdb->prepare查询中添加ACF字段category的校验?
问题分析与修复方案
核心错误点
- 逻辑矛盾的meta_key条件:你把
latitude.meta_key同时设置为$category和'latitude',一条postmeta记录的meta_key不可能同时等于两个不同值,这直接导致查询无结果。 - SQL注入风险与占位符误用:
p.post_title LIKE '%$company%'直接拼接变量,违反WordPress安全规范;同时$wpdb->prepare的参数顺序完全错位,导致距离计算逻辑混乱。 - 缺少独立的category字段关联:ACF的
category字段需要单独关联postmeta表,不能复用存储经纬度的表。
修复后的代码
function get_nearby_locations( $lat, $lng, $distance, $company, $category ) { global $wpdb; $earth_radius = 3959; // 初始化基础SQL语句 $sql = " SELECT DISTINCT p.ID, p.post_title, latitude.meta_value as locLat, longitude.meta_value as locLong, ( %d * acos( cos( radians( %s ) ) * cos( radians( latitude.meta_value ) ) * cos( radians( longitude.meta_value ) - radians( %s ) ) + sin( radians( %s ) ) * sin( radians( latitude.meta_value ) ) ) ) AS distance FROM $wpdb->posts p INNER JOIN $wpdb->postmeta latitude ON p.ID = latitude.post_id INNER JOIN $wpdb->postmeta longitude ON p.ID = longitude.post_id WHERE 1 = 1 AND p.post_type = 'supplier' AND p.post_status = 'publish' AND latitude.meta_key = 'latitude' AND longitude.meta_key = 'longitude' "; $params = array( $earth_radius, $lat, $lng, $lat ); // 处理公司名称搜索 if ( ! empty( $company ) ) { $sql .= " AND p.post_title LIKE %s "; $params[] = "%{$company}%"; } // 处理分类筛选 if ( ! empty( $category ) ) { $sql .= " INNER JOIN $wpdb->postmeta cat_meta ON p.ID = cat_meta.post_id AND cat_meta.meta_key = 'category' AND cat_meta.meta_value = %s "; $params[] = $category; } // 添加距离条件与排序 $sql .= " HAVING distance < %s ORDER BY distance ASC "; $params[] = $distance; // 执行预处理查询 $prepared_sql = $wpdb->prepare( $sql, $params ); $nearbyLocations = $wpdb->get_results( $prepared_sql ); return $nearbyLocations ?: array(); }
关键修复说明
- 新增
cat_meta关联表专门处理ACF的category字段,避免和经纬度的postmeta表冲突。 - 用动态拼接的方式处理可选的搜索条件(公司名称、分类),确保空值时不影响基础查询。
- 所有变量都通过
$wpdb->prepare的占位符传递,彻底避免SQL注入风险。 - 修正了距离计算公式的参数顺序,确保经纬度计算逻辑正确。
内容的提问来源于stack exchange,提问作者onesixty
相关产品推荐
相关产品推荐

