Die HR Hanse Holding verwaltet Immobilien in Hamburg und pflegt ihren Bestand in onOffice enterprise. Die Objekte sollten auf der WordPress-Website erscheinen – mit eigenem Design, Filtern, funktionierenden Detailseiten. Mehrere Anbieter hatten es versucht. Keiner hat es hinbekommen. Auf der Website: null Immobilien.
In diesem Artikel zeige ich, woran es lag und was ich technisch anders gemacht habe: von der API-Konfiguration über Custom Templates in templates.dist/ bis zum onOffice Template Guard, der Anpassungen nach Plugin-Updates automatisch wiederherstellt.
Ausgangslage: Null Immobilien online
Die Hanse Holding hatte bereits mehrere Dienstleister mit der onOffice-Anbindung beauftragt. Die Symptome waren immer die gleichen: Das onOffice-Plugin für WordPress war installiert, der API-Key eingetragen – aber auf der Website erschienen keine Immobilien. Null Treffer in der Listenansicht. Klickte man auf eine Detailseite, kam ein 404-Fehler. Das Standard-Layout des Plugins passte ohnehin nicht zum Corporate Design.
Die typische Reaktion: "Das Plugin funktioniert nicht." In Wirklichkeit funktioniert das Plugin – die Konfiguration drumherum muss stimmen.
onOffice enterprise ist der Marktführer unter den Makler-CRMs im deutschsprachigen Raum: über 30.000 Nutzer bei mehr als 6.000 Unternehmen. Das WordPress-Plugin ist die offizielle Brücke zwischen CRM und Website – aber die Integration ist alles andere als Plug-and-Play.
Fehlersuche: API-Rechte und Permalink-Routing
Die Diagnose war schneller als erwartet. Zwei Ursachen, beide klassisch:
Problem 1: Falsche API-Berechtigungen. Der API-Benutzer in onOffice hatte die Berechtigung "Objekte lesen" auf "nur eigene" statt "alle" gesetzt. Klingt nach einem kleinen Schalter, hat aber massive Auswirkung: Die API liefert nur Objekte zurück, die dem API-Benutzer persönlich zugewiesen sind. Ein technischer API-Account hat in der Regel null Objekte zugewiesen – also gibt die API eine leere Liste zurück. Das Plugin zeigt brav an, was es bekommt: nichts.
// API-Response bei falschen Rechten ("nur eigene"):
{
"status": { "code": 200 },
"data": {
"records": [], // ← leer, nicht Fehler
"countabsolute": 0
}
}
// API-Response bei korrekten Rechten ("alle"):
{
"status": { "code": 200 },
"data": {
"records": [ ... ], // ← 22 Objekte
"countabsolute": 22
}
}
Das Tückische: Die API gibt keinen Fehler zurück. Status 200, leere Liste. Wer nicht weiß, wo der Schalter sitzt, sucht den Fehler im Plugin statt in der onOffice-Admin-Oberfläche.
Problem 2: Permalink-Struktur bricht Routing. Das onOffice-Plugin registriert eigene Rewrite-Rules für die Detailseiten. Diese Rules funktionieren nur, wenn die WordPress-Permalink-Struktur auf "Beitragsname" (/%postname%/) steht. Bei jeder anderen Einstellung – "Standard", "Tag und Name", "Numerisch" – greift die Plugin-Routing-Logik nicht, und Detailseiten-Links laufen ins Leere.
Wenn die Listenansicht funktioniert, aber Klicks auf einzelne Immobilien eine 404-Seite liefern: Permalinks prüfen. Unter Einstellungen → Permalinks muss "Beitragsname" ausgewählt sein. Danach einmal "Änderungen speichern" klicken, damit WordPress die Rewrite-Rules neu generiert – auch wenn sich scheinbar nichts geändert hat.
Nachdem beide Probleme behoben waren, lief die Synchronisation. 22 Immobilien erschienen in der Listenansicht, Detailseiten waren erreichbar. Aber das Standard-Design des Plugins passte nicht zum Corporate Design der Hanse Holding – und das war der eigentlich aufwendige Teil des Projekts.
Custom Templates in templates.dist
Das onOffice-Plugin lädt seine Templates aus dem Verzeichnis templates.dist/ innerhalb des Plugin-Ordners. Eigene Template-Dateien werden dort neben den Standard-Templates abgelegt und über die onOffice-Plugin-Einstellungen als aktive Templates ausgewählt. Das Problem: Bei einem Plugin-Update wird der gesamte Plugin-Ordner ersetzt – inklusive templates.dist/. Ohne Absicherung sind die Custom Templates nach dem Update weg.
Genau das war den vorherigen Dienstleistern passiert. Viele Entwickler arbeiten alternativ mit CSS-Overrides, die das HTML des Plugins voraussetzen und bei Layout-Änderungen brechen. Der saubere Weg: eigene Templates entwickeln und mit einem Recovery-Mechanismus absichern (dazu gleich mehr).
Für die Hanse Holding habe ich eigene Templates entwickelt:
- Listenansicht (
cardgrid.php): 3-spaltiges Card-Grid mit Orts-Filter (TomSelect-Multiselect), Pagination und integriertem Card-Rendering - Detailseite (
custom_detail.php): Lightbox-Galerie mit Pfeilnavigation, dynamische Highlight-Badges, Eckdaten, OpenStreetMap-Karte, sticky Ansprechpartner-Box - CSS (
onoffice-style.css): Komplettes eigenes Stylesheet intemplates.dist/, das die Plugin-Styles überschreibt
wp-content/plugins/
├── onoffice-for-wp-websites/ ← Hauptplugin (nicht anfassen)
│ └── templates.dist/
│ ├── estate/
│ │ ├── default_list.php
│ │ ├── default_detail.php
│ │ ├── cardgrid.php ← Custom Listenansicht + Cards
│ │ └── custom_detail.php ← Custom Detailseite
│ └── onoffice-style.css ← eigenes Stylesheet
│
└── onoffice-template-guard/ ← Recovery-Plugin (HafenPixel)
└── onoffice-template-guard.php ← stellt Templates nach Updates wieder her
Die Custom Templates werden über den Plugin-internen Template-Loader gefunden und in den onOffice-Einstellungen als aktive Templates konfiguriert. Der Template Guard (siehe nächster Abschnitt) stellt sicher, dass sie nach Plugin-Updates automatisch wiederhergestellt werden.
Listenansicht: Card-Grid mit Orts-Filter
Die Standard-Listenansicht des onOffice-Plugins zeigt Immobilien als einfache Textliste. Für die Hanse Holding habe ich ein 3-spaltiges Card-Grid entwickelt (cardgrid.php), das responsiv auf 2 Spalten (Tablet) und 1 Spalte (Mobile) umbricht.
Jede Card zeigt: Hauptbild mit Hover-Zoom, Vermarktungsart-Badge (z.B. orangefarbene "KAUF"-Pill), Objekttitel, Meta-Zeile mit Objektart und Ort, Fakten-Boxen für Zimmeranzahl und Wohnfläche, den Preis (orange, fett) und einen "Details ansehen"-Button.
Oberhalb des Grids sitzt ein Orts-Filter als Multiselect-Dropdown (über TomSelect). Der Filter nutzt die onOffice-Plugin-eigene Filterlogik – kein Custom JavaScript für die Datenabfrage, keine eigene Datenbankabfrage. Die Ergebnisse sind paginiert mit klassischen Seitenzahlen über paginate_links().
Detailseite: Galerie, Eckdaten, Karte
Die Detailseite ist der aufwendigste Teil der Integration. Standard: eine Seite mit Freitext-Beschreibung und ein paar Feldern. Custom: eine vollständige Exposé-Darstellung mit mehreren Sektionen.
Der Aufbau der Custom-Detailseite:
- Bildergalerie mit Lightbox: Klick auf das Hauptbild öffnet ein Vollbild-Overlay mit Pfeilnavigation, Tastatur-Support (ESC, Pfeiltasten), Bild-Counter und Hintergrund-Klick zum Schließen
- Dynamische Highlight-Badges: Alle in onOffice gepflegten Highlight-Felder (Balkon, Aufzug, Stellplatz etc.) werden automatisch über
getFieldLabel()ausgelesen und als visuelle Tags dargestellt - Eckdaten: Dynamisch aus der onOffice-Feldkonfiguration – Standardfelder wie Preis, Wohnfläche, Grundstücksfläche, Zimmeranzahl und alle aktivierten Zusatzfelder
- Objektbeschreibung: Freitext aus onOffice, mit sauberem Typografie-Styling
- Lagekarte: OpenStreetMap via Leaflet.js (DSGVO-konform) – Koordinaten direkt aus dem onOffice-Datensatz. Zusätzlich ein "In Google Maps öffnen"-Button für die Navigation
- Ansprechpartner-Box: Rundes Avatar-Foto, Name, Telefon und E-Mail mit Icons, "Kontakt aufnehmen"-Button – auf Desktop sticky in der Sidebar, auf Mobile unter dem Inhalt
- Kontakt-CTA: Button leitet auf die Kontaktseite weiter (kein eingebettetes Formular auf der Detailseite)
Recovery-Plugin gegen Update-Verlust
Custom Templates in templates.dist/ funktionieren – bis zum nächsten Plugin-Update. Dann wird der gesamte Plugin-Ordner ersetzt, und die Anpassungen sind weg. Was passiert außerdem, wenn jemand versehentlich Dateien löscht? Oder ein Hosting-Migration-Script den Ordner nicht mitkopiert?
Für die Hanse Holding habe ich ein eigenes WordPress-Plugin entwickelt: den onOffice Template Guard. Das Plugin hängt sich an den upgrader_process_complete-Hook – wird also nur ausgelöst, wenn WordPress ein Plugin-Update durchführt. Nach jedem onOffice-Plugin-Update prüft es, ob die Custom-Template-Dateien noch vorhanden sind, und stellt sie bei Bedarf automatisch aus einem geschützten Backup wieder her.
// Vereinfachte Recovery-Logik (onOffice Template Guard)
add_action('upgrader_process_complete', function($upgrader, $options) {
if ($options['type'] !== 'plugin') return;
$templates = [
'templates.dist/estate/cardgrid.php',
'templates.dist/estate/custom_detail.php',
'templates.dist/onoffice-style.css',
];
$plugin_dir = WP_PLUGIN_DIR . '/onoffice-for-wp-websites/';
$backup_dir = WP_PLUGIN_DIR . '/onoffice-template-guard/backup/';
foreach ($templates as $tpl) {
if (!file_exists($plugin_dir . $tpl)) {
// Template fehlt → aus Backup wiederherstellen
wp_mkdir_p(dirname($plugin_dir . $tpl));
@copy($backup_dir . $tpl, $plugin_dir . $tpl);
}
}
}, 10, 2);
Im WordPress-Admin gibt es unter Werkzeuge → onOffice Template Guard eine Status-Seite: Sie zeigt an, welche Templates aktuell vorhanden sind, ob das Backup intakt ist, und bietet eine manuelle Wiederherstellung per Klick. Das Plugin läuft nicht bei jedem Seitenaufruf – nur nach Plugin-Updates. Kein Performance-Overhead im Normalbetrieb.
Der Template Guard ist kein technisches Highlight – und das ist der Punkt. Ein Team, das die Website in zwei Jahren wartet, versteht in dreißig Sekunden, was er tut. Die Admin-Seite zeigt grün oder rot, der Hook feuert nur nach Updates, das Backup liegt an einem festen Ort. Manchmal ist die beste Lösung die langweiligste.
DSGVO: OpenStreetMap statt Google Maps
Immobilien-Detailseiten ohne Karte sind wie Exposés ohne Adresse – möglich, aber nicht sinnvoll. Google Maps ist die Standard-Lösung, hat aber DSGVO-Implikationen: Beim Laden werden IP-Adressen und Browser-Daten an Google übertragen. Das erfordert einen Cookie-Consent, und viele Nutzer lehnen ab.
Das onOffice-Plugin bringt bereits eine Kartenlösung mit: Leaflet.js mit OpenStreetMap-Kacheln. Leaflet ist eine Open-Source-Kartenbibliothek (42 KB gzipped), die Kartenkacheln von OpenStreetMap-Servern lädt. Diese Server verarbeiten keine personenbezogenen Daten im DSGVO-Sinne – die Karte ist sofort sichtbar, ohne Consent-Banner, ohne "Externe Inhalte laden"-Overlay.
Die Koordinaten kommen direkt aus dem onOffice-Datensatz – das CRM liefert sie als Bestandteil jedes Immobilien-Datensatzes mit. Keine zusätzliche Geocodierung im Plugin nötig. Für Nutzer, die eine Wegbeschreibung brauchen, gibt es zusätzlich einen "In Google Maps öffnen"-Button, der die Koordinaten als externen Link übergibt – ohne Google Maps auf der Seite selbst einzubetten.
Zahlen & Ergebnis
Das Ergebnis nach der Integration:
- 22 Immobilien live auf der Website, vollständig aus onOffice synchronisiert
- Listenansicht im 3-spaltigen Card-Grid mit Orts-Filter und Pagination
- Detailseiten mit Galerie, Eckdaten, OpenStreetMap-Karte und Ansprechpartner
- Update-sicher: Custom Templates in
templates.dist/+ onOffice Template Guard als Recovery-Mechanismus - DSGVO-konform: Kein Google Maps, keine externen Tracker auf den Immobilien-Seiten
- Responsive: Mobiloptimiert für alle Geräte
Das Live-Ergebnis ist unter verwaltung-hh.com zu sehen.
- Bei "das Plugin funktioniert nicht" zuerst die API-Konfiguration prüfen – nicht das Plugin
- Permalink-Struktur ist kein Detail, sondern eine Voraussetzung für Plugin-Routing
- Custom Templates in
templates.dist/sind der Weg für eigene Designs – trotzdem kennen ihn wenige - Ein Template Guard mit
upgrader_process_complete-Hook klingt nach Overkill, bis das nächste Update die Anpassungen überschreibt - OpenStreetMap + Leaflet.js ist eine vollwertige Google-Maps-Alternative, die DSGVO-Kopfschmerzen eliminiert
Häufige Fragen zur onOffice-WordPress-Integration
Warum zeigt das onOffice-Plugin keine Immobilien an?
Die häufigste Ursache ist ein falsch konfigurierter API-Benutzer in onOffice. Wenn die Berechtigung auf "Objekte lesen: nur eigene" steht statt "alle", liefert die API nur Objekte zurück, die dem API-Benutzer selbst zugewiesen sind – in der Regel null. Zweithäufigste Ursache: Die WordPress-Permalink-Struktur steht nicht auf "Beitragsname", was die Plugin-eigene Routing-Logik für Detailseiten bricht.
Wo liegen die Custom Templates beim onOffice-Plugin?
Custom Templates werden im Verzeichnis templates.dist/estate/ innerhalb des onOffice-Plugin-Ordners abgelegt und über die Plugin-Einstellungen als aktive Templates konfiguriert. Das Problem: Bei Plugin-Updates wird der gesamte Ordner ersetzt. Ohne Absicherung – z.B. durch einen Template Guard – gehen die Anpassungen verloren. Viele Entwickler wissen das nicht und verlieren ihre Templates beim nächsten Update.
Wie verhindert man, dass Plugin-Updates Custom Templates überschreiben?
Ein eigenes Recovery-Plugin – wie der hier entwickelte "onOffice Template Guard" – hängt sich an den WordPress-Hook upgrader_process_complete. Nach jedem onOffice-Plugin-Update prüft es automatisch, ob die Custom-Template-Dateien noch vorhanden sind, und stellt sie bei Bedarf aus einem geschützten Backup wieder her. Im Admin-Bereich unter Werkzeuge gibt es zusätzlich eine Status-Seite mit manueller Wiederherstellungsoption.
Lassen sich onOffice-Immobilien DSGVO-konform mit Karte anzeigen?
Ja. Statt Google Maps lässt sich OpenStreetMap mit Leaflet.js einbinden. Leaflet lädt Kartenkacheln von OpenStreetMap-Servern, die keine personenbezogenen Daten verarbeiten. Damit entfällt die Notwendigkeit eines Cookie-Consents für die Karteneinbindung – die Detailseite ist DSGVO-sauber ohne Einschränkungen.
Eigene onOffice-Integration geplant?
Du brauchst eine individuelle onOffice-WordPress-Anbindung – mit eigenem Design, zuverlässiger Synchronisation und update-sicheren Templates? Schreib mir.
Zur Leistungsseite