修改WP Job Manager搜索结果排序:按地点距离由近到远
解决WP Job Manager搜索结果按距离由近到远排序的问题
要实现按距离搜索地点由近到远排序,我们需要结合Google Geocoding API转换地址为经纬度,再用Haversine公式计算职位与搜索地点的距离,最后修改查询排序逻辑。以下是具体步骤:
前提准备
确保你的WP Job Manager已经配置了Google Maps API,并且每个职位都存储了地理坐标元数据:
_geolocation_lat:职位纬度_geolocation_lng:职位经度
如果还没配置,先在WP Job Manager设置中填入你的Google API密钥,确保地理定位功能正常工作。
修改get_job_listings函数逻辑
基于你提供的代码,我们需要添加距离计算和排序的逻辑:
1. 获取搜索地点的经纬度并过滤有效职位
在处理search_location的代码块中,先调用Google Geocoding API把搜索地址转换为经纬度,同时过滤掉没有地理坐标的职位:
if ( ! empty( $args['search_location'] ) ) { // 获取搜索地点的经纬度 $api_key = '你的Google API密钥'; // 替换成实际密钥 $geocode_url = "https://maps.googleapis.com/maps/api/geocode/json?address=" . urlencode( $args['search_location'] ) . "&key=" . $api_key; $geocode_response = wp_remote_get( $geocode_url ); $search_lat = $search_lng = null; if ( ! is_wp_error( $geocode_response ) ) { $geocode_data = json_decode( wp_remote_retrieve_body( $geocode_response ), true ); if ( isset( $geocode_data['status'] ) && $geocode_data['status'] === 'OK' ) { $search_lat = $geocode_data['results'][0]['geometry']['location']['lat']; $search_lng = $geocode_data['results'][0]['geometry']['location']['lng']; } } // 原有的地点搜索逻辑 $location_meta_keys = array( 'geolocation_formatted_address', '_job_location', 'geolocation_state_long' ); $location_search = array( 'relation' => 'OR' ); foreach ( $location_meta_keys as $meta_key ) { $location_search[] = array( 'key' => $meta_key, 'value' => $args['search_location'], 'compare' => 'like' ); } // 添加过滤:只保留有地理坐标的职位,避免计算错误 $location_search[] = array( 'key' => '_geolocation_lat', 'compare' => 'EXISTS' ); $location_search[] = array( 'key' => '_geolocation_lng', 'compare' => 'EXISTS' ); $query_args['meta_query'][] = $location_search; // 如果成功获取到经纬度,添加距离排序过滤器 if ( isset( $search_lat ) && isset( $search_lng ) ) { // 传递坐标到过滤器 global $current_search_coords; $current_search_coords = array( 'lat' => $search_lat, 'lng' => $search_lng ); add_filter( 'posts_join', 'job_manager_add_distance_join' ); add_filter( 'posts_orderby', 'job_manager_add_distance_orderby', 10, 2 ); } }
2. 定义距离计算的过滤器函数
在函数外部(比如主题的functions.php或者自定义插件中)添加以下两个过滤器函数,用来修改SQL查询的JOIN和ORDER BY部分:
function job_manager_add_distance_join( $join ) { global $wpdb; // 关联纬度和经度的元数据表 $join .= " LEFT JOIN {$wpdb->postmeta} AS lat_meta ON {$wpdb->posts}.ID = lat_meta.post_id AND lat_meta.meta_key = '_geolocation_lat' "; $join .= " LEFT JOIN {$wpdb->postmeta} AS lng_meta ON {$wpdb->posts}.ID = lng_meta.post_id AND lng_meta.meta_key = '_geolocation_lng' "; return $join; } function job_manager_add_distance_orderby( $orderby, $query ) { global $wpdb, $current_search_coords; if ( ! isset( $current_search_coords ) ) { return $orderby; } $search_lat = $current_search_coords['lat']; $search_lng = $current_search_coords['lng']; // 使用Haversine公式计算距离(单位:公里,若要英里替换6371为3959) $distance_calc = "(((acos(sin((" . $search_lat . "*pi()/180)) * sin((lat_meta.meta_value*pi()/180)) + cos((" . $search_lat . "*pi()/180)) * cos((lat_meta.meta_value*pi()/180)) * cos(((" . $search_lng . " - lng_meta.meta_value)*pi()/180)))) * 180/pi()) * 60 * 1.1515 * 1.60934)"; // 设置按距离升序排序(由近到远),保留原排序作为 fallback $orderby = $distance_calc . " ASC, " . $orderby; // 用完后移除过滤器,避免影响其他查询 remove_filter( 'posts_join', 'job_manager_add_distance_join' ); remove_filter( 'posts_orderby', 'job_manager_add_distance_orderby', 10, 2 ); return $orderby; }
3. 调整默认排序参数
在wp_parse_args之后添加逻辑,确保有搜索地点时优先按距离排序:
// 如果有搜索地点,覆盖默认排序规则 if ( ! empty( $args['search_location'] ) ) { $args['orderby'] = 'distance'; $args['order'] = 'ASC'; }
注意事项
- API密钥权限:确保你的Google API密钥启用了Geocoding API,并且设置了正确的域名限制,避免被滥用。
- 性能优化:如果职位数量较多,建议给
_geolocation_lat和_geolocation_lng元字段添加数据库索引,提升查询速度。 - 错误处理:代码中已经加入了基础的错误处理(比如API请求失败的情况),你可以根据需要扩展,比如提示用户无法获取地点坐标。
内容的提问来源于stack exchange,提问作者user246750
相关产品推荐
相关产品推荐

