File: /var/www/Gosurya/WP2/wp-content/themes/my-listing/includes/src/queries/explore-listings.php
<?php
namespace MyListing\Src\Queries;
class Explore_Listings extends Query {
use \MyListing\Src\Traits\Instantiatable;
public function __construct() {
add_action( 'mylisting_ajax_get_listings', [ $this, 'handle' ] );
add_action( 'mylisting_ajax_nopriv_get_listings', [ $this, 'handle' ] );
// @todo: use the custom ajax handler instead of wp_ajax
add_action( 'wp_ajax_get_listings', [ $this, 'handle' ] );
add_action( 'wp_ajax_nopriv_get_listings', [ $this, 'handle' ] );
}
/**
* Handle AJAX listing queries.
*
* @since 1.0.0
*/
public function handle() {
if ( apply_filters( 'mylisting/ajax-get-request-security-check', false ) === true ) {
check_ajax_referer( 'c27_ajax_nonce', 'security' );
}
$result = $this->run( $_GET );
wp_send_json( $result );
}
/**
* Handle Explore Listings requests, typically $_GET or $_POST.
* Request can be manually constructed, which allows using
* this function outside Ajax/POST context.
*
* @since 1.7.0
*/
public function run( $request ) {
global $wpdb;
if ( empty( $request['form_data'] ) || ! is_array( $request['form_data'] ) || empty( $request['listing_type'] ) ) {
return false;
}
if ( ! ( $listing_type_obj = ( get_page_by_path( $request['listing_type'], OBJECT, 'case27_listing_type' ) ) ) ) {
return false;
}
$type = new \MyListing\Src\Listing_Type( $listing_type_obj );
$form_data = $request['form_data'];
$starttime = microtime(true);
$page = absint( isset($form_data['page']) ? $form_data['page'] : 0 );
$per_page = absint( isset($form_data['per_page']) ? $form_data['per_page'] : c27()->get_setting('general_explore_listings_per_page', 9));
$orderby = sanitize_text_field( isset($form_data['orderby']) ? $form_data['orderby'] : 'date' );
$context = sanitize_text_field( isset( $form_data['context'] ) ? $form_data['context'] : 'advanced-search' );
$args = [
'order' => sanitize_text_field( isset($form_data['order']) ? $form_data['order'] : 'DESC' ),
'offset' => $page * $per_page,
'orderby' => $orderby,
'posts_per_page' => $per_page,
'tax_query' => [],
'meta_query' => [],
'fields' => 'ids',
'recurring_dates' => [],
];
$this->get_ordering_clauses( $args, $type, $form_data );
// Make sure we're only querying listings of the requested listing type.
if ( ! $type->is_global() ) {
$args['meta_query']['listing_type_query'] = [
'key' => '_case27_listing_type',
'value' => $type->get_slug(),
'compare' => '='
];
}
if ( $context === 'term-search' ) {
$taxonomy = ! empty( $form_data['taxonomy'] ) ? sanitize_text_field( $form_data['taxonomy'] ) : false;
$term = ! empty( $form_data['term'] ) ? sanitize_text_field( $form_data['term'] ) : false;
if ( ! $taxonomy || ! $term || ! taxonomy_exists( $taxonomy ) ) {
return false;
}
$tax_query_operator = apply_filters( 'mylisting/explore/match-all-terms', false ) === true ? 'AND' : 'IN';
$args['tax_query'][] = [
'taxonomy' => $taxonomy,
'field' => 'term_id',
'terms' => $term,
'operator' => $tax_query_operator,
'include_children' => $tax_query_operator !== 'AND',
];
// add support for nearby order in single term page
if ( isset( $form_data['proximity'], $form_data['lat'], $form_data['lng'] ) ) {
$proximity = absint( $form_data['proximity'] );
$location = isset( $form_data['search_location'] ) ? sanitize_text_field( stripslashes( $form_data['search_location'] ) ) : false;
$lat = (float) $form_data['lat'];
$lng = (float) $form_data['lng'];
$units = isset($form_data['proximity_units']) && $form_data['proximity_units'] == 'mi' ? 'mi' : 'km';
if ( $lat && $lng && $proximity && $location ) {
$earth_radius = $units == 'mi' ? 3959 : 6371;
$sql = $wpdb->prepare( \MyListing\Helpers::get_proximity_sql(), $earth_radius, $lat, $lng, $lat, $proximity );
$post_ids = (array) $wpdb->get_results( $sql, OBJECT_K );
if ( empty( $post_ids ) ) { $post_ids = ['none']; }
$args['post__in'] = array_keys( (array) $post_ids );
$args['search_location'] = '';
}
}
} else {
foreach ( (array) $type->get_advanced_filters() as $filter ) {
$args = $filter->apply_to_query( $args, $form_data );
}
}
$result = [];
$listing_wrap = ! empty( $request['listing_wrap'] ) ? sanitize_text_field( $request['listing_wrap'] ) : '';
$listing_wrap = apply_filters( 'mylisting/explore/listing-wrap', $listing_wrap );
/**
* Hook after the search args have been set, but before the query is executed.
*
* @since 1.7.0
*/
do_action_ref_array( 'mylisting/get-listings/before-query', [ &$args, $type, $result ] );
$listings = $this->query( $args );
if ( ! empty( $request['return_query'] ) ) {
return $listings;
}
ob_start();
if ( \MyListing\is_dev_mode() ) {
$result['args'] = $args;
$result['sql'] = $listings->request;
}
foreach ( (array) $listings->posts as $listing_id ) {
printf(
'<div class="%s">%s</div>',
$listing_wrap,
\MyListing\get_preview_card( $listing_id )
);
}
$result['html'] = ob_get_clean();
wp_reset_postdata();
// Generate pagination
$result['pagination'] = c27()->get_listing_pagination( $listings->max_num_pages, ($page + 1) );
$result['found_posts'] = absint( $listings->found_posts );
if ( $result['found_posts'] < 1 ) {
$result['showing'] = __( 'No results', 'my-listing' );
} elseif ( $result['found_posts'] === 1 ) {
$result['showing'] = __( 'Showing <b>1</b> result', 'my-listing' );
} elseif ( $result['found_posts'] <= $per_page ) {
$result['showing'] = sprintf( __( 'Showing <b>%d</b> results', 'my-listing' ), $result['found_posts'] );
} else {
$result['showing'] = sprintf(
__( 'Showing <b>%d</b> results out of <b>%s</b>', 'my-listing'),
$listings->post_count,
number_format_i18n( $result['found_posts'] )
);
}
if ( \MyListing\is_dev_mode() ) {
$result['timing'] = sprintf( '%sms', round( ( microtime(true) - $starttime ) * 1000 ) );
}
$result['max_num_pages'] = $listings->max_num_pages;
return $result;
}
/**
* Generate the 'orderby' argument, allowing for custom 'orderby' clauses.
*
* @since 1.6.0
*/
public function get_ordering_clauses( &$args, $type, $form_data ) {
$options = (array) $type->get_ordering_options();
$sortby = ! empty( $form_data['sort'] ) ? sanitize_text_field( $form_data['sort'] ) : false;
if ( empty( $options ) ) {
return false;
}
// default to the first ordering option
if ( empty( $sortby ) ) {
$sortby = $options[0]['key'];
}
if ( ( $key = array_search( $sortby, array_column( $options, 'key' ) ) ) === false ) {
return false;
}
$option = $options[$key];
$clauses = $option['clauses'];
$orderby = [];
foreach ( $clauses as $clause ) {
if ( empty( $clause['context'] ) || empty( $clause['orderby'] ) || empty( $clause['order'] ) || empty( $clause['type'] ) ) {
continue;
}
$clause_hash = substr( md5( json_encode( $clause ) ), 0, 16 );
$clause_id = sprintf( 'clause-%s-%s', $option['key'], $clause_hash );
if ( $clause['context'] === 'option' ) {
if ( $clause['orderby'] === 'rand' ) {
// Randomize every 3 hours.
$seed = apply_filters( 'mylisting/explore/rand/seed', floor( time() / 10800 ) );
$orderby[ "RAND({$seed})" ] = $clause['order'];
} elseif ( $clause['orderby'] === 'rating' ) {
add_filter( 'posts_join', [ $this, 'rating_field_join' ], 35, 2 );
add_filter( 'posts_orderby', [ $this, 'rating_field_orderby' ], 35, 2 );
$args['mylisting_orderby_rating'] = $clause['order']; // Note the custom order to $args, so it's cached properly.
$orderby[ $clause_id ] = []; // Add a dummy orderby, to override the default one.
} elseif ( $clause['orderby'] === 'proximity' ) {
$orderby = 'post__in';
add_filter( 'mylisting/explore/args', function( $args ) use ( $clause ) {
// Support descending order for distance/proximity.
if ( $clause['order'] === 'DESC' && ! empty( $args['post__in'] ) ) {
$args['post__in'] = array_reverse( $args['post__in'] );
}
return $args;
} );
} elseif ( $clause['orderby'] === 'relevance' ) {
// order by relevance only works when there's a single 'orderby' clause,
// and if that's passed as a string instead of an array
$orderby = 'relevance';
} else {
$orderby[ $clause['orderby'] ] = $clause['order'];
}
}
if ( $clause['context'] === 'meta_key' ) {
$field = $type->get_field( $clause['orderby'] );
if ( $field && $field->get_type() === 'recurring-date' ) {
// if a recurring date filter isn't present, join the events table
// and filter listings with the start date set to the current date
// so that only future events are shown by default
$args['recurring_dates'][ $field->get_key() ] = [
'start' => date('Y-m-d H:i:s', current_time('timestamp')),
'end' => '',
'orderby' => true,
'order' => $clause['order'],
'where_clause' => false,
];
$orderby[ $clause_id ] = []; // Add a dummy orderby, to override the default one.
} else {
$args['meta_query'][ $clause_id ] = [
'key' => '_' . $clause['orderby'],
'compare' => 'EXISTS',
'type' => $clause['type'],
];
$orderby[ $clause_id ] = $clause['order'];
}
}
if ( $clause['context'] === 'raw_meta_key' ) {
$args['meta_query'][ $clause_id ] = [
'key' => $clause['orderby'],
'compare' => 'EXISTS',
'type' => $clause['type'],
];
$orderby[ $clause_id ] = $clause['order'];
}
}
if ( ! empty( $orderby ) ) {
$args['orderby'] = $orderby;
if ( isset( $args['order'] ) ) {
unset( $args['order'] );
}
// Ignore order by priority if set.
if ( ! empty( $option['ignore_priority'] ) ) {
$args['mylisting_ignore_priority'] = true;
add_filter( 'mylisting/explore/listing-wrap', function( $wrap ) {
$wrap .= ' hide-priority';
return $wrap;
} );
}
}
// dd($clauses, $option);
// dd($args, $orderby);
}
}