Skip to content

Instantly share code, notes, and snippets.

@jmabbas
Last active October 8, 2026 12:30
Show Gist options
  • Select an option

  • Save jmabbas/a89259a0e8d5d9aa7955842bfe37c83b to your computer and use it in GitHub Desktop.

Select an option

Save jmabbas/a89259a0e8d5d9aa7955842bfe37c83b to your computer and use it in GitHub Desktop.
GoTrek - Search box input update
// 1. Ensure search query variables are registered
add_filter( 'query_vars', function( $vars ) {
$vars[] = 'location';
$vars[] = 'adults';
$vars[] = 'children';
$vars[] = 'rooms';
return $vars;
} );
// 2. Hook into the main WooCommerce product query
add_action( 'pre_get_posts', 'gotrek_serverside_hotel_filter', 20 );
function gotrek_serverside_hotel_filter( $query ) {
// Only modify main queries on the frontend catalog and product search
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
$post_type = $query->get( 'post_type' );
if ( 'product' !== $post_type && ! ( is_post_type_archive( 'product' ) || is_shop() ) ) {
return;
}
$location = sanitize_text_field( get_query_var( 'location', '' ) );
$adults = absint( get_query_var( 'adults', 0 ) );
$children = absint( get_query_var( 'children', 0 ) );
$rooms = absint( get_query_var( 'rooms', 0 ) );
// If no search parameters are present, leave standard catalog query untouched
if ( empty( $location ) && $adults === 0 && $children === 0 && $rooms === 0 ) {
return;
}
// A. Filter by Location (supports both ACF address map and text location)
if ( ! empty( $location ) ) {
$meta_query = (array) $query->get( 'meta_query' );
$meta_query[] = array(
'relation' => 'OR',
array(
'key' => 'hotel_group_location_map',
'value' => $location,
'compare' => 'LIKE',
),
array(
'key' => 'hotel_group_location',
'value' => $location,
'compare' => 'LIKE',
),
);
$query->set( 'meta_query', $meta_query );
}
// B. Filter by Guest & Room Capacity
if ( $adults > 0 || $children > 0 || $rooms > 0 ) {
$matching_ids = gotrek_get_matching_capacity_hotel_ids( $adults, $children, $rooms );
if ( ! empty( $matching_ids ) ) {
$existing_post_in = $query->get( 'post__in' );
if ( ! empty( $existing_post_in ) ) {
$matching_ids = array_intersect( $existing_post_in, $matching_ids );
}
$query->set( 'post__in', ! empty( $matching_ids ) ? $matching_ids : array( 0 ) );
} else {
// No hotels meet capacity -> return empty set cleanly
$query->set( 'post__in', array( 0 ) );
}
}
}
/**
* Helper: Query hotel products matching capacity requirements.
* Cached in transients to prevent database overhead.
*/
function gotrek_get_matching_capacity_hotel_ids( $req_adults, $req_children, $req_rooms ) {
$cache_key = sprintf( 'gotrek_cap_a%d_c%d_r%d', $req_adults, $req_children, $req_rooms );
$cached_ids = get_transient( $cache_key );
if ( false !== $cached_ids ) {
return $cached_ids;
}
$all_hotels = get_posts( array(
'post_type' => 'product',
'posts_per_page' => -1,
'post_status' => 'publish',
'fields' => 'ids',
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'hotel_group_rooms',
'compare' => 'EXISTS',
),
array(
'key' => 'room_group_max_adult',
'compare' => 'EXISTS',
),
),
) );
$matching_ids = array();
foreach ( $all_hotels as $product_id ) {
$hotel_rooms = get_post_meta( $product_id, 'hotel_group_rooms', true );
// Scenario 1: Parent Hotel with associated Rooms
if ( ! empty( $hotel_rooms ) && is_array( $hotel_rooms ) ) {
$rooms_count = count( $hotel_rooms );
$max_adults = 0;
$max_children = 0;
$total_adults = 0;
$total_children = 0;
foreach ( $hotel_rooms as $room ) {
$room_id = is_object( $room ) ? $room->ID : absint( $room );
$r_adults = 0;
$r_child = 0;
if ( function_exists( 'get_field' ) ) {
$rg = get_field( 'room_group', $room_id, false );
if ( is_array( $rg ) ) {
$r_adults = isset( $rg['max_adult'] ) ? absint( $rg['max_adult'] ) : 0;
$r_child = isset( $rg['max_children'] ) ? absint( $rg['max_children'] ) : 0;
}
}
if ( ! $r_adults ) {
$r_adults = absint( get_post_meta( $room_id, 'room_group_max_adult', true ) );
}
if ( ! $r_child ) {
$r_child = absint( get_post_meta( $room_id, 'room_group_max_children', true ) );
}
$total_adults += $r_adults;
$total_children += $r_child;
if ( $r_adults > $max_adults ) $max_adults = $r_adults;
if ( $r_child > $max_children ) $max_children = $r_child;
}
// Exceeds available rooms count
if ( $req_rooms > 0 && $rooms_count < $req_rooms ) {
continue;
}
// Single room request: check single room capacity
if ( $req_rooms === 1 ) {
if ( $req_adults > 0 && $req_adults > $max_adults ) continue;
if ( $req_children > 0 && $req_children > $max_children ) continue;
} else {
// Multi-room request: check total capacity
if ( $req_adults > 0 && $req_adults > $total_adults ) continue;
if ( $req_children > 0 && $req_children > $total_children ) continue;
}
$matching_ids[] = $product_id;
} else {
// Scenario 2: Direct standalone Room product
$r_adults = absint( get_post_meta( $product_id, 'room_group_max_adult', true ) );
$r_child = absint( get_post_meta( $product_id, 'room_group_max_children', true ) );
if ( $req_rooms > 1 ) continue;
if ( $req_adults > 0 && $req_adults > $r_adults ) continue;
if ( $req_children > 0 && $req_children > $r_child ) continue;
$matching_ids[] = $product_id;
}
}
set_transient( $cache_key, $matching_ids, HOUR_IN_SECONDS );
return $matching_ids;
}
// Invalidate cache when any hotel/room product is updated
add_action( 'save_post_product', function() {
global $wpdb;
$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_gotrek_cap_%' OR option_name LIKE '_transient_timeout_gotrek_cap_%'" );
} );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment