• Resolved Oliver Gelbrich

    (@ogelbrich)


    hi!

    i’m trying to list all locations whose postcode starts with a specific number, e.g. “4” – postcodes in germany have 5 digits, so the list should display locations with the postcodes 40667, 41469 as well as 44892… so, all postcodes “4*”, basically.

    how would i hand over a wildcard like that to the list shortcode?
    [locations_list postcode=”4*”]
    does not give the desired result.

    i haven’t seen anything like this in the documentation or the forum.
    i appreciate any help you can give me…

    thanks!

    The page I need help with: [log in to see the link]

Viewing 9 replies - 1 through 9 (of 9 total)
  • You could use create your own shortcode which uses the em_locations_output_locations filter. Something like this:

    add_shortcode('my_locations_list', 'my_em_locations_list_func');
    function my_em_locations_list_func($args, $formats='') {
    global $em_postcode_re;
    $args = (array) $args;
    if (!empty($args['location_postcode'])) {
    $em_postcode_re = $args['location_postcode'];
    add_filter('em_locations_output_locations', 'my_em_locations_output_locations');
    }
    else {
    $em_postcode_re = null;
    }
    $ret = em_get_locations_list_shortcode($args, $formats);
    if ($em_postcode_re !== null) {
    remove_filter('em_locations_output_locations', 'my_em_locations_output_locations');
    }
    return $ret;
    }
    function my_em_locations_output_locations($locations) {
    $global $em_postcode_re;
    $new_locations = [];
    foreach ($locations as $EM_location) {
    if (!empty($EM_location->location_postcode) && preg_match('/^' . $em_postcode_re . '/', $EM_location->location_postcode ) ) {
    $new_locations[] = $EM_location;
    }
    }
    return $new_locations;
    }

    Then use the following shortcode:

    [my_locations_list location_postcode="4*"]

    The postcode attribute on the locations_list shortcode can have the value of true or false. Which tells it whether to search for events with locations.

    Actually the shortcode should look like this:

    [my_locations_list location_postcode="4[0-9]{4}"]

    The regular expression 4[0-9]{4} matches any five-digit number that starts with the digit 4

    Thread Starter Oliver Gelbrich

    (@ogelbrich)

    oooh, i am going to try this. thank you so much! πŸ™‚

    Thread Starter Oliver Gelbrich

    (@ogelbrich)

    hm. initial test failed, it returned

    Keine Veranstaltungsorte
    {4}β€œ]

    since the problem seemed to be the regex, i had chatGPT write that into the code, so that by entering location_postcode=”1″ it shows all locations whose 5-digit postcode begins with 1. this results in the following code:

    add_shortcode('my_locations_list', 'my_em_locations_list_func');

    function my_em_locations_list_func($args, $formats = '') {
    global $em_postcode_re;

    $args = (array) $args; // Ensure $args is an array

    if (!empty($args['location_postcode']) && ctype_digit($args['location_postcode']) && strlen($args['location_postcode']) === 1) {
    // Build regex to match a 5-digit postcode starting with the specified digit
    $em_postcode_re = '/^' . $args['location_postcode'] . '\d{4}$/';
    add_filter('em_locations_output_locations', 'my_em_locations_output_locations'); // Add the filter
    } else {
    $em_postcode_re = null;
    }

    $ret = em_get_locations_list_shortcode($args, $formats); // Call the locations list function

    if ($em_postcode_re !== null) {
    remove_filter('em_locations_output_locations', 'my_em_locations_output_locations'); // Remove the filter after use
    }

    return $ret;
    }

    function my_em_locations_output_locations($locations) {
    global $em_postcode_re;

    $new_locations = [];

    foreach ($locations as $EM_location) {
    // Ensure location_postcode exists and matches the 5-digit regex
    if (!empty($EM_location->location_postcode) && preg_match($em_postcode_re, $EM_location->location_postcode)) {
    $new_locations[] = $EM_location;
    }
    }

    return $new_locations;
    }

    this works, BUT not consistently: for input location_postcode=”0″ it produces a list of locations starting with any number. for input location_postcode=”4″ it produces no results even though there are many location that fit the postcode requirements. so i guess there’s something wrong with the way events calendar’s variables are parsed? i don’t understand.

    i’ve made a results page here that shows what happens for which input: https://padelfinder.de/feeds/

    • location_postcode=β€œ1β€³ returns 1 location, but there are at least 7
    • location_postcode=β€œ2β€³ returns 4, out of at least 11 that would match
    • location_postcode=β€œ4β€³ returns nothing, but there are at least 9 locations
    • location_postcode=β€œ0β€³ returns random locations that don’t seem to match at all

    does any of this make sense to you? i appreciate any help you might be able to give. thank you!

    πŸ™

    Thread Starter Oliver Gelbrich

    (@ogelbrich)

    update:
    adding limit=”999″ lists all matching locations.

    BUT location_postcode=β€œ0β€³ still returns random locations with postcodes starting with 0 up to 9, NOT limited to those starting with 0. huh.

    Thread Starter Oliver Gelbrich

    (@ogelbrich)

    alright! after an additional round of debugging, chatGPT comes up with this, which works fine with this kind of shortcode:

    [my_locations_list location_postcode="0"]



    this is the new script, in case anybody needs it:

    add_shortcode('my_locations_list', 'my_em_locations_list_func');

    function my_em_locations_list_func($args, $formats = '') {
    global $em_postcode_re;

    $args = (array) $args; // Ensure $args is an array

    // Force a high limit if not set, to ensure all locations are fetched
    if (!isset($args['limit']) || !ctype_digit((string) $args['limit'])) {
    $args['limit'] = '999';
    }

    if (isset($args['location_postcode']) && strlen($args['location_postcode']) === 1 && ctype_digit($args['location_postcode'])) {
    // Strict regex to match a 5-digit postcode starting with the specified digit (including 0)
    $em_postcode_re = '/^' . preg_quote($args['location_postcode'], '/') . '\d{4}$/';
    add_filter('em_locations_output_locations', 'my_em_locations_output_locations'); // Add the filter
    } else {
    $em_postcode_re = null; // Ensure it's null if invalid
    }

    $ret = em_get_locations_list_shortcode($args, $formats); // Call the locations list function

    if ($em_postcode_re !== null) {
    remove_filter('em_locations_output_locations', 'my_em_locations_output_locations'); // Remove the filter after use
    }

    return $ret;
    }

    function my_em_locations_output_locations($locations) {
    global $em_postcode_re;

    if (!$em_postcode_re) {
    return $locations; // No filtering needed if regex is null
    }

    $new_locations = [];

    foreach ($locations as $EM_location) {
    // Ensure location_postcode exists and strictly matches the regex
    if (!empty($EM_location->location_postcode) && preg_match($em_postcode_re, $EM_location->location_postcode)) {
    $new_locations[] = $EM_location;
    }
    }

    return $new_locations;
    }

    You don’t really need to use regular expressions for this. Here’s a simpler version:

    add_shortcode('my_locations_list', 'my_em_locations_list_func');

    function my_em_locations_list_func($args, $formats = '') {
    global $postcode_first_char;

    $args = (array) $args; // Ensure $args is an array

    // Force a high limit if not set, to ensure all locations are fetched
    if (!isset($args['limit']) || !ctype_digit((string) $args['limit'])) {
    $args['limit'] = '999';
    }

    if (isset($args['location_postcode']) && strlen($args['location_postcode']) === 1 && ctype_digit($args['location_postcode'])) {
    $postcode_first_char = $args['location_postcode'];
    add_filter('em_locations_output_locations', 'my_em_locations_output_locations'); // Add the filter
    } else {
    $postcode_first_char = null;
    }

    $ret = em_get_locations_list_shortcode($args, $formats); // Call the locations list function

    if ($postcode_first_char !== null) {
    remove_filter('em_locations_output_locations', 'my_em_locations_output_locations'); // Remove the filter after use
    }

    return $ret;
    }

    function my_em_locations_output_locations($locations) {
    global $postcode_first_char;

    if ($postcode_first_char === null) {
    return $locations;
    }

    $new_locations = [];

    foreach ($locations as $EM_location) {
    // Ensure location_postcode exists and the first char matches
    if (!empty($EM_location->location_postcode) && $EM_location->location_postcode[0] == $postcode_first_char) {
    $new_locations[] = $EM_location;
    }
    }

    return $new_locations;
    }
    • This reply was modified 1 year, 1 month ago by joneiseman.
    • This reply was modified 1 year, 1 month ago by joneiseman.
    Thread Starter Oliver Gelbrich

    (@ogelbrich)

    nice! simpler, more elegant and works like a charm – thank you!

    do you think I can use this placeholder thing to render a map of said locations?

    thank you for any ideas.

    I used ChatGPT to generate code to create a shortcode to put the locations on a map:

    function google_map_shortcode($atts) {
    // Extract attributes (if any)
    $atts = shortcode_atts(
    array(
    'width' => '100%',
    'height' => '500px',
    'scope' => 'all' // default scope for EM_Locations::get
    ),
    $atts,
    'google_map'
    );

    // Get markers data with $atts
    $markers = get_markers($atts);

    // Start output buffering
    ob_start();
    ?>
    <div id="map" style="height: <?php echo esc_attr($atts['height']); ?>; width: <?php echo esc_attr($atts['width']); ?>;"></div>

    <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>
    <script>
    function initMap() {
    // PHP array of markers
    var markers = <?php echo json_encode($markers); ?>;

    // Calculate the center of the map
    var latSum = 0;
    var lngSum = 0;
    for (var i = 0; i < markers.length; i++) {
    latSum += markers[i].coords.lat;
    lngSum += markers[i].coords.lng;
    }
    var centerLat = latSum / markers.length;
    var centerLng = lngSum / markers.length;

    // Map options
    var options = {
    zoom: 4,
    center: {lat: centerLat, lng: centerLng}
    };

    // New map
    var map = new google.maps.Map(document.getElementById('map'), options);

    // Loop through markers
    for(var i = 0; i < markers.length; i++){
    addMarker(markers[i]);
    }

    // Add Marker Function
    function addMarker(props){
    var marker = new google.maps.Marker({
    position: props.coords,
    map: map
    });

    // Check content
    if(props.content){
    var infoWindow = new google.maps.InfoWindow({
    content: props.content
    });

    marker.addListener('click', function(){
    infoWindow.open(map, marker);
    });
    }
    }
    }

    // Load map when page is ready
    document.addEventListener('DOMContentLoaded', function() {
    initMap();
    });
    </script>
    <?php
    // Return the buffered content
    return ob_get_clean();
    }

    // Register the shortcode
    add_shortcode('google_map', 'google_map_shortcode');

    // Function to get markers data from Events Manager locations
    function get_markers($atts) {
    $markers = [];

    // Check if the Events Manager plugin is active
    if (class_exists('EM_Locations')) {
    // Get locations based on attributes
    $em_locations = EM_Locations::get($atts);

    foreach ($em_locations as $location) {
    $lat = $location->location_latitude;
    $lng = $location->location_longitude;
    $content = '<h1>' . esc_html($location->location_name) . '</h1><a href="' . esc_url($location->get_permalink()) . '" target="_blank">More info</a>';

    $markers[] = [
    'coords' => ['lat' => (float) $lat, 'lng' => (float) $lng],
    'content' => $content
    ];
    }
    }

    return $markers;
    }

    Don’t forget to change YOUR_API_KEY to your actual Google API key.

Viewing 9 replies - 1 through 9 (of 9 total)

The topic ‘how can i list locations whose postcode starts with a specific number’ is closed to new replies.