如何实现基于输入地址最近经纬度的求职板职位筛选展示
Got it, let's walk through how to implement this distance-based filtering for your WordPress job board—since you already have the lat/long data for both jobs and user inputs, you're halfway there! Here's how to tie everything together with Ajax Load More:
First, double-check that each job post has its latitude and longitude saved as custom fields (I’ll assume you’re using a custom post type like job). Let’s call these fields job_latitude and job_longitude—make sure these are populated for every job you want to include in distance filtering.
We’ll use the Haversine formula to compute the distance between the user’s location and each job. For large job datasets, calculating this directly in SQL is far more efficient than looping through posts in PHP. Let’s cover both approaches, but focus on the SQL method since it integrates cleanly with WordPress queries and Ajax Load More.
PHP Helper Function (for individual job display)
If you need to calculate distance for a single job in your template, use this:
function calculate_job_distance($user_lat, $user_lng, $job_lat, $job_lng) { $earth_radius = 6371; // Use 3956 for miles instead of kilometers $dLat = deg2rad($job_lat - $user_lat); $dLng = deg2rad($job_lng - $user_lng); $a = sin($dLat/2) * sin($dLat/2) + cos(deg2rad($user_lat)) * cos(deg2rad($job_lat)) * sin($dLng/2) * sin($dLng/2); $c = 2 * atan2(sqrt($a), sqrt(1-$a)); return round($earth_radius * $c, 1); // Returns distance rounded to 1 decimal place }
The core task here is modifying ALM’s query to sort jobs by distance, and passing the user’s lat/long from the frontend to the backend.
Frontend: Pass User Lat/Long to ALM
After retrieving the user’s lat/long from Google services, add these values to ALM’s query arguments before it fetches posts. Use ALM’s almBeforeFetch event to do this dynamically:
// Example: After getting user lat/long from Google Maps API const userLat = 40.7128; // Replace with actual user latitude const userLng = -74.0060; // Replace with actual user longitude // Hook into ALM's pre-fetch event to add our parameters jQuery(document).on('almBeforeFetch', function(event, alm) { alm.query_args.user_lat = userLat; alm.query_args.user_lng = userLng; // Optional: Add a max distance filter if you want users to set a range // alm.query_args.max_distance = jQuery('#distance-range').val(); });
Backend: Filter ALM’s Query to Sort by Distance
Add this to your theme’s functions.php or a custom plugin. It modifies the WordPress query to calculate distance via SQL and sort jobs by proximity:
add_action('alm_pre_get_posts', 'filter_jobs_by_proximity'); function filter_jobs_by_proximity($query) { global $wpdb; // Only run this for our job post type and if valid user lat/long exist if ( $query->get('post_type') !== 'job' || !isset($_GET['user_lat']) || !isset($_GET['user_lng']) || !is_numeric($_GET['user_lat']) || !is_numeric($_GET['user_lng']) ) { return; } $user_lat = floatval($_GET['user_lat']); $user_lng = floatval($_GET['user_lng']); $max_distance = isset($_GET['max_distance']) ? intval($_GET['max_distance']) : 100; // Default to 100km // Join postmeta tables to access job lat/long fields $query->query_vars['join'] .= " INNER JOIN $wpdb->postmeta AS pm_lat ON ($wpdb->posts.ID = pm_lat.post_id AND pm_lat.meta_key = 'job_latitude') INNER JOIN $wpdb->postmeta AS pm_lng ON ($wpdb->posts.ID = pm_lng.post_id AND pm_lng.meta_key = 'job_longitude') "; // Calculate distance in the query and add it as a custom field $query->query_vars['select'] .= ", (6371 * acos( cos(radians($user_lat)) * cos(radians(pm_lat.meta_value)) * cos(radians(pm_lng.meta_value) - radians($user_lng)) + sin(radians($user_lat)) * sin(radians(pm_lat.meta_value)) )) AS distance "; // Filter jobs within the max distance (optional) $query->query_vars['having'] = "distance <= $max_distance"; // Sort jobs from closest to farthest $query->set('orderby', 'distance'); $query->set('order', 'ASC'); }
This code ensures only jobs within your specified max distance are fetched, and they’re sorted by proximity.
In your Ajax Load More template (the file that renders each job), display the calculated distance like this:
<?php if (isset($post->distance)) : ?> <div class="job-distance"> <?php echo esc_html($post->distance); ?> km away </div> <?php endif; ?>
Or use the PHP helper function as a fallback:
<?php $user_lat = isset($_GET['user_lat']) ? floatval($_GET['user_lat']) : 0; $user_lng = isset($_GET['user_lng']) ? floatval($_GET['user_lng']) : 0; $job_lat = get_post_meta(get_the_ID(), 'job_latitude', true); $job_lng = get_post_meta(get_the_ID(), 'job_longitude', true); if ($job_lat && $job_lng && $user_lat && $user_lng) : $distance = calculate_job_distance($user_lat, $user_lng, $job_lat, $job_lng); ?> <div class="job-distance"> <?php echo esc_html($distance); ?> km away </div> <?php endif; ?>
- No user address input: The query will automatically skip distance filtering if
user_latoruser_lngare missing, keeping your default job sorting intact. - Missing job lat/long: The current
INNER JOINexcludes jobs without lat/long data. If you want to include them, switch toLEFT JOINand adjust the logic to handle null values. - Sanitization: We use
floatval()andintval()to sanitize user input, preventing SQL injection and invalid data issues.
Hope this gets your distance filtering up and running smoothly with your existing WordPress + Ajax Load More setup. Let me know if you hit any snags with query customization or ALM integration!
内容的提问来源于stack exchange,提问作者Logan C

