A national staffing company needed their ATS jobs live on their WordPress site — filterable, mapped, and ranking in every city and state they placed talent. We built two plugins that work as a system.
The ATS has the jobs. WordPress has the audience. Nothing connected them — cleanly, at scale, with SEO built in.
Their ATS has no official WordPress plugin. Jobs lived in the ATS and died there — manually exported, manually posted, always out of date. A national firm placing in dozens of markets can't run that way.
Ranking for "jobs in Detroit, MI" or "staffing in Toledo, OH" requires a dedicated, unique page for each location. There were none — and no practical way to write hundreds of them by hand.
Years of content on an old website. No structured export, no WordPress-compatible format. The old content had to be preserved during the rebuild without manual copy-paste across hundreds of pages.
Clear separation of concerns — one plugin could be swapped or upgraded without touching the other.
Everything that touches the ATS lives here. The rest of the site — and Plugin 02 — only ever asks this plugin for data.
Authenticates with the ATS API and auto-renews the JWT token on every 15-minute sync cycle — the site never goes offline due to an expired credential.
Fetches all active job records from the ATS on a cron schedule and stores them locally. Jobs appear on the site within 15 minutes of being published in the ATS.
Each unique location is geocoded once and cached persistently. Never re-fetched unless the address changes — no API quota drain from the same city being re-geocoded on every sync.
Collapses "Detroit, Michigan," "Detroit, MI," and "Detroit, MI 48226" into one consistent filter option. The client's ATS data was inconsistent — this engine handles every known variant.
[ats_jobs_list] filterable grid · [ats_jobs_single] full job detail · [ats_jobs_map] interactive location map · [ats_jobs_search] standalone search bar — each independently embeddable anywhere.
Sync events, geocode hits and misses, API errors — all logged to a dedicated table queryable from the WP admin. A full audit trail without cluttering PHP's error_log.
Depends on Plugin 01. Location data flows from the live sync — no manual data entry, no duplicate sources of truth.
Creates one job_location_page CPT record per state and per city — entirely automatically, based on where live jobs exist. Pages appear and disappear as inventory moves.
OpenAI generates 500–600 words of unique, heading-structured content for every state and city — using the client's voice profile from the plugin settings. Every page is different. None are templated duplicates.
When a location has no active jobs, its page is automatically drafted — no dead pages ranking for places where the client has nothing to offer. When new jobs arrive, the page publishes again.
A daily cron checks every published page. Stale content or changed job counts trigger AI regeneration automatically — pages stay current without manual intervention.
When Plugin 01 finishes a sync and fires ats_jobs_sync_complete, Plugin 02 immediately checks for new or removed locations. A new city in the ATS gets a page within 15 minutes.
Any location page can be manually regenerated from the WP admin — useful after changing the voice profile in settings or when a market needs freshened content.
Templated location pages get filtered by Google. Pages that repeat the same copy with only the city name changed don't rank — they compete with each other and dilute the domain. Every page generated by this system is written from scratch for that specific location, using the live job data as context.
The content generator receives the specific jobs active in that city — job titles, industries, job counts — and writes content that reflects the real opportunity landscape there. Not a generic "we staff in Detroit" paragraph.
The system prompt for OpenAI is built from a voice profile the admin configures in the plugin settings — brand tone, keyword priorities, required disclaimers. Every page sounds like the same company.
H1, H2, and H3 are part of the generation spec — not left to the AI. Every page arrives with a correct heading hierarchy that search engines can parse cleanly.
Title tags and meta descriptions include the live job count for that location — "Browse 12 open jobs in Detroit, MI" — updated whenever the page regenerates, so metadata reflects reality.
JobPosting schema written to the head of every location page. Compatible with Yoast SEO and RankMath — the SEO handler hooks into both and yields to whichever is active.
The job_location_page CPT is registered as public and show_in_rest — it's picked up by WordPress core sitemaps, Yoast, and RankMath automatically, with no additional configuration.
The client's ATS records used inconsistent location formats. Without normalization, the same city appeared as multiple filter options — and as multiple separate location pages, each too thin to rank. The normalizer collapses every variant to a single canonical "City, ST" form before any page is created or any filter is built.
The client had years of content on a legacy website with no structured export and no WordPress-compatible format. We built a third plugin that crawled the old site, scraped every page and media asset, and stored them in a structured internal database — without creating WordPress posts or pages. The full content archive was preserved during the rebuild with zero manual copy-paste. When the new site was ready, the migrated content was available for selective import. A purpose-built tool for a specific one-time problem, built and deployed alongside the main system in the same engagement.
We've built this system. We can build the right version of it for your platform and your markets.