Over the past few weeks/months, I have been working on an internal tool to be used by a prominent network of commercial estate agents. These agents work in partnership with a leading pension provider.
The nature of the relationship is that some pension funds are invested in commercial property, therefore to assess the value of a pension meaningfully, the properties need to be valued. This tool essentially boils down to a CRM, whereby the person issuing the instruction can check the progress at any time, and the two organisations will have a centralised tool for easy sharing of information.
As a developer at Geek Designs, I relish an opportunity to work on a project like this. While I do enjoy doing typical websites for businesses, I enjoy the project management and problem-solving involved in a job of this nature, and it’s nice to have an opportunity to plan out a piece of bespoke software like this, on a macroscopic scale.
I built this tool using WordPress. I did look into using other frameworks, such as Django and Rails, but was won over by WordPress. A large selling point for me was the enormous ecosystem of theme and plugin developers, although in this case, I didn’t use a huge amount of third-party plugins.
However, access to this vast library of added functionality did streamline specific steps of the process. Add to this the massive amount of hooks throughout both the front and backend of WordPress and what you have is an easily extensible base for your web app, with a relatively high level of security out of the box.
As this is a CRM type tool, there isn’t really any need for the site to serve a frontend, so I disabled it, with any unrecognised URL redirecting to the login. The WordPress backend, in my opinion, isn’t the most attractive piece of software so that we will be doing some cosmetic work. I’ll go into more detail on this later
This application makes use of an incredibly powerful plugin for WordPress called “Advanced Custom Fields”, hereafter referred to as ACF. What ACF does, is to allow you to (as the name suggests) add custom data to basically anything you want, pages, posts, users, etc. It also has a lot of potential for bespoke websites, as it could conceivably be used to add content “slots” into a page.
The template could be defined via WordPress using PHP, or even using a frontend library such as React for a “decoupled” site, with WordPress acting solely as a CMS and a separate application handling the presentation (via WordPress’ REST API). I’d like to do a write-up on this process in future.
The first step was to create a custom post type (CPT), to represent an instruction. This is a relatively simple task with WordPress. With just a handful of lines of PHP needed to register a custom post type, there are also plugins that achieve this. However, I wanted to keep third-party plugins to a minimum to reduce bloat.
From here I had to establish a fieldset for each instruction. For this, I used ACF, while it isn’t especially complicated to do this manually using PHP, and WordPress’ built-in wp_postmeta table. ACF streamlines this process a lot and makes it easier to revise in future if need be. At this point, the Instruction post type is basically a massive form that is accessible by any logged in user.
This doesn’t work for us, as although we can probably trust all parties involved, we don’t want everybody to be able to edit whatever they please. That’s why we enter custom user roles. Each of these roles will have read-only access to some fields and write access to others.
There is an “Admin” (though not in the conventional WordPress sense, I’m the only user with absolute privileges), who can modify any field, for conflict resolution. Etc. The way ACF works is that fields a user doesn’t have access to won’t be outputted at all, as a disabled input is not a secure way to ensure that users do not modify fields. This caused an issue in that while some roles shouldn’t be able to edit some information, they do need to be able to read it to work from it.
For this, I made a custom plugin. This plugin makes use of WordPress metaboxes on the instruction edit screen. What this does is display the initial information in plain text, not inputs, allowing for secure read-only access to this information for certain users. I then styled this information to match the layout of the fundamental form, to make things easier for the admins who may at some point have to use both.
Next, I created a CPT for Firms, and this contains far less information. It has a comma-separated list of active postcodes, a phone number, email and User ID. There is one for each of the (roughly) 30 firms involved. The primary use for this is to assign ownership of an instruction to the most geographically convenient firm, along with giving the initial instruction author a point of contact should they need to chase anything up. The way this happens is that when you save an instruction, the server loops through every Firm checking, it’s active postcodes (which can include wildcards – causing a little head-scratching). You then store potential matches in an array of Firm IDs.
As the active postcodes of the firms are fine-tuned to avoid conflicts, hopefully, this will become the vast majority of cases. In case of either conflict or no active firm nearby, the instruction will assign to the firm which oversees the whole application. When you assign ownership to a valuation firm, they will receive a notification via email. This will also happen when a case is complete, ownership will then return to the original author, who they notify, and you can activate the gathered information.
I knew that I would need to do some relatively drastic modification of the backend of the site, partly for cosmetic purposes but also for practical purposes, as the sheer amount of information required on the “List View”, would have quickly filled the available width and become unreadable. There were several approaches I looked into for this.
The first thought of mine was to make a child of WordPress’ built-in Admin Table class. This class is used to display all of the list views in the backend, including posts, pages, users, etc. My thought was that it could be modified to use DIVs instead of HTML table elements, as this would be more flexible. Potentially with relevant fields grouped in ordinary parent DIVs, and this would allow me to break each listed item into two or three rows. This action would essentially double the width, increasing the amount of readable information available at a glance.
In the end, I concluded that by changing the display property of my table cells, I could achieve most of this. There is a slight drawback in that I don’t have full control over the markup I output, so I can’t group related fields in the markup (however I have done visually).
I also added a progress bar, which consists of 5 Boolean values for each instruction. Each one of these represents a significant step along the process, the first being “Firm Nominated” and the last being “Invoice Submitted”. This should be handy, as an empty progress bar will signify to the Admin that this instruction needs attention to progress (they will also receive an email notification).
Eventually, I would like to make the instructions sortable by progress, as this will be a useful view both to the pension provider agents, and the administrators of the service.
I also modified the login screen as this is essentially the homepage now, seeing as there isn’t technically a frontend. There are a few hooks on the login page I used (header and footer), this allows me to style this page without modifying any core files, instead – using a plugin. I moved the original login form into a modal, triggered by a login button. Then for a touch of visual interest, I created a carousel of sorts, which displays the valuation firm logos.
At the time of writing, there are still some features I need to implement. The most interesting of which is the ability to export KPI tracking information. The information is mainly how early or late reports are delivered based on the expected date. The results will give an integer value, i.e., 1 for a day early. You can then average the data to provide an overall score.
This will be on a site-wide and a per-firm basis, allowing the administrators to assess which firms are performing best. Also, how to identify any persistently late firms. I put quite a lot of thought into how to implement this. I toyed with the idea of a third CPT to hold only the critical information for this tracking. However, I eventually concluded the best way would be to make a special status for completed instructions; after which point they would archive and only be visible to individual users. This would then serve as the data source for the KPI tracking.
Thanks for reading, and I hope this is of interest! I am planning to do a write-up like this once a month, workload allowing.