Roots Discourse

Integrating Google Maps on specific page in sage 9

Dear Team

I am not experienced with Roots Sage and I am trying to integrate Google Maps on a specific page. I did similar as described here without success. I get an initMapis not a function error as shown in this screenshot .

What I did in my Sage 9 theme:

Please note that I want to load the script on the contact (example.com/kontakt) page only.

I use Roots Bedrock and the api key is placed in the .env file:

GOOGLE_MAPS_API='MY_API_KEY_HERE'

Following references are within the Roots Sage theme folder.

In app/setup.php I extended the wp_enqueue_scripts hook with my google maps script. Please note the &callback=initMap:

add_action('wp_enqueue_scripts', function () {
    wp_enqueue_style('sage/main.css', asset_path('styles/main.css'), false, null);
    wp_enqueue_script('sage/main.js', asset_path('scripts/main.js'), ['jquery'], null, true);
    if (is_page( 'kontakt' )) {
        wp_enqueue_script('google-maps', 'https://maps.googleapis.com/maps/api/js?key=' . env('GOOGLE_MAPS_API') . '&callback=initMap', [], null, true);
    }

    if (is_single() && comments_open() && get_option('thread_comments')) {
        wp_enqueue_script('comment-reply');
    }
}, 100);

I updated resources/assets/scripts/main.js as follows (see last part “kontakt”):

import kontakt from './routes/kontakt';
...
/** Populate Router instance with DOM routes */
const routes = new Router({
    // All pages
    common,
    // Home page
    home,
    // About Us page, note the change from about-us to aboutUs.
    aboutUs,
    // kontakt page
    kontakt,
});

I created resources/assets/scripts/routes/kontakt.js and added following code:

const google = window.google;

export default {
    init() {
      // JavaScript to be fired on the kontakt page
    },
    finalize() {
      // JavaScript to be fired on the kontakt page, after the init JS
      /* eslint-disable no-unused-vars */
      let map;
      function initMap() {
        map = new google.maps.Map(document.getElementById('map'), {
          center: {
            lat: -34.397,
            lng: 150.644,
          },
          zoom: 8,
        });
      }
      /* eslint-disable no-unused-vars */
    },
};

This compiles but I get the fault “initMap is not a function” as mentioned at the beginning of this post.

Does anyone have an idea what I’m doing wrong or can someone give me a hint on how to best integrate google maps into Roots Sage 9? Is something wrong with the visibility of the function?

Thank you in advance for your appreciated feedback.

Regards from Switzerland,
Philipp

When Google Maps attempts to call your init script (initMap) it does so in the global scope. The function you have created in kotakt.js is not available in the global scope (none of the functions you create in Sage’s JS system are, at least not by default), so it cannot be found.

The easiest solution would be to attach your function to the window object, which is a global object in the browser, and then call it from there:

wp_enqueue_script('google-maps', 'https://maps.googleapis.com/maps/api/js?key=' . env('GOOGLE_MAPS_API') . '&callback=window.initMap', [], null, true);
window.initMap = function() {
        map = new google.maps.Map(document.getElementById('map'), {

Thank you @alwaysblank for your appreciated feedback.

Unfortunately I am still doing something wrong. I updated app/setup.php as follows. Please note that I did change order of google maps and the main.js file (not sure if this is needed):

add_action('wp_enqueue_scripts', function () {

    wp_enqueue_style('sage/main.css', asset_path('styles/main.css'), false, null);

    if (is_page( 'kontakt' )) {
        wp_enqueue_script('google-maps', 'https://maps.googleapis.com/maps/api/js?key=' . env('GOOGLE_MAPS_API') . '&callback=window.initMap', [], null, true);
    }

    wp_enqueue_script('sage/main.js', asset_path('scripts/main.js'), ['jquery'], null, true);

    if (is_single() && comments_open() && get_option('thread_comments')) {
        wp_enqueue_script('comment-reply');
    }

}, 100);

With resources/assets/scripts/routes/kontakt.js as follows`:

const google = window.google;

export default {
    init() {
      // JavaScript to be fired on the konktakt page
    },
    finalize() {
      // JavaScript to be fired on the kontakt page, after the init JS
      /* eslint-disable no-unused-vars */
      let map;
      window.initMap = function() {
        map = new google.maps.Map(document.getElementById('map'), {
          center: {
            lat: -34.397,
            lng: 150.644,
          },
          zoom: 8,
        });
      }
      /* eslint-disable no-unused-vars */
    },
};

Or as follows:

const google = window.google;

export default {
    init() {
      // JavaScript to be fired on the konktakt page
    },
    finalize() {
      // JavaScript to be fired on the kontakt page, after the init JS
    },
};

/* eslint-disable no-unused-vars */
let map;
window.initMap = function() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {
      lat: -34.397,
      lng: 150.644,
    },
    zoom: 8,
  });
}
/* eslint-disable no-unused-vars */

I get the fault that can be found here, respectively a window.initMap is not a function error. May I ask if you can see what I am still doing wrong?

The JavaScript file containing your init function needs to have been parsed and loaded by the time the google maps callback attempts to call it. A good first step in that direction would be to make your google maps script dependent on your main.js. Please example the documentation for wp_enqueue_script: https://developer.wordpress.org/reference/functions/wp_enqueue_script/

You may always want to put your code under the “init” method so that it will fire earlier.

Many of the issues you’re running into here are largely independent of Sage. I’d recommend reading up on asset load order, when JS is parsed during load, and how to manage making sure one script loads before another that requires it.

Thank you @alwaysblank for your feedback and patience. Finally it works. I did update the app/setup.php as follows (now without &callback=window.initMap):

if (is_page( 'kontakt' )) {
        wp_enqueue_script('google-maps', 'https://maps.googleapis.com/maps/api/js?key=' . env('GOOGLE_MAPS_API'), [], null, true);
}
wp_enqueue_script('sage/main.js', asset_path('scripts/main.js'), ['jquery'], null, true);

And here my resources/assets/scripts/routes/kontakt.js with the initMap function:

const google = window.google;

export default {
    init() {
      // JavaScript to be fired on the kontakt page
    },
    finalize() {
      // JavaScript to be fired on the kontakt page, after the init JS
      /* eslint-disable no-unused-vars */
      $(function initMap() {
        let mapDiv = document.getElementById('map');
        let map = new google.maps.Map(mapDiv, {
          center: {
            lat: -34.397,
            lng: 150.644,
          },
          zoom: 8,
        });
      })
      /* eslint-disable no-unused-vars */
    },
};

Hope this post will be helpful to others as well.

Thanks,
Philipp