php – 按坐标之间的距离过滤wordpress帖子
我想要做的是通过2个坐标之间的距离过滤一堆wordpress帖子.用户输入的坐标,范围和类别在URL中传递,如下所示:
/?cat=0&s=5041GW&range=250&lat=51.5654368&lon=5.071263999999928 然后有一些帖子(不是全部)有一个lat和long字段,我使用插件高级自定义字段创建.这些是我传递给get_posts以获取按类别过滤的帖子的参数: $args = array( 'posts_per_page' => 24,'category' => $_GET["cat"],'orderby' => 'post_date','order' => 'DESC','post_type' => 'adressen','post_status' => 'publish',); 现在我要做的就是修改它,以便在实际传递范围和位置时,帖子将被过滤为仅返回位置在用户搜索位置的范围(以千米为单位)内的帖子.我似乎无法找到一个好的解决方案,因为我很难使用wordpress及其插件.我真的很感激我能理解的解决方案. 解决方法
这在计算上可能相当昂贵.直接的方法是获取符合条件的所有帖子,然后循环遍历所有帖子,丢弃指定范围之外的帖子.
由于米和纬度/长度之间没有线性映射,因此出现了困难.这取决于你在地球上的位置.有关详情,请参见this question. PHPcoord library存在为您进行此计算,但由于我提出的答案的略微近似性质,我将使用Haversine formula使用Haversine formula描述的近似方法. 我将使用以下公式: >计算两个lat / lng坐标之间的距离(以km为单位): x = Δλ ? cos φm y = Δφ d = R ? √(x2 + y2) 其中φ是弧度的纬度,λ是弧度的经度,R是地球的半径(平均半径= 6,371km) φ2 = asin( sin φ1 ? cos δ + cos φ1 ? sin δ ? cos θ ) λ2 = λ1 + atan2( sin θ ? sin δ ? cos φ1,cos δ ? sin φ1 ? sin φ2 ) 其中θ是方位(从北向顺时针方向),δ是角距离d / R,d是行进距离.见atan2. 因此,我们将定义以下辅助函数: const R = 6371; // km function distance_between_points_rad($lat1,$lng1,$lat2,$lng2){ // latlng in radians $x = ($lng2-$lng1) * cos(($lat1+$lat2)/2); $y = ($lat2-$lat1); // return distance in km return sqrt($x*$x + $y*$y) * R; } function get_destination_lat_rad($lat1,$d,$brng){ return asin( sin($lat1)*cos($d/R) + cos($lat1)*sin($d/R)*cos($brng) ); } function get_destination_lng_rad($lat1,$brng){ $lat2 = get_destination_lat_rad($lat1,$brng); return $lng1 + atan2(sin($brng)*sin($d/R)*cos($lat1),cos($d/R)-sin($lat1)*sin($lat2)); } function get_bounding_box_rad($lat,$lng,$range){ // latlng in radians,$range in km $latmin = get_destination_lat_rad($lat,$range,0); $latmax = get_destination_lat_rad($lat,deg2rad(180)); $lngmax = get_destination_lng_rad($lat,deg2rad(90)); $lngmin = get_destination_lng_rad($lat,deg2rad(270)); // return approx bounding latlng in radians return array($latmin,$latmax,$lngmin,$lngmax); } function distance_between_points_deg($lat1,$lng2){ // latlng in degrees // return distance in km return distance_between_points_rad( deg2rad($lat1),deg2rad($lng1),deg2rad($lat2),deg2rad($lng2) ); } function get_bounding_box_deg($lat,$range){ // latlng in degrees,$range in km return array_map(rad2deg,get_bounding_box_rad(deg2rad($lat),deg2rad($lng),$range)); } (Runnable in ideone) 现在,一般过程应是: >创建一个边界square-ish框,将帖子过滤到一个 您要使用的查询应包含元信息: $lat1 = $_GET['lat']; // degrees $lng1 = $_GET['lng']; // degrees $range = $_GET['range']; // km // get the approximate bounding box $bbox = get_bounding_box_deg($lat1,$range); // query the posts $args = array( 'posts_per_page' => 24,'meta_query' => array( 'relation' => 'AND',array( 'key' => 'lat','value' => array( $bbox[0],$bbox[1] ),'type' => 'numeric','compare' => 'BETWEEN' ),array( 'key' => 'lng','value' => array( $bbox[2],$bbox[3] ),'compare' => 'BETWEEN' ) ) ); $the_query = new WP_Query( $args ); 然后在循环中过滤帖子: // Then filter the posts down in the loop if ( $the_query->have_posts() ) { while ( $the_query->have_posts() ) { $the_query->the_post(); $custom_fields = get_post_custom(); if (isset($custom_fields['lat']) && isset($custom_fields['lng'])){ $lat2 = $custom_fields['lat']; $lng2 = $custom_fields['lng']; $dist = distance_between_points_deg($lat1,$lng2); if ($dist <= $range){ // post is in range } else { // post out of range,discard } } else { // post has no latlng coords } } } else { // no posts found } /* Restore original Post Data */ wp_reset_postdata(); WordPress代码未经测试,如果错误仍然存??在,请道歉.一般的概念是正确的. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |