I'm trying to edit a wp_query
in WordPress using the add_filter
function. When I var_dump
my query request
it outputs the SQL as expected.
However, when it runs it returns an error with a different query! Does anyone know why the query might change, and change so much!
Query from the request
var_dump
(as expected):
SELECT SQL_CALC_FOUND_ROWS wp_posts.*,
( 3959 * acos(
cos( radians(52.486243) )
* cos( radians( lat ) )
* cos( radians( lng ) - radians(-1.890401) )
+ sin( radians(52.486243) )
* sin( radians( lat ) )
) )
AS distance , lat AS latitude , lng AS longitude
FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN lat_lng_post ON wp_posts.ID = lat_lng_post.post_id
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id IN (2) )
AND wp_posts.post_type = 'event'
AND ((wp_posts.post_status = 'publish'))
AND ( (wp_postmeta.meta_key LIKE 'date_%_start-date' AND CAST(wp_postmeta.meta_value AS SIGNED) <= '20140704')
AND (mt1.meta_key LIKE 'date_%_end-date' AND CAST(mt1.meta_value AS SIGNED) >= '20140627') )
AND lat_lng_post.lat = lat
AND lat_lng_post.lng = lng
AND substr(wp_postmeta.meta_key, 1, 6) = substr(mt1.meta_key, 1, 6)
GROUP BY wp_posts.ID
HAVING distance <= 20
ORDER BY distance ASC
LIMIT 0, 10
And this is the query that shows below the error [Unknown column 'lat' in 'field list']
(not expected):
SELECT wp_posts.*,
( 3959 * acos(
cos( radians(52.486243) )
* cos( radians( lat ) )
* cos( radians( lng ) - radians(-1.890401) )
+ sin( radians(52.486243) )
* sin( radians( lat ) )
) ) AS distance , lat AS latitude , lng AS longitude
FROM wp_posts
WHERE 1=1
AND wp_posts.post_type = 'acf-field'
AND ((wp_posts.post_status = 'publish'))
AND wp_posts.post_name = 'field_535e6b9ffe3da'
AND lat_lng_post.lat = lat
AND lat_lng_post.lng = lng
GROUP BY wp_posts.ID
HAVING distance <= 20
ORDER BY distance ASC
LIMIT 0, 1
NOTE
I have a custom table called lat_lng_post
which has three columns, post_id
, lat
, lng
to store location data for each event (custom post type).
EDIT all add_filter functions being used on the query:
function distance_query($distance) {
$lat = $_SESSION['search']['lat'];
$lng = $_SESSION['search']['long'];
$distance .= ",
( 3959 * acos(
cos( radians(".$lat.") )
* cos( radians( lat ) )
* cos( radians( lng ) - radians(".$lng.") )
+ sin( radians(".$lat.") )
* sin( radians( lat ) )
) )
AS distance , lat AS latitude , lng AS longitude";
return $distance;
}
add_filter('posts_fields', 'distance_query');
// add lat_lng_post table inner join
function lat_lng_join($join) {
$join = str_replace('(wp_posts.ID = mt1.post_id)', '(wp_posts.ID = mt1.post_id) INNER JOIN lat_lng_post ON wp_posts.ID = lat_lng_post.post_id', $join);
return $join;
}
add_filter('posts_join', 'lat_lng_join');
// set lat lng definition
function lat_lng_define($define) {
$define .= ' AND lat_lng_post.lat = lat AND lat_lng_post.lng = lng';
return $define;
}
add_filter('posts_where', 'lat_lng_define');
// HAVING distance less than user distance
function having_distance($having) {
$radius = $_SESSION['search']['distance'];
$having = 'wp_posts.ID HAVING distance <= '.$radius.'';
return $having;
}
add_filter('posts_groupby', 'having_distance');
// if sorting by distance
function sort_distance($sortdistance) {
$sortdistance = 'distance ASC';
return $sortdistance;
}
if( $_SESSION['search']['sort-by'] == 'distance' ) :
add_filter('posts_orderby', 'sort_distance');
endif;
function add_additional_where_condition($where) {
$where .= " AND substr(wp_postmeta.meta_key, 1, 6) = substr(mt1.meta_key, 1, 6) ";
return $where;
}
// fix for setting the date to search field
function date_to( $to ) {
$to = str_replace("mt1.meta_key = 'date_%_end-date'", "mt1.meta_key LIKE 'date_%_end-date'", $to);
return $to;
}
// fix for setting the date from search field
function date_from( $from ) {
$from = str_replace("meta_key = 'date_%_start-date'", "meta_key LIKE 'date_%_start-date'", $from);
return $from;
}
// fix for ordering by date
function order_date( $like ) {
$like = str_replace("mt2.meta_key = 'date_%_end-date'", "mt2.meta_key LIKE 'date_%_end-date'", $like);
return $like;
}
// fix for searching by LIKE post title, requires all characters to match
function title_filter( $where, &$wp_query ) {
global $wpdb;
if ( $search_term = $wp_query->get( 'title_like' ) ) {
$where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . esc_sql( like_escape( $search_term ) ) . '%\'';
}
return $where;
}
Also, this is the wp_query
itself that these functions are being added to:
// add query for title
add_filter( 'posts_where', 'title_filter', 10, 2 );
// dates to and from logic
add_filter('posts_where', 'date_from');
add_filter('posts_where', 'date_to');
add_filter('posts_where', 'order_date');
add_filter('posts_where', 'add_additional_where_condition');
// get date inputs from search
$date1 = str_replace('/', '-', $_SESSION['search']['from']);
$when = date("Ymd", strtotime($date1));
$date2 = str_replace('/', '-', $_SESSION['search']['to']);
$when2 = date("Ymd", strtotime($date2));
$year = date('Y');
// Declare the query arguments
if ( get_query_var('paged') ) {
$paged = get_query_var('paged');
} else if ( get_query_var('page') ) {
$paged = get_query_var('page');
} else {
$paged = 1;
}
// make keywords an array
$keywordString = $_SESSION['search']['keyword'];
$keywords = explode(', ', $keywordString);
$taxQuery = array(
'relation' => 'AND',
array (
'taxonomy' => 'main-cat',
'field' => 'slug',
'terms' => $_SESSION['search']['cat']
)
);
if( $_SESSION['search']['keyword'] != '' ) {
$taxQuery[] = array(
'taxonomy' => 'sub-cat',
'field' => 'name',
'terms' => $keywords
);
}
$args = array(
// general
'post_type' => 'event',
'post_status' => 'publish',
'posts_per_page' => 10,
'paged' => $paged,
'cache_results' => false,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'meta_key' => $_SESSION['search']['sort-key'],
'orderby' => $_SESSION['search']['sort-by'],
'order' => 'ASC',
// category filter
'tax_query' => $taxQuery,
// date filter
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'date_%_start-date',
'value' => $when2,
'compare' => '<=',
'type' => 'NUMERIC'
),
array (
'key' => 'date_%_end-date',
'value' => $when,
'compare' => '>=',
'type' => 'NUMERIC'
)
)
);
$temp = $wp_query;
$wp_query = null;
$wp_query = new WP_Query( $args );
It looks like you're trying to setup up posts_*
filters for a secondary query, but you forget to remove the filters afterwards, so they are affecting other queries that run later.
i) You can remove a filter with the remove_filter()
function. Here's an example :
// Add some filter:
add_filter( 'some_filter', 'some_filter_callback', $priority );
// Run a secondary query:
$wp_query = new WP_Query( $args );
// Remove the previous filter:
remove_filter( 'some_filter', 'some_filter_callback', $priority );
where the filter priority must match.
ii) Another way would be to use add the remove_filter()
inside the some_filter_callback()
function. For example:
add_filter( 'some_filter', 'some_filter_callback' );
$wp_query = new WP_Query( $args );
where
some_filter_callback( $string )
{
// Remove the current filter:
remove_filter( current_filter(), __FUNCTION__ );
// Some modifications to the input:
// ...
// Output:
return $string;
}
This will make sure your filter will only run once.
iii) If you're trying to modify the main query, you can restrict the filter with:
if( ! is_admin() && is_main_query() )
{
// ...
}
or
if( ! is_admin() && $query->is_main_query() )
{
// ...
}
if you're using the pre_get_posts
hook, where $query
is the input argument.
iv) Another option would be to create a new class that extends the WP_Query
and contains all the filters you want:
class My_Search_Query extends WP_Query
{
// ...
}
where you use
$query = new My_Search_Query( $args );
to run the query.