Saw a JetSmartFilters bug reported by a friend in Crocoblock Facebook group recently. Quite interesting and I did a test by myself. It’s true and I will provide a temporary solution in this short guide.
Please note that the JetSmartFilters version is v2.3.12 while I am writing this article. This might be not relevant anymore in future version.
Issue / Bug
If we setup a new filter where Filter Type as range and Get min/max dynamically to Get from query meta key. The range filter will automatically query the postmeta table and get the minimum and maximum value for the meta key, then display as min max range in frontend.
However, if some of the posts status set as draft or pending, the range filter still doing the same without excluding them. So this might cause the visitor get a no data result when using the range filter in frontend. No point to remove our draft post just to make it right in frontend correct? Let’s fix this ourselves while waiting Crocoblock releases the actual fix.
Solution: PHP Snippet
Luckily JetSmartFilters providing a filter hook for us to overwrite the min / max arguments. jet-smart-filters/filter-instance/args
saving us!
<?php
add_filter( 'jet-smart-filters/filter-instance/args', 'itchycode_get_minmax_for_publish_post_range', 20, 2);
function itchycode_get_minmax_for_publish_post_range( $args, $filter_instance ) {
/**
* $filter_instance->filter_id is the filter id itself in backend
* $source_cb will only got 2 possiblity for now, "jet_smart_filters_woo_prices" if you choose "WooCommer min/max price" or "jet_smart_filters_meta_values" if you choose "Get from query meta key"
* $query_var is the Query Variable you set in the filter settings
*/
$source_cb = get_post_meta( $filter_instance->filter_id, '_source_callback', true );
$query_var = get_post_meta( $filter_instance->filter_id, '_query_var', true );
/**
* We only target if the filter is "range" type and "Get from query meta key" for Get min/max dynamically setting
*/
if(
!$query_var ||
'jet_smart_filters_meta_values' != $source_cb ||
'range' !== $filter_instance->type->get_id()
) return $args;
/**
* Majority follow the original function of Jet Smart Filters.
* Not good in performance wise since we query the database 1 more time.
* jet_smart_filters_meta_values()
*/
global $wpdb;
$queried_object = get_queried_object();
$tax_query = array();
if ( ! empty( $queried_object->taxonomy ) && ! empty( $queried_object->term_id ) ) {
$tax_query[] = array(
'taxonomy' => $queried_object->taxonomy,
'terms' => array( $queried_object->term_id ),
'field' => 'term_id',
);
}
$tax_query = new WP_Tax_Query( $tax_query );
$tax_query_sql = $tax_query->get_sql( $wpdb->postmeta, 'post_id' );
/**
* Only change in this SQL statement.
* Left join the posts table and only get the "publish" posts.
*
*/
$sql = "SELECT min( FLOOR( meta_value ) ) as min, max( CEILING( meta_value ) ) as max FROM $wpdb->postmeta";
$sql .= " LEFT JOIN {$wpdb->posts} as posts ON {$wpdb->postmeta}.post_id = posts.ID " . $tax_query_sql['join'];
$sql .= " WHERE `meta_key` IN ('" . str_replace( ',', '\',\'', str_replace( ' ', '', $query_var ) ) . "') AND posts.post_status = 'publish' ";
$sql .= $tax_query_sql['where'];
$data = $wpdb->get_row( $sql, ARRAY_A );
/**
* If no result, return the original args.
*/
if ( !empty( $data ) ) {
$args['min'] = ( isset( $data['min'] ) ) ? $data['min'] : $args['min'];
$args['max'] = ( isset( $data['max'] ) ) ? $data['max'] : $args['max'];
}
return $args;
}
?>
Basically, I just reuse the same method by Crocoblock team, just added a left join to get the post status on line 50 – 51. Just amend it to fit your needs. And yup, as per my comment, this is not the best way because we did query the database 1 more time after the original jet_smart_filters_meta_values()
method. For line 31 – 41, I really got no idea yet for now, should be useful for taxonomy range filter, and I do not want to remove it just afraid it will break your rules.
Action & Filter hooks used in this tutorial:
jet-smart-filters/filter-instance/args