Utiliza la geolocalización para dar a tus clientes direcciones para llegar en automóvil
Spanish (Español) translation by Luis Chiabrera (you can also view the original English article)
Este tutorial es una actualización de uno anterior en el que analizamos cómo mostrar instrucciones de conducción directamente en un sitio web de WordPress utilizando la API de Google Maps.
En el primer tutorial, nuestros usuarios tenían que ingresar manualmente su dirección en un formulario en el sitio web; luego se mostraban las instrucciones. Este fue un buen ejemplo de cómo usar la API de Google Maps, pero la capacidad de detectar la ubicación actual de un usuario, además de poder ingresar una dirección manualmente, era una característica que se solicitaba con frecuencia.
Hay mucho terreno que cubrir aquí, pero una gran parte se cubrió en el tutorial anterior. Para evitar tener que repetirme, revisa el primer tutorial "Proporciona a tus clientes direcciones para llegar en automóvil", donde encontrarás todo lo que no se explica en este.
Lo que cubrimos en el original
Esta es una lista de cosas que no cubriremos en este tutorial. Así que siéntete libre de revisar el tutorial original para obtener explicaciones detalladas:
- Cómo registrar configuraciones personalizadas en el Panel de administradorde WordPress. Los tres campos de configuración fueron para:
- El destino
- El texto que se mostrará en la ventana de información
- El nivel de zoom inicial del mapa cuando se carga por primera vez
- Cómo obtener un valor Lat/Lon realmente preciso para tu destino utilizando la muestra de la API de Google Maps V3
- Cómo configurar los códigos cortos utilizados en este tutorial
Nota: Leer el primer tutorial te ayudará a comprender las partes que no se explican en este tutorial. Sin embargo, el código proporcionado en los archivos fuente contiene todo lo que necesitas.
Lo que crearemos



¿Por qué es este mejor que el original?
Además de lo que logramos en el tutorial anterior, también:
- Detectar si el navegador del usuario tiene capacidades de ubicación geográfica.
- Si es así, permíteles usarlo en lugar de ingresar una dirección manualmente
- Proporciona un enlace especial a Google Maps. Al hacer clic (o tocar), este enlace abrirá la aplicación nativa de Mapas en el dispositivo si está disponible y planificará automáticamente la ruta. Esto es especialmente útil en dispositivos iOS y Android.
Otras mejoras al original:
- Examinaremos el manejo mejorado de errores
- Anteriormente, el administrador del sitio tenía que ingresar los valores de latitud y longitud del destino en la configuración de WordPress; hoy veremos cómo aceptar estos valores de lat/lon o una dirección regular. Esto significa que el administrador puede proporcionar un lugar señalado en el mapa (la posición exacta de un edificio, por ejemplo) o simplemente la dirección de la calle.
Paso 1 Crea un archivo CSS
Agregaremos un poco de CSS para mejorar el aspecto/diseño de nuestro mapa y botones, por lo que crearemos una hoja de estilo CSS externa en nuestro directorio de mapas.
Dentro de tu carpeta de temas, tu directorio de mapas ahora debería verse así:
- map.php
- map.js
- map.css
Paso 2 Agrega algo de CSS
En el primer tutorial, agregamos un par de líneas de CSS en la hoja de estilo principal de los temas, style.css. Toma esas líneas e insértalas en este nuevo archivo CSS junto con todo lo que ves a continuación.
Nota: Estos estilos se escribieron para trabajar con el tema de Twenty Eleven. Es posible que el relleno, los márgenes o los colores no se adapten perfectamente a tu tema. Por lo tanto, debes sentirte libre de ajustar cualquiera cosa, no afectará la funcionalidad :)
1 |
#map-container img { max-width: none; } /* From original tut */ |
2 |
#map-container { width: 100%; height: 400px; } /* From original tut */ |
3 |
|
4 |
/* reduce the height of the map on smaller screens */
|
5 |
@media only screen and (max-width: 767px) { |
6 |
#map-container { height: 235px; } |
7 |
}
|
8 |
|
9 |
/* A class we'll use to hide some elements later */
|
10 |
.hidden { display: none; } |
11 |
|
12 |
/* Button styles - edit at will! */
|
13 |
.map-button { |
14 |
display: block; |
15 |
padding: 5px; |
16 |
background: #d9edf7; |
17 |
border: 1px solid #bce8f1; |
18 |
color: #3a87ad; |
19 |
margin: 5px 0; |
20 |
border-radius: 3px; |
21 |
text-shadow: 1px 1px 1px white; |
22 |
}
|
23 |
|
24 |
.map-button:hover, .map-button:focus { |
25 |
background: #b1dce5; |
26 |
text-decoration: none; |
27 |
}
|
28 |
|
29 |
/* Cancel out any default padding on 'p' elements */
|
30 |
#directions p { |
31 |
margin-bottom: 0; |
32 |
}
|
33 |
|
34 |
/* Adjust how the input element displays */
|
35 |
#from-input { |
36 |
margin: 5px 0; |
37 |
border-radius: 3px; |
38 |
padding: 5px; |
39 |
}
|
Ahora puedes seguir adelante y poner en cola el archivo dentro del código corto wpmap_map.
1 |
wp_register_style('wptuts-style', get_template_directory_uri() . '/map/map.css', '', '', false); |
2 |
wp_enqueue_style ('wptuts-style'); |
Paso 3 Agrega el nuevo HTML para los botones
Ahora agreguemos el marcado para los botones en nuestro código corto wpmap_directions_input
.
- Debido a que solo queremos que nuestros nuevos botones 'geo' aparezcan para los usuarios que tienen la capacidad, envolveremos nuestros botones en un
div
y aplicaremos la clase 'hidden
' que definimos en nuestro CSS. Luego, podemos eliminar esta clase más tarde si la ubicación geográfica está habilitada. - Esta vez enviamos un parámetro al método
WPmap.getDirections
('manual
' o 'geo
'); esto nos permite tener la funcionalidad original (donde un usuario ingresa una dirección manualmente) junto con el nuevo método de ubicación geográfica. - La etiqueta
span
es donde insertaremos el enlace especial que abrirá la aplicación Mapa en móviles y tabletas. Hay un poco de trabajo involucrado para construir el enlace correctamente, así que lo veremos más de cerca más adelante en la sección de JavaScript de este tutorial.
1 |
function wpmap_directions_input() { |
2 |
|
3 |
$address_to = get_option('map_config_address'); |
4 |
|
5 |
$output = '<div id="directions"> |
6 |
<p>For Driving Directions, Enter your Address below :</p>
|
7 |
<input id="from-input" type="text" value="" size="20" placeholder="Enter your address here" />
|
8 |
<select onchange="" id="unit-input">
|
9 |
<option value="imperial" selected="selected">Imperial</option>
|
10 |
<option value="metric">Metric</option>
|
11 |
</select>
|
12 |
<a href="#" onclick="WPmap.getDirections(\'manual\'); return false" class="map-button">Get Driving Directions </a><br />
|
13 |
<input id="map-config-address" type="hidden" value="' . $address_to . '"/> |
14 |
<div id="geo-directions" class="hidden">
|
15 |
<p>Alternatively, you can</p>
|
16 |
<a href="#" onclick="WPmap.getDirections(\'geo\'); return false" class="map-button">Use your Current Location </a>
|
17 |
<span id="native-link"></span>
|
18 |
</div>
|
19 |
</div>'; |
20 |
return $output; |
21 |
}
|
Resumen rápido
Hasta ahora, en relación al tutorial original, tenemos:
- Creaste un archivo CSS con un estilo básico y lo pusiste en cola.
- Se agregó un marcado adicional para permitir nuevos botones que solo los navegadores modernos verán.
A continuación, veremos las modificaciones de JavaScript. Hay mucho en esta próxima sección, así que en lugar de hacer una comparación directa con el original, haré todo lo posible para explicar lo que está sucediendo en cada método/función y puedes revisar los archivos fuente completos al final para ver cómo encaja todo.
Paso 4 El JavaScript
Ahora aquí viene la parte divertida. En el primer tutorial, nuestro método init()
fue responsable de crear una instancia del mapa en el mismo formato para cada carga de página. Esto significaba que todos recibirían exactamente la misma funcionalidad independientemente de las capacidades del dispositivo - ¡es hora de cambiar eso!
Cuando un usuario visita nuestro sitio web usando un teléfono inteligente, por ejemplo, queremos poder ofrecerle la posibilidad de usar su ubicación actual en lugar de ingresarla manualmente. Además, queremos la posibilidad de iniciar la aplicación nativa de Mapas en el teléfono y tener la ruta planificada automáticamente.
Un breve comentario sobre la compatibilidad con el navegador
La API de JavaScript de GeoLocation es una de las nuevas funciones de HTML5 con mejor soporte. Más del 75% de todos los navegadores parecen admitirlo según caniuse.com. ¡Creo que eso significa que estamos bastante a salvo! (De todos modos, proporcionaremos una alternativa para los navegadores más antiguos :))
Ahora, sumerjámonos en JavaScript.
Entendiendo el Código
En pocas palabras, todo lo que buscamos hacer aquí es brindar la opción de usar la ubicación geográfica si está disponible. Si no es así, los usuarios aún podrán ingresar una dirección manualmente.
Si echas un vistazo al flujo de control simplificado (a continuación), puedes ver que usamos los mismos métodos para configurar el mapa, pero un par más si la ubicación geográfica está habilitada.



