按 long/lat 查询自定义 post 类型以找到最近的
Querying custom post types by long/lat to find nearest
我有一个网站,允许用户输入他们的 post代码,然后他们就可以看到附近的餐馆。我将餐厅存储在 MySQL table 中,每一行包含餐厅名称、地址、营业时间以及经纬度。
当用户输入他们的 post 代码时,我使用 Google API 将 post 代码转换为经度和纬度,然后我使用此 SQL查询...
select
locations.*,
SQRT(
69.1*69.1*(latitude - $latitude)*(latitude - $latitude) +
53*53*(longitude - $longitude)*(longitude - $longitude)
) as distance
from locations
having distance <= 100
order by distance
limit 100
我正在将站点迁移到 Wordpress。我创建了一个名为 restaurants 的自定义 post 类型,并使用 Advanced Custom Fields 来记录相同的字段 - 名称、地址、营业时间以及经度和纬度。我将经度和纬度存储在不同的字段中。
我可以利用WP_Query
查询所有餐厅:
$query = new WP_Query( array( 'post_type' => 'restaurants' ) );
但是我如何修改我的 WP_Query
调用以允许我根据提供的经度和纬度来搜索和排序餐馆?
首先,wordpress 将您的自定义帖子存储在 wp_posts table 中,而 acf 字段存储在 wp_post_meta table 中,因此您必须加入他们以某种方式 sql 。如果我理解你是正确的,你可以使用 wpdb class,它允许你进行自己的 sql 查询。 https://codex.wordpress.org/Class_Reference/wpdb
我认为最好的选择是这个
在你的主题选项中创建一个文本区域 acf 字段给它提示 <style>.keepitsecret-keeptitsafe{display:none;}</style>
并给那个字段本身一个 class 的 "keepitsecret-keeptitsafe" 所以它对前端用户隐藏
运行 就像每天的 cronjob(这些餐馆多久更换一次位置,你知道吗?)来获取你 post 的所有 POST_IDs一个经纬度数组,看起来应该是这样的:[1=>['lat'=>12123123, 'lon'=>12123123132], 3=>['lat'=>12123123, 'lon'=>12123123132]] 并将其作为 json 存储在先前制作的 Option ACField 中。 (提示:当你检索时,确保传递 false 以避免格式化你的 json ) get_field('latlon', 'option', false)
// 作为一个 bakcup,如果你愿意,请保存到文件
$allyourcustomposts = get_posts(['post_type'=>['whateveryourcustompostis'], 'posts_per_page'=> -1]);
foreach($allyourcustomposts as $post) {
$lat = get_field('lat', $post->ID);
$lon = get_field('lon', $post->ID);
if($lat && $lon && $lat != '' && $lon != '') {
$savior[$post->ID] = ['lat'=>$lat,'lon'=>$lon];
}
}
if(count($savior) > 0) {
$json = json_encode($savior);
update_field('field_5b04b0544d603', $json, 'option');
@file_put_contents('savior.json', $json);
}
创建一个函数,使用可选的 $distance = 0 参数查找 2 个位置之间的距离。
现在,当您搜索时,从存储的 POST_ID=>lat&lon 数组中遍历所有 posts 保存一个单独的 $finals[post_id 数组] = 距离
对数组进行排序,然后array_keys得到顺序中的所有post id
最后在你的 wp_query 到 $args['post__in'] = $finalspostids,
如果您需要按照 $finalpostid 中的顺序进行排序,$args['orderby'] = 'post__in'
一点起始代码:
function orderByNearby($lat, $lon, $arrayOfLatLonPosts, $distance = 0) {
$orderedIds = [];
if($lat != 0 && $lon != 0 && $arrayOfLatLonPosts && count($arrayOfLatLonPosts) > 0) {
foreach($arrayOfLatLonPosts as $post_id => $arrayOfLatLonPost) {
$dist = @closeEnough($arrayOfLatLonPost->lat, $arrayOfLatLonPost->lon, $lat, $lon);
if($distance > 0) {
if($dist 0) {
asort($ids);
$args['post__in'] = array_keys($ids);
$args['orderby'] = 'post__in';
} else {
$args['s'] = 'this is hilariously monstreous stupendous name search that will never and probably will ever match!!! so blah blah blah blah blah';
}
所以当您传递 $distance 变量时,您有时会得到 0 个结果,在这种情况下,只需将极长的搜索文本传递给 return 空。
ps。第一次在这里回答问题,编辑的人渣就是地堡!!!
祝你好运。
VA79 是正确的,这将非常复杂,执行 sql 连接和其他操作。
我找到了一个非常简单且易于实施的解决方案。
1。
首先你需要安装这个插件:
https://mg.wordpress.org/plugins/acf-google-maps-radius-search/
2。
在第 40 行的这个(!)插件的 functions.php 中,您必须在变量 $address 中设置高级自定义字段的名称。
3。
在第 163 行的此插件的 acf_gms.class.php 中,您必须在 $address 变量中再次设置您的字段名称。
4。
现在您必须保存 posts,它们具有 Google 地图字段表单高级自定义字段设置,因此具有经度和纬度值。这很重要,否则新创建的数据库 table(感谢插件)将没有其中的值。
5。
保存后,您的数据库中有一个新的 table,其中包含 Post ID、Long 和 Lat Value。感谢插件,太棒了
我现在假设您希望在 post 存档页面上有表单字段,您可以在其中输入地址并按顺序输出 posts,其中最接近的post 首先显示,下一个最接近的 post 依次类推。你想找最近的,所以我想这就是你要找的。
应在您的 archive.php 文件中输入以下代码。请用您的密钥替换 API 密钥。
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=YOURAPIKEY&libraries=places"></script>
<script>
function initialize() {
var input = document.getElementById('location');
var options = {
types: ['(regions)'],
};
var autocomplete = new google.maps.places.Autocomplete(input, options);
google.maps.event.addListener(autocomplete, 'place_changed', function () {
var place = autocomplete.getPlace();
document.getElementById('lng').value = place.geometry.location.lng();
document.getElementById('lat').value = place.geometry.location.lat();
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
如您所见,我们正在从表单字段中获取位置、经度和纬度值。所以表格看起来像这样,可以放在存档 php 文件中。
<form id="yourform">
<div>
<input id="location" type="text" name="location" placeholder="Postcode and place of residence" autocomplete="on" runat="server" />
<input type="hidden" id="lng" name="lng" />
<input type="hidden" id="lat" name="lat" />
</div> <!-- field -->
<input type="submit" value="Search nearest" />
</form>
如果您在 ID 为 "location" 的输入字段中输入位置,google 地图将提供位置建议。当您提交表单时,我们开始使用的脚本将使用此位置并获取 long 和 lat 值。使用隐藏输入,此值将 posted 到 URL 作为参数 (?lng=...&lat=...)。
使用我们的插件 运行 和新数据库 table,您将获得 post 按您输入的位置的距离排序的数据。
就是这样。如果您有任何问题,请不要介意。
我有一个网站,允许用户输入他们的 post代码,然后他们就可以看到附近的餐馆。我将餐厅存储在 MySQL table 中,每一行包含餐厅名称、地址、营业时间以及经纬度。
当用户输入他们的 post 代码时,我使用 Google API 将 post 代码转换为经度和纬度,然后我使用此 SQL查询...
select
locations.*,
SQRT(
69.1*69.1*(latitude - $latitude)*(latitude - $latitude) +
53*53*(longitude - $longitude)*(longitude - $longitude)
) as distance
from locations
having distance <= 100
order by distance
limit 100
我正在将站点迁移到 Wordpress。我创建了一个名为 restaurants 的自定义 post 类型,并使用 Advanced Custom Fields 来记录相同的字段 - 名称、地址、营业时间以及经度和纬度。我将经度和纬度存储在不同的字段中。
我可以利用WP_Query
查询所有餐厅:
$query = new WP_Query( array( 'post_type' => 'restaurants' ) );
但是我如何修改我的 WP_Query
调用以允许我根据提供的经度和纬度来搜索和排序餐馆?
首先,wordpress 将您的自定义帖子存储在 wp_posts table 中,而 acf 字段存储在 wp_post_meta table 中,因此您必须加入他们以某种方式 sql 。如果我理解你是正确的,你可以使用 wpdb class,它允许你进行自己的 sql 查询。 https://codex.wordpress.org/Class_Reference/wpdb
我认为最好的选择是这个
在你的主题选项中创建一个文本区域 acf 字段给它提示
<style>.keepitsecret-keeptitsafe{display:none;}</style>
并给那个字段本身一个 class 的 "keepitsecret-keeptitsafe" 所以它对前端用户隐藏运行 就像每天的 cronjob(这些餐馆多久更换一次位置,你知道吗?)来获取你 post 的所有 POST_IDs一个经纬度数组,看起来应该是这样的:[1=>['lat'=>12123123, 'lon'=>12123123132], 3=>['lat'=>12123123, 'lon'=>12123123132]] 并将其作为 json 存储在先前制作的 Option ACField 中。 (提示:当你检索时,确保传递 false 以避免格式化你的 json )
get_field('latlon', 'option', false)
// 作为一个 bakcup,如果你愿意,请保存到文件
$allyourcustomposts = get_posts(['post_type'=>['whateveryourcustompostis'], 'posts_per_page'=> -1]);
foreach($allyourcustomposts as $post) {
$lat = get_field('lat', $post->ID);
$lon = get_field('lon', $post->ID);
if($lat && $lon && $lat != '' && $lon != '') {
$savior[$post->ID] = ['lat'=>$lat,'lon'=>$lon];
}
}
if(count($savior) > 0) {
$json = json_encode($savior);
update_field('field_5b04b0544d603', $json, 'option');
@file_put_contents('savior.json', $json);
}
创建一个函数,使用可选的 $distance = 0 参数查找 2 个位置之间的距离。
现在,当您搜索时,从存储的 POST_ID=>lat&lon 数组中遍历所有 posts 保存一个单独的 $finals[post_id 数组] = 距离
对数组进行排序,然后array_keys得到顺序中的所有post id
最后在你的 wp_query 到 $args['post__in'] = $finalspostids,
如果您需要按照 $finalpostid 中的顺序进行排序,$args['orderby'] = 'post__in'
一点起始代码:
function orderByNearby($lat, $lon, $arrayOfLatLonPosts, $distance = 0) {
$orderedIds = [];
if($lat != 0 && $lon != 0 && $arrayOfLatLonPosts && count($arrayOfLatLonPosts) > 0) {
foreach($arrayOfLatLonPosts as $post_id => $arrayOfLatLonPost) {
$dist = @closeEnough($arrayOfLatLonPost->lat, $arrayOfLatLonPost->lon, $lat, $lon);
if($distance > 0) {
if($dist 0) {
asort($ids);
$args['post__in'] = array_keys($ids);
$args['orderby'] = 'post__in';
} else {
$args['s'] = 'this is hilariously monstreous stupendous name search that will never and probably will ever match!!! so blah blah blah blah blah';
}
所以当您传递 $distance 变量时,您有时会得到 0 个结果,在这种情况下,只需将极长的搜索文本传递给 return 空。
ps。第一次在这里回答问题,编辑的人渣就是地堡!!!
祝你好运。
VA79 是正确的,这将非常复杂,执行 sql 连接和其他操作。
我找到了一个非常简单且易于实施的解决方案。
1。 首先你需要安装这个插件: https://mg.wordpress.org/plugins/acf-google-maps-radius-search/
2。 在第 40 行的这个(!)插件的 functions.php 中,您必须在变量 $address 中设置高级自定义字段的名称。
3。 在第 163 行的此插件的 acf_gms.class.php 中,您必须在 $address 变量中再次设置您的字段名称。
4。 现在您必须保存 posts,它们具有 Google 地图字段表单高级自定义字段设置,因此具有经度和纬度值。这很重要,否则新创建的数据库 table(感谢插件)将没有其中的值。
5。 保存后,您的数据库中有一个新的 table,其中包含 Post ID、Long 和 Lat Value。感谢插件,太棒了
我现在假设您希望在 post 存档页面上有表单字段,您可以在其中输入地址并按顺序输出 posts,其中最接近的post 首先显示,下一个最接近的 post 依次类推。你想找最近的,所以我想这就是你要找的。
应在您的 archive.php 文件中输入以下代码。请用您的密钥替换 API 密钥。
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=YOURAPIKEY&libraries=places"></script>
<script>
function initialize() {
var input = document.getElementById('location');
var options = {
types: ['(regions)'],
};
var autocomplete = new google.maps.places.Autocomplete(input, options);
google.maps.event.addListener(autocomplete, 'place_changed', function () {
var place = autocomplete.getPlace();
document.getElementById('lng').value = place.geometry.location.lng();
document.getElementById('lat').value = place.geometry.location.lat();
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
如您所见,我们正在从表单字段中获取位置、经度和纬度值。所以表格看起来像这样,可以放在存档 php 文件中。
<form id="yourform">
<div>
<input id="location" type="text" name="location" placeholder="Postcode and place of residence" autocomplete="on" runat="server" />
<input type="hidden" id="lng" name="lng" />
<input type="hidden" id="lat" name="lat" />
</div> <!-- field -->
<input type="submit" value="Search nearest" />
</form>
如果您在 ID 为 "location" 的输入字段中输入位置,google 地图将提供位置建议。当您提交表单时,我们开始使用的脚本将使用此位置并获取 long 和 lat 值。使用隐藏输入,此值将 posted 到 URL 作为参数 (?lng=...&lat=...)。
使用我们的插件 运行 和新数据库 table,您将获得 post 按您输入的位置的距离排序的数据。
就是这样。如果您有任何问题,请不要介意。