verwaltung-hh.com – Immobilien-Bereich der HR Hanse Holding

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 in Zahlen

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.

onOffice API-Response
// 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.

Häufigster Fehler bei onOffice-Integrationen

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:

Custom Template-Dateien
  • 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 in templates.dist/, das die Plugin-Styles überschreibt
Verzeichnisstruktur
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().

Listenansicht mit Card-Grid und Orts-Filter auf verwaltung-hh.com
3-spaltiges Card-Grid mit Orts-Filter (TomSelect) und Pagination. Responsiv auf 2 und 1 Spalte.

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)
Detailseite mit Galerie, Eckdaten und OpenStreetMap-Karte auf verwaltung-hh.com
Custom-Detailseite im Corporate Design: Bildergalerie, Eckdaten und OpenStreetMap-Karte.

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.

PHP
// 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.

Wartbarkeit über Cleverness

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.

Was ich aus diesem Projekt mitgenommen habe
  • 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