web-dev-qa-db-ja.com

与えられた緯度と経度から500マイル以内のデータベースからすべての結果を見つける

私はこの問題に立ち往生しています。ここでの主な要件は、与えられた緯度と経度から500マイル以内にあるすべての結果をデータベースから見つけることです。 latiとlongiをそれらの緯度と経度の郵便番号と一緒にpost_metaに保存しました。これで、ユーザーが郵便番号を検索してドロップダウンからマイルを選択し、そのクエリに一致するすべての結果が得られるようになります。インスタンス。

ユーザーはこのような質問をします

51310から500マイル

クエリは、郵便番号51310の500マイル以内にあるすべての結果を返すはずです。

これが私がこれまでにやったことです。これが実際にデータベースへの問い合わせをしている主な機能です。

if (isset($_GET['s']) && !empty($_GET['s'])) {

        $searchterm = isset($q->query_vars['s']) ? sanitize_text_field($q->query_vars['s']) : '';

        // we have to remove the "s" parameter from the query, because it will prevent the posts from being found
        $q->query_vars['s'] = '';

        if ($searchterm != '') {

            $search_radius = $this->geocode($searchterm);

            if (!$search_radius) {
                return false;
            }

            $lat = $search_radius['lat']; // get the lat of the requested address
            $lng = $search_radius['lng']; // get the lng of the requested address
            // we'll want everything within, say, 30km distance
            $distance = isset($_GET['within']) && !empty($_GET['within']) ? floatval($_GET['within']) : 50;

            // earth's radius in km = ~6371
            $radius = auto_listings_metric() == 'yes' ? 6371 : 3950;

            // latitude boundaries
            $maxlat = $lat + rad2deg($distance / $radius);
            $minlat = $lat - rad2deg($distance / $radius);

            // longitude boundaries (longitude gets smaller when latitude increases)
            $maxlng = $lng + rad2deg($distance / $radius / cos(deg2rad($lat)));
            $minlng = $lng - rad2deg($distance / $radius / cos(deg2rad($lat)));

            // build the meta query array
            $radius_array = array(
                'relation' => 'AND',
            );

            $radius_array[] = array(
                'key' => '_al_listing_lat',
                'value' => array($minlat, $maxlat),
                'type' => 'DECIMAL(10,5)',
                'compare' => 'BETWEEN',
            );
            $radius_array[] = array(
                'key' => '_al_listing_lng',
                'value' => array($minlng, $maxlng),
                'type' => 'DECIMAL(10,5)',
                'compare' => 'BETWEEN',
            );

            return apply_filters('auto_listings_search_radius_args', $radius_array);

そして、私がこの関数を書いたジオコードを見つけるために。

$address = urlencode(esc_html($address));

    // google map geocode api url
    $url = auto_listings_google_geocode_maps_url($address);

    $arrContextOptions = array(
        "ssl" => array(
            "verify_peer" => false,
            "verify_peer_name" => false,
        ),
    );

    // get the json response
    $resp_json = file_get_contents($url, false, stream_context_create($arrContextOptions));

    // decode the json
    $resp = json_decode($resp_json, true);

    //pp( $resp );
    // response status will be 'OK', if able to geocode given address 
    if ($resp['status'] == 'OK') {

        // get the lat and lng
        $lat = $resp['results'][0]['geometry']['location']['lat'];
        $lng = $resp['results'][0]['geometry']['location']['lng'];

        // verify if data is complete
        if ($lat && $lng) {

            return array(
                'lat' => $lat,
                'lng' => $lng,
            );
        } else {
            return false;
        }
    } else {
        return false;
    }

フィールド内を選択しない場合、このコードは特定の郵便番号の正確な結果を返しますが、フィールド内を選択した場合は何も表示されません。このコードの中で私が間違っていることを誰かに教えてもらえますか。

2
Mohsin

問題は、クエリをデータベースに送信したときに、配列のレベルが変更されていて、レコードの取得が妨げられていたために 's'の値が空にならなかったことです。機能を変更してクエリを実行したところ、問題は解決しました。

他の誰かがそのような機能を作る必要がある場合のために、これはこの論理のために更新されたコードです。

すべてのデータが集まってクエリを作成する主な機能

public function pre_get_posts($q) {

    // check if the user is requesting an admin page 
    if (is_admin() || !$q->is_main_query())
        return;

    if (!is_post_type_archive('auto-listing'))
        return;

    if (!is_search())
        return;

    $meta_query = array();

    $year_query[] = $this->year_query();
    $model_query[] = $this->model_query();
    $condition_query[] = $this->condition_query();
    $odometer_query[] = $this->odometer_query();
    $price_query[] = $this->price_meta_query();
    $body_type_query = $this->body_type_query();
    $country_query = $this->country_query();
    $transmission_query = $this->transmission_query();
    $radius_query[] = $this->radius_query($q);

    $query_1 = array_merge($country_query, $year_query, $model_query, $condition_query, $price_query, $odometer_query, $transmission_query);
    // if our radius query fails, fall back to keyword searching
    // will fail with no map API key
    if (empty($radius_query[0]) || !$radius_query[0]) {
        $keyword_query[] = $this->keyword_query($q);
        $query_2 = $keyword_query;
    } else {
        $query_2 = $radius_query;
    }

    // if no keyword
    if (empty($_GET['s'])) {
        $query_1['relation'] = 'AND';
        $meta_query[] = $query_1;
    }

    // if keyword
    if (!empty($_GET['s'])) {
        $query_2['relation'] = 'OR';
        $meta_query[] = $query_1;
        $meta_query[] = $query_2;
        $meta_query['relation'] = 'AND';
    }

    $q->set('meta_query', $meta_query);

    $q->set('tax_query', $body_type_query);

    $q->set('post_type', 'auto-listing');

}

実際に魔法をやっていたRadiusクエリ関数

public function radius_query($q) {

    if (isset($_GET['s']) && !empty($_GET['s'])) {

        $searchterm = isset($q->query_vars['s']) ? sanitize_text_field($q->query_vars['s']) : '';

        // we have to remove the "s" parameter from the query, because it will prevent the posts from being found
        $q->query_vars['s'] = '';

        if ($searchterm != '') {

            $search_radius = $this->geocode($searchterm);

            if (!$search_radius)
                return false;

            $lat = $search_radius['lat']; // get the lat of the requested address
            $lng = $search_radius['lng']; // get the lng of the requested address
            // we'll want everything within, say, 30km distance
            $distance = isset($_GET['within']) && !empty($_GET['within']) ? floatval($_GET['within']) : 0.1;

            // earth's radius in km = ~6371
            $radius = auto_listings_metric() == 'yes' ? 6371 : 3950;

            // latitude boundaries
            $maxlat = $lat + rad2deg($distance / $radius);
            $minlat = $lat - rad2deg($distance / $radius);

            // longitude boundaries (longitude gets smaller when latitude increases)
            $maxlng = $lng + rad2deg($distance / $radius / cos(deg2rad($lat)));
            $minlng = $lng - rad2deg($distance / $radius / cos(deg2rad($lat)));

            // build the meta query array
            $radius_array = array(
                'relation' => 'AND',
            );

            $radius_array[] = array(
                'key' => '_al_listing_lat',
                'value' => array($minlat, $maxlat),
                'type' => 'DECIMAL(10,5)',
                'compare' => 'BETWEEN',
            );
            $radius_array[] = array(
                'key' => '_al_listing_lng',
                'value' => array($minlng, $maxlng),
                'type' => 'DECIMAL(10,5)',
                'compare' => 'BETWEEN',
            );

            return apply_filters('auto_listings_search_radius_args', $radius_array);
        }
    }
}

ユーザーが入力したZipコードから緯度と経度を取得していた最後の関数 /

private function geocode($address) {
    // url encode the address
    $address = urlencode(esc_html($address));

    // google map geocode api url
    $url = auto_listings_google_geocode_maps_url($address);

    $arrContextOptions = array(
        "ssl" => array(
            "verify_peer" => false,
            "verify_peer_name" => false,
        ),
    );

    // get the json response
    $resp_json = file_get_contents($url, false, stream_context_create($arrContextOptions));

    // decode the json
    $resp = json_decode($resp_json, true);

    //pp( $resp );
    // response status will be 'OK', if able to geocode given address 
    if ($resp['status'] == 'OK') {

        // get the lat and lng
        $lat = $resp['results'][0]['geometry']['location']['lat'];
        $lng = $resp['results'][0]['geometry']['location']['lng'];

        // verify if data is complete
        if ($lat && $lng) {

            return array(
                'lat' => $lat,
                'lng' => $lng,
            );
        } else {
            return false;
        }
    } else {
        return false;
    }
}

この答えに基づいて投稿を見つけるには、郵便番号をpost_metaテーブルに格納してlatiとlongiを取得し、コードで指定された式でmaxとminの境界を検索することでlatとlngを取得する必要があります。そうでない場合は、詳細に回答してください。

0
Mohsin