De acuerdo, creo que tenemos una buena comprensión de lo que estamos tratando de lograr aquí, así que ahora proporcionaré una explicación de cada método individualmente; como siempre, consulta los archivos de origen para ver cómo encaja todo en el mismo archivo. .
Establecer propiedades
Aquí consultamos el DOM para recuperar algunas propiedades que usaremos más adelante. También obtenemos un par de objetos de la API que manejarán la solicitud 'obtener direcciones'.
1 |
var WPmap = { |
2 |
|
3 |
// HTML Elements we'll use later! |
4 |
mapContainer : document.getElementById('map-container'), |
5 |
dirContainer : document.getElementById('dir-container'), |
6 |
toInput : document.getElementById('map-config-address'), |
7 |
fromInput : document.getElementById('from-input'), |
8 |
unitInput : document.getElementById('unit-input'), |
9 |
geoDirections : document.getElementById('geo-directions'), |
10 |
nativeLinkElem : document.getElementById('native-link'), |
11 |
startLatLng : null, |
12 |
destination : null, |
13 |
geoLocation : null, |
14 |
geoLat : null, |
15 |
geoLon : null, |
16 |
|
17 |
// Google Maps API Objects |
18 |
dirService : new google.maps.DirectionsService(), |
19 |
dirRenderer : new google.maps.DirectionsRenderer(), |
20 |
map : null, |
21 |
|
22 |
/** WPmap Object continues throughout tutorial **/ |
init()
Este es el primer método que se llamará cuando se cargue nuestra página.
- Lo primero que hacemos es verificar las capacidades de ubicación geográfica en el navegador.
- Si está disponible, ejecutamos algunos métodos más para configurar los botones adicionales en la página (los veremos en breve)
- Si no está disponible, lo saltamos todo y seguimos directamente con la configuración del destino.
- La última parte del método
init()
es el controlador de eventos que usamos para mostrar un mensaje al usuario cuando se solicitan direcciones. Nota: Esto es opcional - sientete libre de eliminarlo.
1 |
init:function () { |
2 |
|
3 |
if (WPmap.geoLoc = WPmap.getGeo()) { |
4 |
// things to do if the browser supports GeoLocation. |
5 |
WPmap.getGeoCoords(); |
6 |
} |
7 |
|
8 |
WPmap.getDestination(); |
9 |
|
10 |
// listen for when Directions are requested |
11 |
google.maps.event.addListener(WPmap.dirRenderer, 'directions_changed', function () { |
12 |
|
13 |
infoWindow.close(); //close the first infoWindow |
14 |
marker.setVisible(false); //remove the first marker |
15 |
|
16 |
// setup strings to be used. |
17 |
var distanceString = WPmap.dirRenderer.directions.routes[0].legs[0].distance.text; |
18 |
|
19 |
// set the content of the infoWindow before we open it again. |
20 |
infoWindow.setContent('Thanks!<br /> It looks like you\'re about <strong> ' + distanceString + '</strong> away from us. <br />Directions are just below the map'); |
21 |
|
22 |
// re-open the infoWindow |
23 |
infoWindow.open(WPmap.map, marker); |
24 |
setTimeout(function () { |
25 |
infoWindow.close() |
26 |
}, 8000); //close it after 8 seconds. |
27 |
|
28 |
}); |
29 |
}//init |
Ok, he mostrado el método init()
primero esta vez para que puedas entender cómo funcionará el flujo de control.
Ahora te mostraré los métodos involucrados cuando un usuario tiene capacidades de ubicación geográfica.
Detectando la ubicación geográfica
getGeo()
Todo comienza con la "detección de características" estándar.
Para determinar si un navegador es compatible con GeoLocation o no, todo lo que hacemos es verificar la existencia del objeto navigator.geolocation
.
1 |
getGeo : function() { |
2 |
if (!! navigator.geolocation) |
3 |
return navigator.geolocation; |
4 |
else |
5 |
return undefined; |
6 |
}, |
getGeoCoords()
Ahora que sabemos que el navegador tiene una ubicación geográfica, podemos seguir adelante y solicitar las coordenadas actuales.
- Llamamos a
getCurrentPosition()
y pasamos dos parámetros: una función de devolución de llamada exitosa y una función de devolución de llamada de error
1 |
getGeoCoords : function () { |
2 |
WPmap.geoLoc.getCurrentPosition(WPmap.setGeoCoords, WPmap.geoError) |
3 |
}, |
setGeoCoords()
Esta es nuestra devolución de llamada exitosa. Si llegamos hasta aquí, habremos recuperado con éxito las coordenadas del usuario.
-
position
será un objeto que contiene la información de ubicación geográfica para que podamos seguir adelante y establecer los valores de Lat/Lon en las propiedades del objeto. - A continuación, llamamos a
showGeoButton()
para mostrar el botón para usar la ubicación actual. - Finalmente, llamamos a
setNativeMapLink()
para construir el enlace que abrirá las aplicaciones de mapas nativas.
1 |
setGeoCoords : function (position) { |
2 |
WPmap.geoLat = position.coords.latitude; |
3 |
WPmap.geoLon = position.coords.longitude; |
4 |
WPmap.showGeoButton(); |
5 |
WPmap.setNativeMapLink(); |
6 |
}, |
geoError()
Esto manejará cualquier error recibido de getCurrentPosition()
- esto es muy útil en el desarrollo, pero en producción es posible que desees eliminarlo, ya que de todos modos ofrecemos un respaldo a la entrada manual de direcciones.
1 |
geoError : function(error) { |
2 |
var message = ""; |
3 |
// Check for known errors |
4 |
switch (error.code) { |
5 |
case error.PERMISSION_DENIED: |
6 |
message = "This website does not have permission to use the Geo location API"; |
7 |
break; |
8 |
case error.POSITION_UNAVAILABLE: |
9 |
message = "Sorry, your current position cannot be determined, please enter your address instead."; |
10 |
break; |
11 |
case error.PERMISSION_DENIED_TIMEOUT: |
12 |
message = "Sorry, we're having trouble trying to determine your current location, please enter your address instead."; |
13 |
break; |
14 |
} |
15 |
if (message == "") { |
16 |
var strErrorCode = error.code.toString(); |
17 |
message = "The position could not be determined due to an unknown error (Code: " + strErrorCode + ")."; |
18 |
} |
19 |
console.log(message); |
20 |
}, |
showGeoButton
Muestra el botón "obtener ubicación actual".
- Nuestro enfoque es ocultar siempre el botón, a menos que estén habilitados tanto JavaScript como la ubicación geográfica. Logramos esto eliminando la clase
.hidden
usando.removeClass()
. Este es un método auxiliar que simplifica mucho la eliminación de clases en elementos HTML (estará en la parte inferior de los archivos fuente)
1 |
showGeoButton : function() { |
2 |
var geoContainer = document.getElementById('geo-directions'); |
3 |
geoContainer.removeClass('hidden'); |
4 |
}, |
setNativeMapLink()
Este es el enlace especial que abrirá aplicaciones de mapas nativas en dispositivos iOS y Android. Debido a que previamente guardamos los valores Lat/Lon actuales en nuestro objeto, ahora podemos generar fácilmente el enlace con el formato correcto.
1 |
setNativeMapLink: function() { |
2 |
var locString = WPmap.geoLat + ',' + WPmap.geoLon; |
3 |
var destination = WPmap.toInput.value; |
4 |
var newdest = destination.replace(' ', ''); |
5 |
WPmap.nativeLinkElem.innerHTML = ('<a href="http://maps.google.com/maps?mrsp=0' |
6 |
+ '&daddr=' |
7 |
+ newdest |
8 |
+ '&saddr=' |
9 |
+ locString |
10 |
+ '" class="map-button">Open in Google Maps</a>'); |
11 |
}, |
getDestination()
Aquí estamos determinando si el administrador ha ingresado un valor de Lat/Lon o una dirección regular en la página de Opciones:
- Primero probamos para ver si
toInput
es un valor Lat/Lon usando una expresión regular. - Si es así, establecemos
WPmap.destination
igual a un objetogoogle.maps.LatLng
. - Si no es así, usamos
google.maps.Geocoder()
para convertir la dirección en un objetogoogle.maps.LatLng
y establecerlo como destino. - De cualquier manera, ahora todo está en su lugar para configurar el mapa usando
setupMap()
1 |
getDestination:function() { |
2 |
|
3 |
var toInput = WPmap.toInput.value; |
4 |
var isLatLon = (/^(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)$/.test(toInput)); |
5 |
|
6 |
if (isLatLon) { |
7 |
var n = WPmap.toInput.value.split(","); |
8 |
WPmap.destination = new google.maps.LatLng(n[0], n[1]); |
9 |
WPmap.setupMap(); |
10 |
} |
11 |
else { |
12 |
geocoder = new google.maps.Geocoder(); |
13 |
geocoder.geocode( { 'address': WPmap.toInput.value}, function(results, status) { |
14 |
WPmap.destination = results[0].geometry.location; |
15 |
WPmap.setupMap(); |
16 |
}); |
17 |
} |
18 |
|
19 |
}, |
setupMap()
Muy similar al original - configura el mapa con el marcador centrado en nuestro destino y el texto de las opciones de administración dentro de la ventana de información.
1 |
/* Initialize the map */ |
2 |
setupMap : function() { |
3 |
|
4 |
// get the content |
5 |
var infoWindowContent = WPmap.mapContainer.getAttribute('data-map-infowindow'); |
6 |
var initialZoom = WPmap.mapContainer.getAttribute('data-map-zoom'); |
7 |
|
8 |
WPmap.map = new google.maps.Map(WPmap.mapContainer, { |
9 |
zoom:parseInt(initialZoom), // ensure it comes through as an Integer |
10 |
center:WPmap.destination, |
11 |
mapTypeId:google.maps.MapTypeId.ROADMAP |
12 |
}); |
13 |
|
14 |
marker = new google.maps.Marker({ |
15 |
map:WPmap.map, |
16 |
position:WPmap.destination, |
17 |
draggable:false |
18 |
}); |
19 |
|
20 |
// set the infowindow content |
21 |
infoWindow = new google.maps.InfoWindow({ |
22 |
content:infoWindowContent |
23 |
}); |
24 |
infoWindow.open(WPmap.map, marker); |
25 |
|
26 |
}, |
getDirections()
Esta es llamada siempre que se solicitan direcciones. Su único argumento, 'request
', nos ayudará a determinar si el usuario hizo clic en el botón para usar una dirección ingresada manualmente o la de 'ubicación actual'.
1 |
getDirections:function (request) { |
2 |
|
3 |
// Get the postcode that was entered |
4 |
var fromStr = WPmap.fromInput.value; |
5 |
|
6 |
var dirRequest = { |
7 |
origin : fromStr, |
8 |
destination : WPmap.destination, |
9 |
travelMode : google.maps.DirectionsTravelMode.DRIVING, |
10 |
unitSystem : WPmap.getSelectedUnitSystem() |
11 |
}; |
12 |
|
13 |
// check if user clicked 'use current location' |
14 |
if (request == 'geo') { |
15 |
var geoLatLng = new google.maps.LatLng( WPmap.geoLat , WPmap.geoLon ); |
16 |
dirRequest.origin = geoLatLng; |
17 |
} |
18 |
|
19 |
WPmap.dirService.route(dirRequest, WPmap.showDirections); |
20 |
}, |
showDirections()
Sin cambios con respecto al original: maneja la inserción de las direcciones en la página.
1 |
/** |
2 |
* Output the Directions into the page. |
3 |
*/ |
4 |
showDirections:function (dirResult, dirStatus) { |
5 |
if (dirStatus != google.maps.DirectionsStatus.OK) { |
6 |
switch (dirStatus) { |
7 |
case "ZERO_RESULTS" : |
8 |
alert ('Sorry, we can\'t provide directions to that address (you maybe too far away, are you in the same country as us?) Please try again.'); |
9 |
break; |
10 |
case "NOT_FOUND" : |
11 |
alert('Sorry we didn\'t understand the address you entered - Please try again.'); |
12 |
break; |
13 |
default : |
14 |
alert('Sorry, there was a problem generating the directions. Please try again.') |
15 |
} |
16 |
return; |
17 |
} |
18 |
// Show directions |
19 |
WPmap.dirRenderer.setMap(WPmap.map); |
20 |
WPmap.dirRenderer.setPanel(WPmap.dirContainer); |
21 |
WPmap.dirRenderer.setDirections(dirResult); |
22 |
}, |
Terminando el JavaScript
Fuera del objeto, solo hay que agregar el detector de eventos que cargará el mapa cuando la página esté lista y la función auxiliar de la que hablamos anteriormente.
1 |
/* Load the map when the page is ready */ |
2 |
google.maps.event.addDomListener(window, 'load', WPmap.init); |
3 |
|
4 |
/* Function to easily remove any class from an element. */ |
5 |
HTMLElement.prototype.removeClass = function(remove) { |
6 |
var newClassName = ""; |
7 |
var i; |
8 |
var classes = this.className.split(" "); |
9 |
for(i = 0; i < classes.length; i++) { |
10 |
if(classes[i] !== remove) { |
11 |
newClassName += classes[i] + " "; |
12 |
} |
13 |
} |
14 |
this.className = newClassName; |
15 |
} |
Y finalmente...
Ahora, para que todo funcione, solo necesitas colocar la carpeta del mapa en tu tema y luego revisar las cosas que cubrimos en el primer tutorial.
-
Incluye map.php en tu tema functions.php
1
/** In functions.php **/
2
include('map/map.php');
- Ingresa tu destino, el texto de la ventana de información y el nivel de zoom en los campos que creamos en Configuración. Se pueden encontrar en Configuración -> General -> Configuración del mapa
- Luego, en cualquier página o publicación, ingresa los tres códigos cortos
[wpmap_map]
[wpmap_directions_input]
[wpmap_directions_container]
Conclusion
Como mencioné, esta es una actualización de este tutorial y, por lo tanto, realmente necesitas revisar ambos para comprender completamente todo el proceso. Sin embargo, posiblemente la forma más fácil de entender cómo encaja todo sería ver los archivos fuente proporcionados.
Después de todo esto, deberías tener una pequeña aplicación de mapas bastante ordenada que responderá a diferentes tamaños de pantalla y también agregará funcionalidad adicional a los usuarios con navegadores modernos. Al mismo tiempo, proporciona una buena alternativa para todos los demás.