simplemap/classes/xml-search.php

235 lines
7.6 KiB
PHP
Executable File

<?php
if ( !class_exists( 'SM_XML_Search' ) ){
class SM_XML_Search{
// Register hook to perform the search
function sm_xml_search() {
add_action( 'template_redirect', array( &$this, 'init_search' ) );
}
// Inits the search process. Collects default options, search options, and queries DB
function init_search() {
if ( isset( $_GET['sm-xml-search'] ) ) {
global $wpdb, $simple_map;
remove_filter( 'the_title', 'at_title_check' );
$defaults = array(
'lat' => false,
'lng' => false,
'radius' => false,
'namequery' => false,
'query_type' => 'distance',
'address' => false,
'city' => false,
'state' => false,
'zip' => false,
'onlyzip' => false,
'country' => false,
'limit' => false,
'page' => false,
'pid' => 0,
);
$input = array_filter( array_intersect_key( $_GET, $defaults ) ) + $defaults;
$smtaxes = array();
if ( $taxonomies = get_object_taxonomies( 'sm-location' ) ) {
foreach ( $taxonomies as $key => $tax ) {
$phpsafe = str_replace( '-', '_', $tax );
$_GET += array( $phpsafe => '' );
$smtaxes[$tax] = $_GET[$phpsafe];
}
}
// Define my empty strings
$distance_select = $distance_having = $distance_order = '';
// We're going to do a hard limit to 5000 for now.
if ( !$input['limit'] || $input['limit'] > 250 || $input['limit'] == 0 ) {
$limit_int = 250;
$limit = "LIMIT 250";
}
else {
$limit_int = absint( $input['limit'] );
$limit = 'LIMIT ' . $limit_int;
}
$limit = apply_filters( 'sm-xml-search-limit', $limit );
if ( $input['page'] && $input['page'] < 250 ) {
$offset = 'OFFSET ' . ( absint($input['page']) - 1) * absint( $input['limit'] );
}
else {
$offset = '';
}
// Locations within specific distance or just get them all?
$distance_select = $wpdb->prepare( "( 3959 * ACOS( COS( RADIANS(%s) ) * COS( RADIANS( lat_tbl.meta_value ) ) * COS( RADIANS( lng_tbl.meta_value ) - RADIANS(%s) ) + SIN( RADIANS(%s) ) * SIN( RADIANS( lat_tbl.meta_value ) ) ) ) AS distance", $input['lat'], $input['lng'], $input['lat'] ) . ', ';
$distance_order = 'distance, ';
if ( $input['radius'] ) {
$input['radius'] = ( $input['radius'] < 1 ) ? 1 : $input['radius'];
$distance_having = $wpdb->prepare( "HAVING distance < %d", $input['radius'] );
}
$i = 1;
$taxonomy_join = '';
foreach ( array_filter( $smtaxes ) as $taxonomy => $tax_value ) {
$term_ids = explode( ',', $tax_value );
if ( $term_ids[0] == 'OR' ) {
unset( $term_ids[0] );
if ( empty( $term_ids ) ) {
continue;
}
$search_values = array( "IN (" . vsprintf( '%d' . str_repeat( ',%d', count( $term_ids ) - 1 ), $term_ids ) . ")" );
} else {
$search_values = array();
foreach ( $term_ids as $term_id ) {
$search_values[] = sprintf( '= %d', $term_id );
}
}
foreach ( $search_values as $search_value ) {
$taxonomy_join .= "
INNER JOIN
$wpdb->term_relationships AS term_rel_$i ON posts.ID = term_rel_$i.object_id
INNER JOIN
$wpdb->term_taxonomy AS tax_$i ON
term_rel_$i.term_taxonomy_id = tax_$i.term_taxonomy_id
AND tax_$i.taxonomy = '$taxonomy'
AND tax_$i.term_id $search_value
";
$i++;
}
}
// Find out how many items are in the table
$total_locations_sql = $wpdb->get_var( "
SELECT
COUNT(*)
FROM
$wpdb->posts AS posts
INNER JOIN
$wpdb->postmeta lat_tbl ON lat_tbl.post_id = posts.ID AND lat_tbl.meta_key = 'location_lat'
INNER JOIN
$wpdb->postmeta lng_tbl ON lng_tbl.post_id = posts.ID AND lng_tbl.meta_key = 'location_lng'
$taxonomy_join
WHERE
posts.post_type = 'sm-location'
AND posts.post_status = 'publish'
" );
$total_locations = absint($total_locations_sql);
$total_pages = ceil($total_locations / $limit_int); // use ceiling to round up -- 0.01 is still "1 page"
$this_page_number = absint($input['page']);
if($this_page_number < 1) {
$this_page_number = 1;
}
$sql = "SELECT
lat_tbl.meta_value AS lat,
lng_tbl.meta_value AS lng,
$distance_select
posts.ID,
posts.post_content,
posts.post_title
FROM
$wpdb->posts AS posts
INNER JOIN
$wpdb->postmeta lat_tbl ON lat_tbl.post_id = posts.ID AND lat_tbl.meta_key = 'location_lat'
INNER JOIN
$wpdb->postmeta lng_tbl ON lng_tbl.post_id = posts.ID AND lng_tbl.meta_key = 'location_lng'
$taxonomy_join
WHERE
posts.post_type = 'sm-location'
AND posts.post_status = 'publish'
GROUP BY
posts.ID
$distance_having
ORDER BY " . apply_filters( 'sm-location-sort-order', $distance_order . ' posts.post_name ASC', $input ) . " " . $limit . " " . $offset;
$sql = apply_filters( 'sm-xml-search-locations-sql', $sql );
// TODO: Consider using this to generate the marker node attributes in print_xml().
$location_field_map = array(
'location_address' => 'address',
'location_address2' => 'address2',
'location_city' => 'city',
'location_state' => 'state',
'location_zip' => 'zip',
'location_country' => 'country',
'location_phone' => 'phone',
'location_fax' => 'fax',
'location_email' => 'email',
'location_url' => 'url',
'location_special' => 'special',
);
$options = $simple_map->get_options();
$show_permalink = !empty( $options['enable_permalinks'] );
if ( $locations = $wpdb->get_results( $sql ) ) {
// Start looping through all locations i found in the radius
foreach ( $locations as $key => $value ) {
// Add postmeta data to location
$custom_fields = get_post_custom( $value->ID );
foreach ( $location_field_map as $key => $field ) {
if ( isset( $custom_fields[$key][0] ) ) {
$value->$field = $custom_fields[$key][0];
}
else {
$value->$field = '';
}
}
$value->postid = $value->ID;
$value->name = apply_filters( 'the_title', $value->post_title );
$the_content = trim( $value->post_content );
if ( !empty( $the_content ) ) {
$the_content = apply_filters( 'the_content', $the_content );
}
$value->description = $the_content;
$value->permalink = '';
if ( $show_permalink ) {
$value->permalink = get_permalink( $value->ID );
$value->permalink = apply_filters( 'the_permalink', $value->permalink );
}
// List all terms for all taxonomies for this post
$value->taxes = array();
foreach ( $smtaxes as $taxonomy => $tax_value ) {
$phpsafe_tax = str_replace( '-', '_', $taxonomy );
$local_tax_names = '';
// Get all taxes for this post
if ( $local_taxes = wp_get_object_terms( $value->ID, $taxonomy, array( 'fields' => 'names' ) ) ) {
$local_tax_names = implode( ', ', $local_taxes );
}
$value->taxes[$phpsafe_tax] = $local_tax_names;
}
}
} else {
// Print empty XML
$locations = array();
}
$locations = apply_filters( 'sm-xml-search-locations', $locations );
$output = array('locations' => $locations, 'total_locations' => $total_locations, 'total_pages' => $total_pages, 'this_page' => $this_page_number);
$this->print_json( $output, $smtaxes );
}
}
// Prints the JSON output
function print_json( $dataset, $smtaxes ) {
header( 'Status: 200 OK', false, 200 );
header( 'Content-type: application/json' );
do_action( 'sm-xml-search-headers' );
do_action( 'sm-print-json', $dataset, $smtaxes );
echo json_encode( $dataset );
die();
}
}
}