How We Built a Physician Directory for a US Health System Using WordPress
Building a physician directory sounds straightforward. A list of doctors, some filters, a search box. That framing will get you into trouble fast.
When Commonwealth Health came to us, the brief had three constraints that changed everything: the directory had to live inside their existing enterprise CMS, it could not inherit any of that CMS's global styles, and non-technical staff needed to update physician records without touching code. That combination is harder than it sounds.
The Enterprise CMS Problem
Commonwealth Health runs a large content management system across their entire network. Our directory component would be embedded as a module inside that system. The parent CMS had decades of accumulated CSS, including aggressive global rules that would override almost anything we wrote.
The first thing we did was map what we were actually dealing with. We pulled the parent stylesheet and catalogued every rule that could interfere: font resets, link colours, button styles, margin overrides applied to div and p elements directly. There were a lot of them.
The solution was to treat our component as if it were a completely foreign application. We used CSS custom properties scoped to a single wrapper class, giving us our own design tokens that the parent system could not touch. For anything the parent CSS was aggressive about, we used the Shadow DOM to create genuine style isolation. The component's internal DOM lives in its own encapsulated context. Styles in, styles out. Nothing bleeds.
This is not the approach you reach for on a simple site build. But when you are working inside an enterprise environment you do not control, it is the only one that holds.
Search and Filter Without a Plugin
The instinct on a WordPress project is to reach for a plugin. For a physician directory, that usually means SearchWP or FacetWP. Both are solid tools. Neither was appropriate here.
Commonwealth Health had specific filter requirements: specialty, location, accepting new patients, gender, telehealth availability. The filter interactions needed to be immediate, with no page reload. The parent CMS had JavaScript conflicts that ruled out several popular libraries.
We wrote the search and filter logic in vanilla JavaScript. The directory data was loaded as a JSON payload on page initialisation, and all filtering happened client-side. This gave us complete control over the interaction, zero plugin dependencies, and a faster user experience than any server-side filtered result could deliver.
The JavaScript was modular: a data layer, a filter engine, a DOM renderer, and a URL state manager so filtered views could be bookmarked and shared. Each piece tested independently. When Commonwealth Health's IT team reviewed the code for security sign-off, the separation made that process faster.
The Excel Data Pipeline
Non-technical staff needed to update physician records. This happens constantly in a health system. Doctors join the network, change locations, update their accepted insurances, go on extended leave. If every update required a developer, the directory would be out of date within a month.
We built a pipeline that starts with an Excel template. Staff fill in physician details using a spreadsheet that validates inputs with column-level rules: dropdown lists for specialties, required fields flagged, phone number formatting enforced. The completed spreadsheet feeds into a Python script that normalises the data and imports it into WordPress as custom post type entries via WP-CLI.
The staff guide we wrote covers the full process in 12 pages. Screenshots at every step. What happens if a required field is blank. How to handle a physician with multiple locations. How to run the import without breaking existing records. We tested the guide with three people from the Commonwealth Health admin team before finalising it. They found 4 points that needed clearer language.
That feedback loop matters. A guide written by developers for non-developers will almost always assume too much.
What WCAG Compliance Actually Requires at This Scale
The physician directory had to meet WCAG 2.1 AA. That is the standard. But at the scale of a physician directory, hitting AA is more work than it sounds.
Every physician card needed proper heading hierarchy. Every image needed alt text, which meant every physician needed a photo or a described placeholder. Every filter control needed a visible label, not just a placeholder attribute. Every interactive element needed a focus state that met the 3:1 contrast ratio against the adjacent colour. The search input needed to be operable by keyboard. Results needed to announce themselves to screen readers when filters changed.
That last one is the one people miss. When a user applies a filter and 12 results appear, a sighted user sees it immediately. A screen reader user hears nothing unless you use an ARIA live region to announce the change. We wrapped the results count in a role="status" element with aria-live="polite". When filters update, the reader announces the new count automatically.
We ran every page state through axe and Lighthouse during development. Not just once at the end. At every significant milestone. Finding an accessibility failure late in a project is expensive. Finding it during development costs almost nothing.
What We Learned from Working Inside Enterprise Constraints
The constraints that felt like obstacles shaped a better product. Because we could not rely on the parent CMS's styles, we built a component that is genuinely portable. Because we could not use plugins, we wrote leaner JavaScript that the client actually understands. Because the data pipeline had to work for non-developers, we built something more reliable than a manual process could ever be.
Enterprise projects reward discipline. Every decision needs a reason. Every dependency is a risk. Every assumption about what the hosting environment will tolerate needs to be tested.
If you are scoping a similar project, the questions to answer before writing a line of code are: what CSS does the parent environment inject globally, what JavaScript libraries are already loaded, what are the deployment and code review constraints, and who owns updates after handover.
Get those answers in writing. They will save you weeks.
If your organisation is dealing with a complex component build inside an existing system, talk to us about how we approach it.

