通过接近纬度和经度对WordPress帖子进行排序

时间:2013-11-03 19:10:11

标签: mysql wordpress geolocation metadata geocoding

我在WordPress中有很多帖子。这些帖子属于“餐馆”类别。每个帖子都有一个自定义的元键/值,如下所示:

$post_geocode = get_post_meta($post->ID, 'geocode', true);
// $post_geocode = '34.0510613,-118.244705'

您必须登录WordPress才能使用我的网站,因此每个用户都有为其存储的地理编码,如下所示:

$user_geocode = get_user_meta( $user->ID, 'geocode', true );
// $user_geocode = '34.043925,-118.2424291'

因此,我希望能够获得帖子并对其进行排名,以便与用户所在位置相近。

理想情况下,它会使用WP Query类。但我很乐意在需要时更改地理编码的存储方式。

最佳答案如下:

// This is how I manage the type of restaurant you'll see (eg: Mexican, Italian etc)
$cat_query = array(
    'taxonomy'  => 'category',
    'field'     => 'slug',
    'terms'     => $restaurant_category, 
    'operator'  => 'IN'
);

// Go and get the posts
$args = array(
    'post_type'         => 'post',
    'post_status'       => 'publish',
    'posts_per_page'    => -20,
    'geocode'               => $user_geocode, // WOuld love this to work!!!
    'orderby'           => 'geocode', // Would love this to work!!!
    'fields'            => 'ids',
    'tax_query'         => array(
        'relation'      => 'AND',
        $cat_query,
    )
);          

$posts = get_posts($args);

2 个答案:

答案 0 :(得分:2)

如果您将后期数据保存在数据库中(将坐标分为纬度和逻辑两个字段),您可以使用余弦定律的大地形式来查找点之间的距离。Reference

  

COS(d / R)= COS(LAT1)COS(LAT2)COS(long2-long1)+ SIN(LAT1)SIN(LAT2)

其中R =地球半径(6367公里,3959英里)

以下SQL查询将提供以kms为单位的距离,其中$ center_lat& $ center_lng是用户位置。

$postids=$wpdb->get_col( $wpdb->prepare("SELECT  name, lat, lng, 
( 6367 * acos( cos( radians(%f) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(%f) ) + sin( radians(%f) ) * sin( radians( lat ) ) ) ) AS distance FROM mytable HAVING distance < %d ORDER BY distance LIMIT 0 , 5",
$center_lat,$center_lng,$center_lat,$radius));
if ( $postids ) 
{
    foreach ( $postids as $id ) 
    {
       echo $id->name;
       echo $id->distance;
       //etc
    }   
}   

该查询基于我使用的代码here,但使用here找到的信息进行了修改。我无法访问WordPress进行检查。

答案 1 :(得分:0)

您肯定需要以不同方式存储您的值。当我这样做时,我已经使用了一些类似于

的表格
CREATE TABLE `geo_db` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `post_id` int(11) DEFAULT NULL,
  `lat` float DEFAULT NULL,
  `lng` float DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `post_id` (`post_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

您也可以使用GEOMETRY类型的单列,但这对于比较地理点是很好的。然后在你的插件中,你将修改WP_Query中使用的sql

function geo_posts_fields( $sql, WP_Query $wp_query ){
    global $wpdb;

    // get your user coords here. explode $user_geocode or store in custom db as well.
    $lat = 45;
    $lng = -122;

    if( $wp_query->query_vars['orderby'] == 'geocode' )
        $sql .= $wpdb->prepare( ", ROUND( ( 3959 * acos( cos( radians(geo_db.lat) ) * cos( radians( %f ) ) 
                               * cos( radians(%f) - radians(geo_db.lng)) + sin(radians(geo_db.lat)) 
                               * sin( radians(%f)))), 1 ) AS `distance` ", $lat, $lng, $lat );

    return $sql;
}

function geo_posts_join( $sql, WP_Query $wp_query ){
    global $wpdb;

    if( $wp_query->query_vars['orderby'] == 'geocode' )
        $sql .= " LEFT JOIN geo_db ON $wpdb->posts.ID = geo_db.post_id ";

    return $sql;
}

function geo_posts_orderby( $sql, WP_Query $wp_query ){
    if( $wp_query->query_vars['orderby'] == 'geocode' )
        $sql = " `distance` ASC, ".$sql;

    return $sql;
}

function geo_posts_request( $sql, WP_Query $wp_query ){
    // just to see whats going on
    var_dump( $sql );
    return $sql;
}


add_filter( 'posts_fields', 'geo_posts_fields', 10, 2 );
add_filter( 'posts_join', 'geo_posts_join', 10, 2 );
add_filter( 'posts_orderby', 'geo_posts_orderby', 10, 2 );
add_filter( 'posts_request', 'geo_posts_request', 10, 2 );

最后,你需要注册一个查询var才能使用orderby作为get_posts的参数,我建议你创建一个新的WP_Query

$geo_posts = new WP_Query( array(
    'post_type' => 'any',
    'orderby' => 'geocode'
) );

while( $geo_posts->have_posts() ): $geo_post->the_post(); // etc