2
\$\begingroup\$

I am currently working on my first WordPress plugin. I display custom post types on a google map with pins. The custom post types also have additional information by ACF fields which are displayed in an info window on the marker. You can filter the pins on the map by a filter dropdown, which refers to the custom post types taxonomies.

I also created a WordPress backend page on which you can chose the custom post type to put out on the map and apply the google maps API key.

Apart from that I also added some features like resetting the map to the initial view after closing the info window or changing the category in the filter dropdown and a loading animation.

The plugin works quite well but before going live with it I would like so ask some experienced developers for help.

I would like to wrap my maps-script.js in an IIFE. How can I do that?

Do you see any critical error regarding WordPress plugin development I should take care of?

What could I do better in general?

Current demo of the plugin

plugin.php

<?php

function display_partner_posts_on_map()
{
    // Load the posts
    $args = [
        "post_type" => get_option("cpt_select"),
        "posts_per_page" => -1,
    ];
    $partner_posts = get_posts($args);

    // Load the map data for each post
    $map_data = [];
    foreach ($partner_posts as $post) {
        $map_field = get_field("karte", $post->ID);
        if ($map_field) {
            $map_data[] = [
                "lat" => $map_field["lat"],
                "lng" => $map_field["lng"],
                "title" => get_the_title($post->ID),
                "category" => wp_get_post_terms(
                    $post->ID,
                    "partner-kategorie",
                    [
                        "fields" => "names",
                    ]
                ),
                "logo" => get_field("logo", $post->ID),
                "adresse" => get_field("adresse", $post->ID),
                "telefon" => get_field("telefon", $post->ID),
                "email" => get_field("e-mail", $post->ID),
                "website" => get_field("website", $post->ID),
                "link" => get_permalink($post->ID),
            ];
        }
    }

    // Enqueue the Google Maps API
    wp_enqueue_script(
        "google-maps",
        "https://maps.googleapis.com/maps/api/js?key=" . get_option("api_key")
    );

    // Enqueue the partner-map script
    wp_enqueue_script(
        "map-script",
        plugin_dir_url(__FILE__) . "/maps-script.js",
        [],
        "1.0",
        true
    );
    wp_localize_script("map-script", "mapData", $map_data);

    // Print the filter dropdown menu
    $categories = get_terms("partner-kategorie");
    echo '<div id="partner-map-filters">';
    echo '<select onchange="filterPartnerMapMarkers(this.value)">';
    echo '<option value="all">Alle Partner</option>';
    foreach ($categories as $category) {
        echo '<option value="' .
            $category->name .
            '">' .
            $category->name .
            "</option>";
    }
    echo "</select>";
    echo "</div>";

    // Print loader
    echo '<div id="map-loading-spinner" class="loading-spinner"></div>';

    // Print the map container
    echo '<div id="partner-map"></div>';
}





// Generate Shortcode to display the map
add_shortcode("partner_map", "display_partner_posts_on_map");





// Add Stylesheet for Plugin
function custom_plugin_enqueue_styles()
{
    wp_enqueue_style(
        "custom-plugin-styles",
        plugin_dir_url(__FILE__) . "styles.css"
    );
}
add_action("wp_enqueue_scripts", "custom_plugin_enqueue_styles");





// Add Custom Backend Page for Plugin Settings
function custom_plugin_settings_page()
{
    ?>
    <div class="wrap">
        <h1>Orths Medien Google Maps Plugin Settings</h1>
        <form method="post" action="options.php">
            <?php
            settings_fields("api_key");
            do_settings_sections("custom-plugin");
            submit_button();
            ?>
        </form>
    </div>
    <hr>
<div class="wrap">
    <form method="post" action="options.php">
        <?php settings_fields("orths_medien_google_maps_settings"); ?>
        <?php do_settings_sections("orths_medien_google_maps_settings"); ?>
        <table class="form-table">
            <tr>
                <th scope="row">
                    <label for="cpt_select">Select CPT:</label>
                </th>
                <td>
                    <select name="cpt_select" id="cpt_select">
                        <?php
                        $args = [
                            "public" => true,
                            "_builtin" => false,
                        ];
                        $output = "names";
                        $operator = "and";
                        $post_types = get_post_types($args, $output, $operator);
                        foreach ($post_types as $post_type) {
                            echo '<option value="' .
                                $post_type .
                                '" ' .
                                selected(
                                    get_option("cpt_select"),
                                    $post_type,
                                    false
                                ) .
                                ">" .
                                $post_type .
                                "</option>";
                        }
                        ?>
                    </select>
                </td>
            </tr>
            <tr>
                <th scope="row">
                    <label for="tax_select">Select Taxonomies:</label>
                </th>
                <td>
                    <select name="tax_select" id="tax_select" multiple>
                        <?php
                        $taxonomies = get_taxonomies();
                        foreach ($taxonomies as $taxonomy) {
                            $tax = get_taxonomy($taxonomy);
                            echo '<option value="' .
                                $taxonomy .
                                '" ' .
                                selected(
                                    get_option("tax_select"),
                                    $taxonomy,
                                    false
                                ) .
                                ">" .
                                $tax->label .
                                "</option>";
                        }
                        ?>
                    </select>
                </td>
            </tr>
        </table>
        <?php submit_button(); ?>
    </form>
</div>
    <?php
}




function custom_plugin_add_settings_menu()
{
    add_options_page(
        "Orths Medien Maps",
        "Orths Medien Maps",
        "manage_options",
        "custom-plugin",
        "custom_plugin_settings_page"
    );
}
add_action("admin_menu", "custom_plugin_add_settings_menu");




function custom_plugin_display_api_key_element()
{
    ?>
    <input type="text" name="api_key" id="api_key" value="<?php echo get_option(
        "api_key"
    ); ?>" />
    <?php
}




function custom_plugin_settings_section_callback()
{
    echo __("Enter your Google Maps API key here", "custom-plugin");
}




function custom_plugin_settings_init()
{
    add_settings_section(
        "api_key",
        "API Key",
        "custom_plugin_settings_section_callback",
        "custom-plugin"
    );
    add_settings_field(
        "api_key",
        "API Key",
        "custom_plugin_display_api_key_element",
        "custom-plugin",
        "api_key"
    );
    register_setting("api_key", "api_key");
    register_setting("orths_medien_google_maps_settings", "cpt_select");
    register_setting("orths_medien_google_maps_settings", "tax_select");
}

add_action("admin_init", "custom_plugin_settings_init");

maps-script.js

// Define the global variables
let partnerMap
let initialMapCenter = {
    lat: 51.0480508,
    lng: 6.1584734
}
let initialMapZoom = 11
const partnerMapData = mapData
const partnerMapMarkers = []
const partnerMapInfoWindows = []

// Show the loading spinner before the map is initialized
document.getElementById('map-loading-spinner').style.display = 'block'

// Complete Initialize the map function
function initPartnerMap() {
        partnerMap = new google.maps.Map(document.getElementById('partner-map'), {
        center: initialMapCenter,
        zoom: initialMapZoom
    })

    // Add the markers to the map
    for (let i = 0; i < partnerMapData.length; i++) {
        const marker = new google.maps.Marker({
            position: {
                lat: partnerMapData[i].lat,
                lng: partnerMapData[i].lng
            },
            map: partnerMap,
            icon: {
                url: '/wp-content/plugins/orths-maps-plugin/img/map_icon.svg',
                scaledSize: new google.maps.Size(33, 33)
            },
            title: partnerMapData[i].title,
            category: partnerMapData[i].category
        })
        partnerMapMarkers.push(marker)

        // Create the info window for the marker
        const infoWindow = new google.maps.InfoWindow({
            content: '<div class="infofenster">' +
                '<img src="' + partnerMapData[i].logo + '" alt="Logo" class="popuplogo">' +
                '<h3>' + partnerMapData[i].title + '</h3>' +
                '<p>' + partnerMapData[i].adresse + '</p>' +
                '<p>' + partnerMapData[i].telefon + '<br>' + '<a href="mailto:' + partnerMapData[i].email + '">' + partnerMapData[i].email + '</a>' + '<br>' + '<a href="' + partnerMapData[i].website + '" target="_blank">' + partnerMapData[i].website + '</a>' + '</p>' +
                '<p><strong><a href="' + partnerMapData[i].link + '">Mehr Informationen</a></strong></p>' +
                '</div>'
        })
        partnerMapInfoWindows.push(infoWindow)

        // Add the info window to the marker
        marker.addListener('click', function() {
            // Close the open info window
            for (let i = 0; i < partnerMapInfoWindows.length; i++) {
                partnerMapInfoWindows[i].close()
            }

            const index = partnerMapMarkers.indexOf(this)
            partnerMapInfoWindows[index].open(partnerMap, this)

            // center the map on the marker
            partnerMap.panTo(this.getPosition())
            partnerMap.setZoom(14)
            partnerMap.panBy(0, -100)
        })

        function resetMap() {
            partnerMap.setCenter(initialMapCenter)
            partnerMap.setZoom(initialMapZoom)
        }

        // Zoom out to original position after closing window
        infoWindow.addListener('closeclick', function() {
            resetMap()
        })

        // Zoom out to original position when filter changes
        document.getElementById('partner-map-filters').addEventListener('change', function() {
            resetMap()
        })
    }

    // Load Kreis Heinsberg
    const kreisHeinsbergData = new google.maps.Data()
    kreisHeinsbergData.loadGeoJson('/wp-content/plugins/orths-maps-plugin/kreis-heinsberg.geojson')
    kreisHeinsbergData.setMap(partnerMap)

    // Customize the style of the overlay
    kreisHeinsbergData.setStyle({
        strokeColor: '#000000',
        strokeOpacity: 0.35,
        strokeWeight: 2,
        fillColor: '#000000',
        fillOpacity: 0.1,
        clickable: false
    })
}

// Close the loading spinner before the map is initialized
setTimeout(function() {
    document.getElementById('map-loading-spinner').style.display = 'none'
}, 800)



// Show the loading spinner before the filter is applied
document.getElementById('map-loading-spinner').style.display = 'block'

// Filter the markers by category
function filterPartnerMapMarkers(category) {
    for (var i = 0; i < partnerMapInfoWindows.length; i++) {
        partnerMapInfoWindows[i].close()
    }
    document.getElementById('map-loading-spinner').style.display = 'block'
    for (var i = 0; i < partnerMapMarkers.length; i++) {
        if (category === 'all' || partnerMapMarkers[i].category.indexOf(category) > -1) {
            partnerMapMarkers[i].setVisible(true)
        } else {
            partnerMapMarkers[i].setVisible(false)
        }
    }
    setTimeout(function() {
        document.getElementById('map-loading-spinner').style.display = 'none'
    }, 200)
}

window.addEventListener('load', initPartnerMap)
\$\endgroup\$
0

1 Answer 1

1
\$\begingroup\$

On maps-script.js i've seen a couple of setTimeout to hide and show the spinner element, you could create custom events and add listeners to them, so you don't need to wait more or less than needed.

const ShowSpinnerEvent = new CustomEvent('show_spinner')
const HideSpinnerEvent = new CustomEvent('hide_spinner')

const spinnerEl = document.getElementById('map-loading-spinner')
const showSpinner = () => { spinnerEl.style.display = 'block' }
const hideSpinner= () => { spinnerEl.style.display = 'none' }

spinnerEl.addEventListener(ShowSpinnerEvent, showSpinner)
spinnerEl.addEventListener(HideSpinnerEvent, hideSpinner)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.