Manchmal braucht man zu einer Adresse die Geo-Koordinaten. Für diese Aufgabe kann man die kostenfreie API von Open Street Map verwenden.
Beispiel
Du legst einen Custom Post Type: standort
an, weil du auf einer Kunden Webseite die Niederlassungen der Firma darstellen willst. Später möchtest du diese mit Google Maps darstellen oder eine Umkreissuche für diesen Post Type bauen.
Dazu musst du die vom Benutzer eingegebene Adresse des Standortes in Geo-Koordinaten umwandeln.
Zusätzlich erstellst du für den Post Type noch ein Textfeld z.B. mit ACF: adresse
in das die Benutzer die Adresse des Standortes als Freitext eintippen können.
Die Open Street Map API (Nominatim)
Hier geht es zur Dokumentation: https://nominatim.org/release-docs/develop/api/Search/
In unserem Beispiel verwenden wir die Freitextsuche du kannst aber auch spezifischer suchen.
Endpunkt Freitextsuche
https://nominatim.openstreetmap.org/search?q=Musterstraße 1, 11111 Musterstadt
Endpunkt spezifische Suche
https://nominatim.openstreetmap.org/search?street=Musterstraße 1&postalcode=11111&city=Musterstadt
Ausgabe / Response als JSON
Um die Suchergebnisse als JSON zu erhalten müssen wir noch den format=json
Parameter anfügen:
https://nominatim.openstreetmap.org/search?q=Hauptbahnhof Berlin&format=json
Damit erhalten wir, sofern die Suche ein Ergebnis findet schon die Koordinaten (lat, lon) die wir benötigen:
[
{
"place_id": 22416464,
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
"osm_type": "node",
"osm_id": 2459919675,
"boundingbox": [
"52.5196361",
"52.5296361",
"13.364861",
"13.374861"
],
"lat": "52.5246361",
"lon": "13.369861",
"display_name": "Berlin Hauptbahnhof (tief), Eingangsebene, Moabit, Mitte, Berlin, 10557, Deutschland",
"class": "railway",
"type": "station",
"importance": 0.6988462520106494,
"icon": "https://nominatim.openstreetmap.org/ui/mapicons//transport_train_station2.p.20.png"
},
]
Zusätzliche Parameter
Man kann auch noch weitere Parameter anfügen um noch mehr Details zu erhalten.
addressdetails
https://nominatim.openstreetmap.org/search?q=Hauptbahnhof Berlin&format=json&addressdetails=1
Erweitert die Response um folgende Daten:
"address": {
"railway": "Berlin Hauptbahnhof (tief)",
"road": "Eingangsebene",
"suburb": "Moabit",
"borough": "Mitte",
"city": "Berlin",
"state": "Berlin",
"postcode": "10557",
"country": "Deutschland",
"country_code": "de"
}
extratags
https://nominatim.openstreetmap.org/search?q=Hauptbahnhof Berlin&format=json&extratags=1
Erweitert die Response um öffentlich verfügbare Daten wie z.B. Wikipedia
"extratags": {
"layer": "-2",
"train": "yes",
"uic_ref": "8098160",
"operator": "DB Netz AG",
"uic_name": "Berlin Hauptbahnhof (tief)",
"wikidata": "Q1097",
"wikipedia": "de:Berlin Hauptbahnhof",
"start_date": "2006-05-28",
"wheelchair": "yes",
"railway:ref": "BL",
"public_transport": "station",
"toilets:wheelchair": "yes",
"railway:station_category": "1"
}
namedetails
https://nominatim.openstreetmap.org/search?q=Hauptbahnhof Berlin&format=json&namedetails=1
Erweitert die Response um alternative Namen der Adresse
"namedetails": {
"name": "Berlin Hauptbahnhof (tief)",
"name:de": "Berlin Hauptbahnhof (tief)",
"short_name": "Berlin Hbf (tief)",
"official_name": "Berlin Hauptbahnhof - Lehrter Bahnhof"
}
Eine Kontakt E-Mail angeben (optional)
Verwendest du die API regelmäßig und in hoher Frequenz wird darum gebeten eine Kontakt E-Mail anzugeben.
https://nominatim.openstreetmap.org/search?q=Hauptbahnhof Berlin&format=json&[email protected]
Die API Klasse
Füge diese Klasse in dein Theme oder Plugin ein.
class Nominatim
{
public static function endpoint( $endpoint ) {
return [
'endpoint' => 'https://nominatim.openstreetmap.org/'.$endpoint
];
}
public static function search( $string ) {
$auth = self::endpoint( 'search/?format=json&q='.$string.'&addressdetails=1&[email protected]' );
$response = wp_remote_get( $auth['endpoint'] );
if ( is_wp_error( $response ) ) {
if ( defined('WP_DEBUG_LOG') && true === WP_DEBUG_LOG ) {
error_log( $response->get_error_message() );
}
return 0;
}
$response = wp_remote_retrieve_body( $response );
$response = json_decode( $response );
if ( empty( $response ) ) {
return 0;
}
// Nimm das erste Item, falls es mehrere Treffer gibt ist das erste meist das Beste
$response = $response[0];
return $response;
}
public static function get_coords( $string ) {
$response = self::search( $string );
$lat = $response->lat;
$lon = $response->lon;
$coords = [
'lat' => $lat,
'lon' => $lon
];
return $coords;
}
}
Mit der Funktion get_coords( $string )
erhalten wir nur die Koordinaten die wir benötigen.
Die Koordinaten zu dem Post abspeichern, wenn ein Post aktualisiert wird
Wir verwenden den ACF Hook save_post um bei Update eines Standort Posts die Koordinaten über die API zu holen und speichern diese als Custom Fields ins Post Meta
// ACF Hook nach Update eines Postes
add_action( 'acf/save_post', 'update_coords' );
function update_coords( $post_id ) {
// Ermittelt den Post Type
$post_type = get_post_type( $post_id );
// Update nur bei "Standort" Posts
if ( 'standort' === $post_type ) {
// Erhalte alle ACF Felder des Postes
$fields = get_fields( $post_id );
// Erhalte den Wert des neuen Adresse Feldes
$adresse = $fields['adresse'];
// Ruft die OSM Api Klasse auf und gibt die Koordinaten zurück
$coords = \Nominatim::get_coords( $adresse );
$lat = $coords['lat'];
$lon = $coords['lon'];
// Updated die Koordinaten als normale Custom Fields
update_post_meta( $post_id, 'lat', $lat );
update_post_meta( $post_id, 'lon', $lon );
}
}
Links
Usage Policy: https://operations.osmfoundation.org/policies/nominatim/
API Dokumentation: https://nominatim.org/release-docs/develop/api/Search/
ACF: save_posts: https://www.advancedcustomfields.com/resources/acf-save_post/