Munstadi

API, Development, Front-End
Contractor: H1 Web Oy
Client: Munstadi
Website: munstadi.fi
Close X

As part of a bigger project for Munstadi I had to implement a map displaying places based on coordinates fetched from an API provided by the city of Helsinki.

I decided to go with the Open Source project Leaflet.js for the front-end development and with writing a plugin for the back-end.

The communication with the API happens in the client side and it’s triggered whenever a new place is created (a subsite in the same network in this case) or whenever the user clicks the ‘Regenerate all coordinates’ button.

munstadi1

munstadi2


/**
	* Map API Wordpress Plugin
	* Author: Federico Di Rosa
	* Version: 1.0
	* License: MIT
	*/

if (!class_exists('MapApiPublic')) {

	class MapApiPublic {

		public static $map_div_id = 'map';

		public function __construct() {}

		public function get_all_places_data() {
			$coordinates = array();
			$args = array(
				'post_type'  => MapApiAdmin::$post_type,
				'posts_per_page' => -1,
				'meta_query' => array(
					array(
						'key'     => MapApiAdmin::$latitude_meta_key,
						'value' => '',
						'compare' => '!='
					),
					array(
						'key'     => MapApiAdmin::$longitude_meta_key,
						'value' => '',
						'compare' => '!='
					)
				),
			);

			$all_coordinates = new WP_Query( $args );
			if ( $all_coordinates->have_posts() ) :
				while ( $all_coordinates->have_posts() ) :
					$all_coordinates->the_post();
					$coordinates[ get_the_id() ]['lat'] = get_post_meta( get_the_id(), MapApiAdmin::$latitude_meta_key, true );
					$coordinates[ get_the_id() ]['lon'] = get_post_meta( get_the_id(), MapApiAdmin::$longitude_meta_key, true );
					$coordinates[ get_the_id() ]['title'] = get_the_title();
					$coordinates[ get_the_id() ]['url'] = get_post_meta( get_the_id(), MapApiAdmin::$site_url_meta_key, true );
				endwhile;
			endif;
			wp_reset_postdata();

			return $coordinates;
		}

		public function load_assets() {
			wp_enqueue_script( 'map-api-leaflet-js', plugin_dir_url( MAP_API_BASENAME ) . 'vendor/leaflet-0.7.3/leaflet.js', false, '1.0', true );
			wp_enqueue_script( 'map-api-leaflet-providers-js', plugin_dir_url( MAP_API_BASENAME ) . 'vendor/leaflet-plugins/leaflet-providers.js', array( 'map-api-leaflet-js' ), '1.0', true );
			wp_enqueue_style( 'map-api-leaflet-css', plugin_dir_url( MAP_API_BASENAME ) . 'vendor/leaflet-0.7.3/leaflet.css', false, '1.0' );
			wp_register_script( 'map-api-js', plugin_dir_url( MAP_API_BASENAME ) . 'js/map-api.min.js', array( 'jquery', 'map-api-leaflet-js' ), '1.0', true );
			wp_enqueue_style( 'map-api-css', plugin_dir_url( MAP_API_BASENAME ) . 'css/map-api.css', false, '1.0' );

			$data = array(
				'map_div_id' => self::$map_div_id,
				'coordinates' => self::get_all_places_data()
			);

			wp_localize_script( 'map-api-js', 'map_api_data', $data );
			wp_enqueue_script( 'map-api-js' );
		}

		public static function render_map() {
			self::load_assets();
			echo self::$map_div_id;
		}

	}

}


/*!
	* Map API Wordpress Plugin
	* Author: Federico Di Rosa
	* Version: 1.0
	* License: MIT
	*/

