Last active
March 26, 2025 16:09
-
-
Save unwiredtech/06a312e84a4001c004e72070782e2861 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /* | |
| • A fully hierarchical, cascading search form | |
| • AJAX populates States based on selected Workspace Type | |
| • Then populates Cities based on selected State + Type | |
| • Searches and returns locations filtered by all 3 levels | |
| */ | |
| function workspace_search_form_shortcode() { | |
| ob_start(); | |
| ?> | |
| <form id="workspace-search-form"> | |
| <select name="workspace_type" id="workspace_type"> | |
| <option value="">Select Workspace Type</option> | |
| <?php | |
| $workspace_types = get_terms([ | |
| 'taxonomy' => 'location-workspace-types', | |
| 'hide_empty' => false | |
| ]); | |
| foreach ($workspace_types as $type) { | |
| echo '<option value="' . esc_attr($type->term_id) . '">' . esc_html($type->name) . '</option>'; | |
| } | |
| ?> | |
| </select> | |
| <select name="state" id="state" disabled> | |
| <option value="">Select State</option> | |
| </select> | |
| <select name="city" id="city" disabled> | |
| <option value="">Select City</option> | |
| </select> | |
| <button type="submit">Search</button> | |
| </form> | |
| <div id="workspace-search-results"></div> | |
| <script> | |
| const ajaxUrl = "<?php echo admin_url('admin-ajax.php'); ?>"; | |
| document.addEventListener('DOMContentLoaded', () => { | |
| const workspaceSelect = document.getElementById('workspace_type'); | |
| const stateSelect = document.getElementById('state'); | |
| const citySelect = document.getElementById('city'); | |
| workspaceSelect.addEventListener('change', function () { | |
| const val = this.value; | |
| stateSelect.innerHTML = '<option>Loading...</option>'; | |
| citySelect.innerHTML = '<option>Select City</option>'; | |
| citySelect.disabled = true; | |
| if (!val) { | |
| stateSelect.innerHTML = '<option>Select State</option>'; | |
| stateSelect.disabled = true; | |
| return; | |
| } | |
| fetch(ajaxUrl + '?action=get_states_by_workspace_type&term_id=' + val) | |
| .then(res => res.json()) | |
| .then(data => { | |
| stateSelect.innerHTML = '<option value="">Select State</option>'; | |
| data.forEach(item => { | |
| stateSelect.innerHTML += `<option value="${item.id}">${item.name}</option>`; | |
| }); | |
| stateSelect.disabled = false; | |
| }); | |
| }); | |
| stateSelect.addEventListener('change', function () { | |
| const stateId = this.value; | |
| const workspaceId = workspaceSelect.value; | |
| if (!stateId || !workspaceId) return; | |
| citySelect.innerHTML = '<option>Loading...</option>'; | |
| citySelect.disabled = true; | |
| fetch(ajaxUrl + '?action=get_cities_by_state&workspace_type=' + workspaceId + '&state_id=' + stateId) | |
| .then(res => res.json()) | |
| .then(data => { | |
| citySelect.innerHTML = '<option value="">Select City</option>'; | |
| data.forEach(item => { | |
| citySelect.innerHTML += `<option value="${item.id}">${item.name}</option>`; | |
| }); | |
| citySelect.disabled = false; | |
| }); | |
| }); | |
| const form = document.getElementById('workspace-search-form'); | |
| form.addEventListener('submit', function (e) { | |
| e.preventDefault(); | |
| const data = new FormData(form); | |
| data.append('action', 'workspace_search'); | |
| fetch(ajaxUrl, { | |
| method: 'POST', | |
| body: data | |
| }) | |
| .then(res => res.text()) | |
| .then(html => { | |
| document.getElementById('workspace-search-results').innerHTML = html; | |
| }); | |
| }); | |
| }); | |
| </script> | |
| <?php | |
| return ob_get_clean(); | |
| } | |
| add_shortcode('workspace_search_form', 'workspace_search_form_shortcode'); | |
| add_action('wp_ajax_get_states_by_workspace_type', 'get_states_by_workspace_type'); | |
| add_action('wp_ajax_nopriv_get_states_by_workspace_type', 'get_states_by_workspace_type'); | |
| function get_states_by_workspace_type() { | |
| $term_id = intval($_GET['term_id']); | |
| $location_ids = get_posts([ | |
| 'post_type' => 'locations', | |
| 'posts_per_page' => -1, | |
| 'fields' => 'ids', | |
| 'tax_query' => [ | |
| [ | |
| 'taxonomy' => 'location-workspace-types', | |
| 'field' => 'term_id', | |
| 'terms' => $term_id | |
| ] | |
| ] | |
| ]); | |
| $terms = wp_get_object_terms($location_ids, 'cities-states', [ | |
| 'parent' => 0, | |
| 'fields' => 'all' | |
| ]); | |
| $unique_terms = []; | |
| foreach ($terms as $term) { | |
| $unique_terms[$term->term_id] = [ | |
| 'id' => $term->term_id, | |
| 'name' => $term->name | |
| ]; | |
| } | |
| wp_send_json(array_values($unique_terms)); | |
| } | |
| add_action('wp_ajax_get_cities_by_state', 'get_cities_by_state'); | |
| add_action('wp_ajax_nopriv_get_cities_by_state', 'get_cities_by_state'); | |
| function get_cities_by_state() { | |
| $workspace_type = intval($_GET['workspace_type']); | |
| $state_id = intval($_GET['state_id']); | |
| $location_ids = get_posts([ | |
| 'post_type' => 'locations', | |
| 'posts_per_page' => -1, | |
| 'fields' => 'ids', | |
| 'tax_query' => [ | |
| [ | |
| 'taxonomy' => 'location-workspace-types', | |
| 'field' => 'term_id', | |
| 'terms' => $workspace_type | |
| ], | |
| [ | |
| 'taxonomy' => 'cities-states', | |
| 'field' => 'term_id', | |
| 'terms' => get_term_children($state_id, 'cities-states') | |
| ] | |
| ] | |
| ]); | |
| $terms = wp_get_object_terms($location_ids, 'cities-states', [ | |
| 'parent' => $state_id, | |
| 'fields' => 'all' | |
| ]); | |
| $unique_terms = []; | |
| foreach ($terms as $term) { | |
| $unique_terms[$term->term_id] = [ | |
| 'id' => $term->term_id, | |
| 'name' => $term->name | |
| ]; | |
| } | |
| wp_send_json(array_values($unique_terms)); | |
| } | |
| add_action('wp_ajax_workspace_search', 'handle_workspace_search'); | |
| add_action('wp_ajax_nopriv_workspace_search', 'handle_workspace_search'); | |
| function handle_workspace_search() { | |
| $workspace_type = intval($_POST['workspace_type']); | |
| $state = intval($_POST['state']); | |
| $city = intval($_POST['city']); | |
| $args = [ | |
| 'post_type' => 'locations', | |
| 'posts_per_page' => -1, | |
| 'tax_query' => [ | |
| 'relation' => 'AND', | |
| [ | |
| 'taxonomy' => 'location-workspace-types', | |
| 'field' => 'term_id', | |
| 'terms' => [$workspace_type], | |
| ], | |
| [ | |
| 'taxonomy' => 'cities-states', | |
| 'field' => 'term_id', | |
| 'terms' => [$city], | |
| ] | |
| ] | |
| ]; | |
| $query = new WP_Query($args); | |
| if ($query->have_posts()) { | |
| echo '<ul>'; | |
| while ($query->have_posts()) { | |
| $query->the_post(); | |
| echo '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>'; | |
| } | |
| echo '</ul>'; | |
| } else { | |
| echo '<p>No results found.</p>'; | |
| } | |
| wp_reset_postdata(); | |
| wp_die(); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment