通过long / lat查询自定义帖子类型以查找最近的帖子类型

时间:2017-07-09 21:06:38

标签: php wordpress advanced-custom-fields

我有一个网站,允许用户输入他们的邮政编码,然后他们看到附近的餐馆。我将餐厅存储在MySQL表中,每行包含餐馆名称,地址,营业时间以及经度和纬度。

当用户输入邮政编码时,我使用Google API将邮政编码转换为经度和纬度,然后使用此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的自定义帖子类型,并使用高级自定义字段记录相同的字段 - 名称,地址,开放时间和经度和纬度。我将经度和纬度存储在不同的字段中。

我可以利用WP_Query查询所有餐馆:

$query = new WP_Query( array( 'post_type' => 'restaurants' ) );

但是如何修改我的WP_Query电话,以便我可以通过接近所提供的经度和纬度来搜索和分类餐馆?

3 个答案:

答案 0 :(得分:1)

首先wordpress将你的自定义帖子存储在wp_posts表中,而acf字段存储在wp_post_meta表中,所以你必须以某种方式将它们与sql连接起来。如果我理解你的正确,你可以使用wpdb类,它允许你自己的SQL查询。 https://codex.wordpress.org/Class_Reference/wpdb

答案 1 :(得分:1)

我认为最好的选择是

  1. 在主题选项中创建一个文本区域的acf字段,给它提示<style>.keepitsecret-keeptitsafe{display:none;}</style>,并为该字段本身提供一个&#34; keepitsecret-keeptitsafe&#34;所以它隐藏在前端用户

  2. 像每天的cronjob一样运行(这些餐馆多久更换一次locatoins,你知道吗?)来获取帖子的所有POST_ID,其中包含一个lat&amp; lon数组,它应该是这样的:[1 =&gt; ; [&#39; lat&#39; =&gt; 12123123,&#39; lon&#39; =&gt; 12123123132],3 =&gt; [&#39; lat&#39; =&gt; 12123123,&#39 ; lon&#39; =&gt; 12123123132]]并将其存储为先前创建的选项ACField中的json。 (提示:当你检索时,确保传递假以避免格式化你的json)get_field('latlon', 'option', false) //作为bakcup,如果你想要保存到文件

  3. 
        $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);
        }
    
    1. 使用可选的$ distance = 0参数创建一个查找2个位置之间距离的函数。

    2. 现在当你搜索时,迭代来自存储的POST_ID =&gt; lat&amp; lon数组的所有帖子,保存一个单独的$ finals数组[post_id] = distance

    3. 对数组进行asort,然后使用array_keys来获取订单中的所有帖子ID

    4. 最后在你的wp_query到$ args [&#39; post__in&#39;] = $ finalspostids,

      如果您需要按照$ finalpostids中的订单进行订购,则$ args [&#39; orderby&#39;] =&#39; post__in&#39;

      一些初学者代码:

      
      
          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结果,只要传递极长的搜索文本就可以返回空。

      PS。第一次在这里回答问题,可怕的编辑是碉堡!!!

      祝你好运。

答案 2 :(得分:1)

VA79是正确的,这将非常复杂,需要执行sql连接和操作。

我找到了一个非常简单且易于实现的解决方案。

1。 首先,您需要安装此插件: https://mg.wordpress.org/plugins/acf-google-maps-radius-search/

2。 在第40行的this(!)插件的functions.php中,您必须在变量$ address中设置高级自定义字段的名称。

3。 在第163行的此插件的acf_gms.class.php中,您必须在$ address变量中再次设置字段名称。

4。 现在,您必须保存设置了“ Google地图字段”表单“高级自定义字段”并因此具有经度和纬度值的帖子。这很重要,否则新创建的数据库表(由于插件)将没有值。

5。 保存后,您的数据库中将有一个新表,其中包含“职位ID”,“长整数和经度值”。多亏了该插件,太棒了。

我现在假设您要在帖子存档页面上拥有表单字段,您可以在其中输入地址,并按顺序输出帖子,其中先显示最近的帖子,然后显示下一个最近的帖子,再依次显示以此类推。您想找到最近的,所以我想这就是您要寻找的。

以下代码应输入到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>

如您所见,我们正在从表单字段中获取位置,long和lat值。因此,表单看起来像这样,可以放在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值。使用隐藏的输入,此值将作为参数(?lng = ...&lat = ...)发布到URL。

运行我们的插件并使用新的数据库表后,您将按到您输入的位置的距离获得排序的帖子。

就是这样。如果您有任何疑问,不要介意。