Created
May 22, 2015 22:16
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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