2

我在 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);
4

2 回答 2

2

如果您将您的帖子数据保存在数据库中(将您的坐标分成纬度和对数两个字段),您可以使用余弦定律的大地测量形式来查找点之间的距离。参考

cos(d/R)=cos(lat1)cos(lat2)cos(long2-long1)+sin(lat1)sin(lat2)

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

以下 SQL 查询将以公里为单位提供距离,其中 $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
    }   
}   

该查询基于我在此处使用的代码,但已根据此处找到的信息进行了修改。我无权访问 WordPress 进行检查。

于 2013-11-04T01:09:50.540 回答
1

您肯定需要以不同的方式存储您的值。完成此操作后,我使用了类似于以下内容的表格

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 );

最后,您需要注册一个查询变量才能使用 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
于 2013-11-05T18:44:12.947 回答