Skip to content

Instantly share code, notes, and snippets.

@archonic
Created May 22, 2015 22:16
Show Gist options
  • Save archonic/2d57320ae438745146c3 to your computer and use it in GitHub Desktop.
Save archonic/2d57320ae438745146c3 to your computer and use it in GitHub Desktop.
WordPress Geo Products. Depends on ACF for location meta. Replaces product search to include distance query.
class WP_Query_Geo extends WP_Query {
private $lat = NULL;
private $lng = NULL;
private $distance = NULL;
/**
* Constructor - adds necessary filters to extend Query hooks
*/
public function __construct( $args = array() ) {
// Extract Latitude
if(!empty($args['lat'])) {
$this->lat = $args['lat'];
}
// Extract Longitude
if(!empty($args['lng'])) {
$this->lng = $args['lng'];
}
// Extract Longitude
if(!empty($args['distance'])) {
$this->distance = $args['distance'];
}
// unset lat/long
unset($args['lat'], $args['lng'], $args['distance']);
add_filter('posts_fields', array($this, 'posts_fields'), 10, 2);
add_filter('posts_join', array($this, 'posts_join'), 10, 2);
add_filter('posts_where', array($this, 'posts_where'), 10, 2);
add_filter('posts_orderby', array($this, 'posts_orderby'), 10, 2);
add_filter('posts_distinct', array($this, 'posts_distinct'), 10, 2);
parent::query($args);
// Remove filters so only WP_GeoQuery queries this way
remove_filter('posts_fields', array($this, 'posts_fields'));
remove_filter('posts_join', array($this, 'posts_join'));
remove_filter('posts_where', array($this, 'posts_where'));
remove_filter('posts_orderby', array($this, 'posts_orderby'));
remove_filter('posts_distinct', array($this, 'posts_distinct'));
}
/**
* Return only distinct results
*/
public function posts_distinct() {
return "DISTINCT";
}
/**
* Selects the distance from a haversine formula
*/
public function posts_fields($fields) {
global $wpdb;
if(!empty($this->lat) && !empty($this->lng)) {
$fields .= sprintf(", ( 6371 * acos(
cos( radians(%s) ) *
cos( radians( latitude.meta_value ) ) *
cos( radians( longitude.meta_value ) - radians(%s) ) +
sin( radians(%s) ) *
sin( radians( latitude.meta_value ) )
) ) AS distance ", $this->lat, $this->lng, $this->lat);
}
$fields .= ", latitude.meta_value AS latitude ";
$fields .= ", longitude.meta_value AS longitude ";
echo '<pre>FIELDS: ' . $fields . '</pre>';
return $fields;
}
/**
* Makes joins as necessary in order to select lat/long metadata
*/
public function posts_join($join, $query) {
global $wpdb;
$join .= " INNER JOIN {$wpdb->postmeta} AS latitude ON {$wpdb->posts}.ID = latitude.post_id ";
$join .= " INNER JOIN {$wpdb->postmeta} AS longitude ON {$wpdb->posts}.ID = longitude.post_id ";
echo '<pre>JOIN: ' . $join . '</pre>';
return $join;
}
/**
* Adds where clauses to compliment joins
*/
public function posts_where($where) {
$where .= ' AND latitude.meta_key="lat" ';
$where .= ' AND longitude.meta_key="lng" ';
if(!empty($this->lat) && !empty($this->lng) && !empty($this->distance)) {
if(is_numeric($this->distance)) {
$where .= sprintf(' HAVING distance <= %s ', $this->distance);
}
}
echo '<pre>WHERE: ' . $where . '</pre>';
return $where;
}
/**
* Adds where clauses to compliment joins
*/
public function posts_orderby($orderby) {
if(!empty($this->lat) && !empty($this->lng)) {
$orderby = " distance ASC, " . $orderby;
}
return $orderby;
}
}
// Override product search to include post_meta lat/lng, order by distance (if search provides location)
add_action('pre_get_posts','product_location_search_filter');
function product_location_search_filter( $query ) {
if ( !is_admin() && is_post_type_archive('product') && $query->is_search ) {
# How do I get search terms up in dis?
$args = array(
'post_type' => $query->get('post_type') ,
'posts_per_page' => 20,
'fields' => 'all',
'lat' => $_REQUEST['lat'],
'lng' => $_REQUEST['lng'],
'distance' => $_REQUEST['dist'],
# UNCOMMENTING THIS MAKES THE SKY FALL. But why?
#'s' => $_REQUEST['s']
);
$geo_query = new WP_Query_Geo( $args );
# Actually affect search query
global $wp_query;
$wp_query = $geo_query;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment