Loading Google Maps

This HowTo guide describes a solution for loading Google Maps in the pro version. It allows the visitor to the website to decide whether they want Google Maps to load or not.

Here Google Maps scripts are loaded only after the user has consented and their decision is stored in a cookie. The user sees a button where the map would be. Once they have clicked on the button they will see a data protection notice with a link to the Google Maps data protection declaration. The user must confirm their consent by activating a checkbox and clicking on the "load map" button.

The page is then reloaded with the corresponding Google Maps scripts.

Integrate as follows:

  1. A constant is defined which allows an integrator to activate the functionality. The following TypoScript is required to configure the constant.
# customcategory=tracking=tracking
themes.configuration.tracking {
    # customsubcategory=tracking_googlemap_alert=Google Map Alert
    googleMaps {
        # cat=tracking/tracking_googlemap_alert/10; type=options[0,1]; label= Google Map Alert: Show Button to load Google Maps
        active = 0
    }
}

The constant is also available in the Page Settings in Setup TypoScript. This allows the constant to be set via the frontend.

page.10.settings.tracking.googleMaps {
    active = {$themes.configuration.tracking.googleMaps.active}
}

Node 10 is the configuration of your fluid template.

page.10 = FLUIDTEMPLATE
  1. Integrate the placeholders and the data protection information. You will need to create a new Partial and add/modify language labels for the text.

Language file: typo3conf\ext\my_sitepackage_theme\Resources\Private\Language\locallang.xlf

<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.0">
    <file source-language="en" datatype="plaintext" original="messages"
          date="2020-11-16T00:00:00Z" product-name="my_sitepackage_theme">
        <header/>
        <body>
            <trans-unit id="maps_btn_label" xml:space="preserve">
                <source>Karte laden</source>
            </trans-unit>
            <trans-unit id="maps_modal_title" xml:space="preserve">
                <source>Google Map laden</source>
            </trans-unit>
            <trans-unit id="maps_modal_text_heading" xml:space="preserve">
                <source>Datenschutzhinweis</source>
            </trans-unit>
            <trans-unit id="maps_modal_text" xml:space="preserve">
                <source>Wenn Sie die Map  auf dieser Seite sehen möchten, werden personenbezogene Daten an den Betreiber der Map gesendet und ein Cookie durch den Betreiber gesetzt. Daher ist es möglich, dass der Anbieter Ihre Zugriffe speichert und Ihr Verhalten analysieren kann. Die Datenschutzerklärung von Google Maps finden Sie unter: </source>
            </trans-unit>
            <trans-unit id="maps_modal_text_small" xml:space="preserve">
                <source>Bitte beachten Sie, dass nach Ihrer Zustimmung diese Seite neu geladen wird. Formular-Angaben gehen dabei ggf. verloren.</source>
            </trans-unit>
            <trans-unit id="maps_modal_checkbox_label" xml:space="preserve">
                <source>Ich akzeptiere die Datenschutz-Bedingungen und möchte die Map jetzt laden.</source>
            </trans-unit>
            <trans-unit id="maps_modal_btn_label" xml:space="preserve">
                <source>Karte laden</source>
            </trans-unit>
        </body>
    </file>
</xliff>

Fluid Partial: typo3conf\ext\my_sitepackage_theme\Resources\Private\Partials\Elements\GoogleMaps.html

<div xmlns="http://www.w3.org/1999/xhtml" lang="en"
     xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
    <f:section name="Default">
        <!-- my_sitepackage_theme: Partials/GoogleMaps.html [begin] -->

        <div class="google-maps-alert d-none">
            <div class="map-placeholder">
                <div class="d-flex flex-wrap justify-content-center align-items-center bg bg-light w-100 h-100"
                     style="min-height: 200px;">
                    <button type="button"
                            class="btn btn-primary btn-map-modal"
                            data-toggle="modal"
                            data-target="#google-map-modal"
                            title="{f:translate(key: 'maps_btn_label', extensionName: 'my_sitepackage_theme')}">
                        <f:translate key="maps_btn_label" extensionName="my_sitepackage_theme" />
                    </button>
                </div>
            </div>
        </div>

        <div class="modal" tabindex="-1" role="dialog" id="google-map-modal">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <h4 class="modal-title pl-0">
                            <f:translate key="maps_modal_title" extensionName="my_sitepackage_theme" />
                        </h4>
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                            <span aria-hidden="true">&times;</span>
                        </button>
                    </div>
                    <div class="modal-body">
                        <h3><f:translate key="maps_modal_text_heading" extensionName="my_sitepackage_theme" /></h3>
                        <p>
                            <f:translate key="maps_modal_text" extensionName="my_sitepackage_theme" />
                            <f:link.external uri="https://policies.google.com/privacy"
                                             target="_blank"
                                             title="https://policies.google.com/privacy">
                                https://policies.google.com/privacy
                            </f:link.external>
                        </p>
                        <div class="form-check mb-3">
                            <input class="form-check-input" type="checkbox" value="" id="map-privacy-check">
                            <label class="form-check-label" for="map-privacy-check">
                                <f:translate key="maps_modal_checkbox_label" extensionName="my_sitepackage_theme" />
                            </label>
                        </div>
                        <small>
                            <f:translate key="maps_modal_text_small" extensionName="my_sitepackage_theme" />
                        </small>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-primary btn-load-map" onclick="activateGoogleMaps();">
                            <f:translate key="maps_modal_btn_label" extensionName="my_sitepackage_theme" />
                        </button>
                    </div>
                </div>
            </div>
        </div>

        <!-- my_sitepackage_theme: Partials/GoogleMaps.html [end] -->
    </f:section>