jQuery(document).ready(function($) {

	var MAP_API = {
		map: '',
		init: function(){
			if (MAP_API.is_map())
				MAP_API.create_map();
		},
		is_map: function() {
			if (!$('#' + map_api_data.map_div_id).length) return false;
			else return true;
		},
		create_map: function(){
			MAP_API.map = L.map( map_api_data.map_div_id, {
					center: [60.1708, 24.9375], // default: Helsinki
					zoom: 12,
					attributionControl: false
			});
			MAP_API.tile_layer();
			MAP_API.add_markers();
		},
		tile_layer: function(){
			var topLayer = L.tileLayer.provider('Hydda.Full').addTo( MAP_API.map ); // OpenStreetMap.HOT is another good one
		},
		add_markers: function(){
			var coordinates = [];
			var fit_all_markers = true;
			$.each(map_api_data.coordinates, function(i, post_id) {
				if (!isNaN(post_id.lat) && !isNaN(post_id.lon)) {
					var marker = L.marker([ post_id.lat, post_id.lon ]).addTo( MAP_API.map ).bindPopup( '
' + post_id.title + '
' + post_id.url + '' ); var place = []; var match = false; if ( parseInt(i) === parseInt(MAP_API.get_request_id()) ) { match = true; coordinates = []; marker.openPopup(); } if (fit_all_markers === true) { place.push(post_id.lat); place.push(post_id.lon); coordinates.push(place); } if (match === true) { fit_all_markers = false; } } }); MAP_API.set_view_with_bounds( coordinates ); }, set_view_with_bounds: function() { var bounds = L.latLngBounds(arguments[0]); MAP_API.map.fitBounds(bounds); }, get_request_id: function() { var search = window.location.search; var request_id = search.substr(search.indexOf('&id;=') + 4); return request_id; } }; MAP_API.init(); });

/*!
	* Map API Wordpress Plugin
	* Author: Federico Di Rosa
	* Version: 1.0
	* License: MIT
	*/

jQuery(document).ready(function($) {

	var MAP_API_ADMIN = {
		error_msg: 'There was an error fetching the data, try again later

OK
', saving_msg: 'Saving coordinates..

OK
', success_msg: 'Coordinates saved successfully

OK
', error_saving: 'There was a problem saving the data, try again

OK
', not_found_msg: 'Site\'s url not found in City of Helsinki Service Map API

Insert coordinates manually (leave empty to skip):


OK
', not_found_msg_all: 'None of the sites were found in City of Helsinki Service Map API

OK
</span>', fetching_msg: 'Fetching coordinates from City of Helsinki Service Map API

(Please wait, this may take few minutes)

STOP
', request: false, not_found: false, init: function() { if (map_api_admin_data.regenerate_all == 1) { MAP_API_ADMIN.regenerate_all(); } else { if (map_api_admin_data.new_site == 1) { MAP_API_ADMIN.wait_for_it(); } else { MAP_API_ADMIN.initiate_call(); } } }, wait_for_it: function() { $(document).ajaxComplete(function( event, xhr, settings ) { if ( settings.url == '/wp-admin/admin-ajax.php' ) { if (map_api_admin_data.new_site == 1) { MAP_API_ADMIN.initiate_call(); map_api_admin_data.new_site = false; } } }); }, regenerate_all: function() { $('input[type="button"]#regenerate-all').on('click', function(){ MAP_API_ADMIN.initiate_call(); }); }, initiate_call: function() { MAP_API_ADMIN.show_message( MAP_API_ADMIN.fetching_msg ); MAP_API_ADMIN.api_call(); }, loading_dots: function() { var dots = 0; if (!$('.loading-dots').length) return; setInterval (function() { if (dots < 3) { $('.loading-dots').append('.'); dots++; } else { $('.loading-dots').text(''); dots = 0; } }, 500); }, api_call: function() { MAP_API_ADMIN.request = $.ajax({ url: map_api_admin_data.api_url, type: 'GET', dataType: 'jsonp', // xhrFields: { // onprogress: function (e) { // if (e.lengthComputable) { // console.log(e.loaded / e.total * 100 + '%'); // } // } // } }); MAP_API_ADMIN.request.done(function( data, textStatus, jqXHR ) { MAP_API_ADMIN.process_data( data ); }); MAP_API_ADMIN.request.fail(function( jqXHR, textStatus, errorThrown ) { if ($('.map-api-modal-inner-div').length) $('.map-api-modal-inner-div').html( MAP_API_ADMIN.error_msg ); }); }, parse_url: function( url ) { url = url.toLowerCase(); var url_object = document.createElement('a'); url_object.href = url; var hostname = url_object.hostname; var pathname = url_object.pathname; var search = url_object.search; url = hostname + pathname + search; if (url.substr(-1) == '/') { url = url.substr(0, url.length - 1); } return url; }, compare_urls: function( url1, url2 ) { if (url1 === undefined || url2 === undefined) return false; url1 = MAP_API_ADMIN.parse_url( url1 ); url2 = MAP_API_ADMIN.parse_url( url2 ); if (url1 == url2) return true; else return false; }, process_data: function( data ) { var coordinates = {}; if (map_api_admin_data.regenerate_all == 1) { if (map_api_admin_data.posts) { MAP_API_ADMIN.not_found = true; $.each(map_api_admin_data.posts, function(post_id, site_url) { if ($.isArray(data)) { $.each(data, function(index, object) { var returned_value = MAP_API_ADMIN.get_coordinates( object, site_url ); if (returned_value) coordinates[post_id] = returned_value; }); } else { coordinates[post_id] = MAP_API_ADMIN.get_coordinates( data, site_url ); } }); if ( !MAP_API_ADMIN.not_found ) { MAP_API_ADMIN.regenerate_all_update_post_meta( coordinates ); if ($('.map-api-modal-inner-div').length) $('.map-api-modal-inner-div').html( MAP_API_ADMIN.saving_msg ); } else { if ($('.map-api-modal-inner-div').length) $('.map-api-modal-inner-div').html( MAP_API_ADMIN.not_found_msg_all ); } } } else { MAP_API_ADMIN.not_found = true; if ($.isArray(data)) { $.each(data, function(index, object) { var returned_value = MAP_API_ADMIN.get_coordinates( object, map_api_admin_data.site_url ); if (returned_value) coordinates[post_id] = returned_value; }); } else { coordinates[post_id] = MAP_API_ADMIN.get_coordinates( data, map_api_admin_data.site_url ); } if ( !MAP_API_ADMIN.not_found ) { MAP_API_ADMIN.update_post_meta( coordinates ); if ($('.map-api-modal-inner-div').length) $('.map-api-modal-inner-div').html( MAP_API_ADMIN.saving_msg ); } else { if ($('.map-api-modal-inner-div').length) $('.map-api-modal-inner-div').html( MAP_API_ADMIN.not_found_msg ); } } }, get_coordinates: function( data, site_url ) { var coordinates; if (data.hasOwnProperty('www_fi') && MAP_API_ADMIN.compare_urls( data.www_fi, site_url )) { if (data.hasOwnProperty('latitude') && data.hasOwnProperty('longitude')) { coordinates = {}; coordinates.latitude = data.latitude; coordinates.longitude = data.longitude; MAP_API_ADMIN.not_found = false; } } return coordinates; }, update_post_meta: function( coordinates ) { MAP_API_ADMIN.request = $.ajax({ url: map_api_admin_data.ajax_url, type: 'POST', dataType: 'html', data: { action: 'update_post_meta_coordinates', latitude: coordinates.latitude, longitude: coordinates.longitude } }); MAP_API_ADMIN.request.done(function( data, textStatus, jqXHR ) { if ($('.map-api-modal-inner-div').length) $('.map-api-modal-inner-div').html( MAP_API_ADMIN.success_msg ); }); MAP_API_ADMIN.request.fail(function( jqXHR, textStatus, errorThrown ) { if ($('.map-api-modal-inner-div').length) $('.map-api-modal-inner-div').html( MAP_API_ADMIN.error_saving ); }); }, regenerate_all_update_post_meta: function( coordinates ) { MAP_API_ADMIN.request = $.ajax({ url: map_api_admin_data.ajax_url, type: 'POST', dataType: 'html', data: { action: 'regenerate_all_update_post_meta_coordinates', coordinates: coordinates } }); MAP_API_ADMIN.request.done(function( data, textStatus, jqXHR ) { if ($('.map-api-modal-inner-div').length) $('.map-api-modal-inner-div').html( MAP_API_ADMIN.success_msg ); }); MAP_API_ADMIN.request.fail(function( jqXHR, textStatus, errorThrown ) { if ($('.map-api-modal-inner-div').length) $('.map-api-modal-inner-div').html( MAP_API_ADMIN.error_saving ); }); }, remove_message: function() { if ($('.map-api-modal-overlay').length) { $('.map-api-modal-overlay').remove(); } }, close_modal: function() { $(document).on('click', '.map-api-close', function(){ if ($(this).hasClass('submit-coordinates-manually')) { if ($('input#latitude_manual').val() !== '' && $('input#longitude_manual').val() !== '') { MAP_API_ADMIN.update_post_meta( { latitude: $('input#latitude_manual').val(), longitude: $('input#longitude_manual').val() } ); } else { MAP_API_ADMIN.remove_message(); } } else if ($(this).hasClass('abort-ajax')) { MAP_API_ADMIN.request.abort(); } else { MAP_API_ADMIN.remove_message(); } }); }, show_message: function( message ) { var max_width = 500; var max_height = 250; var window_width = $(window).width() - 40; var window_height = $(window).height() - 40; var inner_div_height = $('.map-api-modal-inner-div').height(); if (window_width > max_width) window_width = max_width; if (window_height > max_height) window_height = max_height; var overlay_style = 'position:fixed;'; overlay_style += ' top:0;'; overlay_style += ' right:0;'; overlay_style += ' bottom:0;'; overlay_style += ' left:0;'; overlay_style += ' background:rgba(0,0,0,0.5);'; overlay_style += ' z-index:9999999;'; var modal_style = 'position:absolute;'; modal_style += ' width:' + window_width + 'px;'; modal_style += ' left:50%;'; modal_style += ' margin-left:-' + (window_width/2) + 'px;'; modal_style += ' height:' + window_height + 'px;'; modal_style += ' top:50%;'; modal_style += ' margin-top:-' + (window_height/2) + 'px;'; modal_style += ' background:white;'; modal_style += ' color:#333;'; modal_style += ' text-align:center;'; var inner_div_style = 'padding: 0px 40px;'; inner_div_style += ' -o-transform: translateY(-50%);-moz-transform: translateY(-50%);-webkit-transform: translateY(-50%);-ms-transform: translateY(-50%);transform: translateY(-50%);'; inner_div_style += ' position: relative;'; inner_div_style += ' top: 50%;'; $('body').append('
' + message + '
'); MAP_API_ADMIN.loading_dots(); MAP_API_ADMIN.close_modal(); } }; MAP_API_ADMIN.init(); });