Extending a real estate CRM nobody owns the source of
The problem
An agency running its whole sales operation inside a commercial real estate CRM that almost fitted, needing features the product does not offer and cannot be waited on for.
Building on someone else’s commercial theme is a constraint, not an excuse. You cannot patch it, the vendor will overwrite anything you touch, and the client still needs the feature this quarter.
What the agency needed
- Inquiries tied to the specific properties they were about, so an agent opening a lead sees the right listings rather than a generic match.
- A record of properties a lead already owns, which changes the conversation entirely and was simply not modelled.
- Proposal emails in Macedonian, branded, and readable on a phone, because that is where they are opened.
- A history of what was sent to whom, visible from the inquiry rather than reconstructed from a sent folder.
- Deal reminders with a dashboard that shows at a glance what is going cold.
- Search across the whole inquiry table, not just the page of it currently on screen.
Outreach over Viber
In this market Viber is where property conversations actually happen, and no Western real estate tooling accounts for that. Agents now compose a property proposal from the matched listings and send it through Viber directly.
Getting there took a detour worth recording. The obvious implementation, handing Viber a pre-filled message through its URL scheme, silently loses to the page’s own social metadata — Viber reads the link preview and shares that instead of the message. The working answer was a preview modal with the message editable and copied to the clipboard, then Viber opened separately. Slightly less elegant, and it actually sends what the agent wrote.
Built to survive the next update
- Template changes live in a child theme, never in the parent.
- Custom logic is injected rather than forked, so a theme update does not silently revert a feature.
- Branded email markup sits in an override that survives the plugin being updated underneath it.
- Where the CRM’s own methods return only a paginated slice of the data, the dashboard search queries the tables directly, so filtering works across every record rather than across the current page.
The one that cost a day
Data added by a custom field kept vanishing on save. The cause was that the CRM answers its own AJAX request and terminates the PHP process before late-priority hooks ever run, so the save code was never reached. Moving the write to a hook that fires during shutdown fixed it permanently. Nothing in the documentation says this; the only way to find it is to read the plugin and watch the log.
The outcome
A layer of custom functionality over the CRM covering inquiry-to-property tracking, agent outreach over Viber, branded Macedonian proposal emails and a searchable inquiry dashboard, all built to survive theme and plugin updates.