</div>

In order for the Partial to be loaded, it needs to be included in the page Fluid Template or the Partial which is used for the map. We usually add the code to the Partial footer.

    <f:if condition="{settings.tracking.googleMaps.active}">
        <f:render partial="Elements/GoogleMaps" section="Default"  arguments="{_all}" />
    </f:if>
  1. TypoScript and JS required for functionality

The following JavaScript sets and reads the cookies. File: typo3conf\ext\my_sitepackage_theme\Resources\Public\JavaScript\Cookies.js

    var Cookies = {
        set: function(name, value, days) {
            var expires = "";
            if (days) {
                var date = new Date();
                date.setTime(date.getTime() + (days*24*60*60*1000));
                expires = "; expires=" + date.toUTCString();
            }
            document.cookie = name + "=" + (value || "")  + expires + "; path=/";
        },
        get: function(name) {
            var nameEQ = name + "=";
            var ca = document.cookie.split(';');
            for(var i=0;i < ca.length;i++) {
                var c = ca[i];
                while (c.charAt(0) === ' ') c = c.substring(1,c.length);
                if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length,c.length);
            }
            return null;
        }
    };

The following JavaScript swaps the map view with a placeholder and register the user's decision. File: typo3conf\ext\my_sitepackage_theme\Resources\Public\JavaScript\GoogleMapsAllowed.js

    jQuery(document).ready(function () {
        //
        // Google map
        var googleMapsAlert = jQuery('.google-maps-alert').length;
        var googleMapsModal = jQuery('#google-map-modal');
        if (googleMapsAlert) {
            var googleMapsPlaceholder = jQuery('.map-placeholder').html();
            var googleMapsAllowed = Cookies.get('googleMapsAllowed');
            if (googleMapsAllowed === null) {
                var mapWrapperOpenimmoOverview = jQuery('#openimmo-google-map-overview');
                if (mapWrapperOpenimmoOverview.length > 0) {
                    mapWrapperOpenimmoOverview.html(googleMapsPlaceholder);
                }
                var mapWrapperOpenimmo = jQuery('#openimmo-detail-map');
                if (mapWrapperOpenimmo.length > 0) {
                    mapWrapperOpenimmo.html(googleMapsPlaceholder);
                }
                var mapWrapperOpenimmoSearchRequest = jQuery('#openimmo-search-request-map');
                if (mapWrapperOpenimmoSearchRequest.length > 0) {
                    mapWrapperOpenimmoSearchRequest.html(googleMapsPlaceholder);
                    googleMapsModal.find('.close').remove();
                    googleMapsModal.modal({
                        backdrop: 'static'
                    });
                    googleMapsModal.modal('show');
                }
            }
        }
    });

    function activateGoogleMaps() {
        var googleMapsCheckbox = jQuery('#map-privacy-check');
        if (googleMapsCheckbox.is(":checked")) {
            Cookies.set('googleMapsAllowed', '1', 365);
            window.location.reload(false);
        } else {
            googleMapsCheckbox.addClass('is-invalid');
        }
    }

The TypoScript below checks whether the constant is active and the user can decide whether to load the map.

If the constant is active then the 2 JavaScript files above are loaded. At the same time, the scripts which load Google Maps are deleted.

Once the user has consented, the Google Maps scripts are reloaded.

File: typo3conf\ext\my_sitepackage_theme\Configuration\TypoScript\Library\googleMapsAllowed.typoscript

#
# Load Google Maps
#
# The google Maps notification / button should to be displayed
# So the visitor has to decide whether to load Google Maps
[{$themes.configuration.tracking.googleMaps.active} == 1]
page {
    includeJSFooterlibs {
        cookie = EXT:my_sitepackage_theme/Resources/Public/JavaScript/Cookies.js
        cookie {
            external = 0
            forceOnTop = 0
            disableCompression = 0
            excludeFromConcatenation = 0
        }
    }

    includeJSFooter {
        googleMapsAllowed = EXT:my_sitepackage_theme/Resources/Public/JavaScript/GoogleMapsAllowed.js
        googleMapsAllowed {
            external = 0
            forceOnTop = 0
            disableCompression = 0
            excludeFromConcatenation = 0
        }
    }
}

# Copy config for scripts to load if user allow Google Maps
lib.googleMapsAllowed.includeJSFooterlibs.googleMaps < page.includeJSFooterlibs.googleMaps
lib.googleMapsAllowed.includeJSFooterlibs.googleMapsHtmlMarker < page.includeJSFooterlibs.googleMapsHtmlMarker
lib.googleMapsAllowed.includeJSFooterlibs.googleMapsClustering < page.includeJSFooterlibs.googleMapsClustering

# Remove scripts form openimmo pro
page.includeJSFooterlibs.googleMaps >
page.includeJSFooterlibs.googleMapsHtmlMarker >
page.includeJSFooterlibs.googleMapsClustering >
[GLOBAL]

# If google Maps loadings is accepted by user
[request.getCookieParams() ['googleMapsAllowed'] == 1]
    page.includeJSFooterlibs.googleMaps < lib.googleMapsAllowed.includeJSFooterlibs.googleMaps
    page.includeJSFooterlibs.googleMapsHtmlMarker < lib.googleMapsAllowed.includeJSFooterlibs.googleMapsHtmlMarker
    page.includeJSFooterlibs.googleMapsClustering < lib.googleMapsAllowed.includeJSFooterlibs.googleMapsClustering
[GLOBAL]