Work/White-Label/ATS Integration & Location SEO
WL White-Label Engagementstaffing & workforce · confidential client

Live ATS sync plus AI-generated SEO for every market you serve.

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.

What we built
Two-plugin WordPress system
Industry
Staffing & workforce solutions
Delivery
White-labelconfidential
Integrates with
Their ATS platformlive sync
Job Board + Location Pages · Live System
// ats jobs · live sync
Detroit, MI ✕ Healthcare Full-Time
Registered Nurse – ICU
Full-Time · Healthcare · Synced 4 min ago
📍 Detroit, MI
Medical Lab Technician
Contract · Healthcare · Synced 4 min ago
📍 Detroit, MI
Light Industrial Assembler
Temp-to-Hire · Manufacturing · Synced 4 min ago
📍 Southfield, MI
// location pages · ai-generated
yoursite.com/jobs/michigan/detroit
Jobs in Detroit, MI | Staffing & Placement
✦ AI-generated · 547 words · auto-published
Detroit's healthcare and manufacturing sectors continue to see strong demand for skilled workers in 2025. Our staffing team specializes in connecting Detroit-area employers with qualified candidates across nursing, light industrial, and administrative roles…
TitleJobs in Detroit, MI — 12 Open Positions
Meta descBrowse 12 open jobs in Detroit, MI…
SchemaJobPosting ✓
StatusPublished ✓
RN – ICU Lab Tech Assembler +9 more
// three problems that needed three different solutions

The ATS has the jobs. WordPress has the audience. Nothing connected them — cleanly, at scale, with SEO built in.

🔗

No live ATS integration

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.

🔍

No search presence by market

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.

📁

Legacy site to migrate

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.

// the solution · two plugins, one system

Plugin 01 owns the data. Plugin 02 owns the pages.

Clear separation of concerns — one plugin could be swapped or upgraded without touching the other.

plugin 01 · ats jobs · v1.0.8

The data layer.

Everything that touches the ATS lives here. The rest of the site — and Plugin 02 — only ever asks this plugin for data.

JWT auth exchange

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.

📡

15-minute cron sync

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.

📍

Geocoding cache

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.

🗂️

Location normalizer

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.

📋

4 frontend shortcodes

[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.

📝

Structured logger

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.

plugin 02 · location pages · v0.5.1

The SEO layer.

Depends on Plugin 01. Location data flows from the live sync — no manual data entry, no duplicate sources of truth.

📄

Auto-generated CPT

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.

AI content per page

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.

👁️

Auto-draft on no jobs

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.

🔄

Daily content refresh

A daily cron checks every published page. Stale content or changed job counts trigger AI regeneration automatically — pages stay current without manual intervention.

Hooks into sync completion

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.

🎛️

Admin regenerate-on-demand

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.

// end-to-end pipeline

From a new job in the ATS to a ranked, AI-described city page — in 15 minutes.

Client ATS
job published in ATS
ATS Jobs
JWT auth · 15-min cron · geocode · normalize
Sync Complete hook
ats_jobs_sync_complete
Location Pages
new city detected · CPT created
AI Generator
OpenAI · 500-600 words · voice profile
SEO Handler
title · meta · schema · auto-publish
JWT auto-renew15-min cron syncGeocoding cacheLocation normalizer AI content generationAuto-draft / auto-publishDaily refresh cron Schema markupYoast compatibleRankMath compatible
// seo at scale

Hundreds of location pages. Every one unique.

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.

AI content that uses live job data

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.

🗣️

Voice profile from settings

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.

📐

Proper heading structure

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.

🔄

Dynamic job counts in metadata

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.

🏷️

Schema markup per page

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.

🗺️

Sitemap-ready CPT

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.

// every location page gets
Unique AI content · 500–600 words H1 / H2 / H3 structure Live job count in title tag Unique meta description JobPosting schema Yoast SEO compatible RankMath compatible Auto-draft when jobs = 0 Auto-publish when jobs return Daily content refresh Sitemap-ready out of the box

The location normalizer — because client data is never clean.

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.

Detroit, MichiganDetroit, MIfull state name → abbreviation
Detroit, MI 48226Detroit, MIZIP code stripped
: Detroit, MichiganDetroit, MIstray prefix removed
26100 American Dr, Southfield, MI 48034Southfield, MIstreet address → city/state only
// third tool · built in the same engagement

Legacy website migration — without touching WordPress posts.

📁

A purpose-built scraper that crawled the old site and stored it — cleanly, separately, non-destructively.

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.

// by the numbers

What the system delivers.

15 min
from ATS publish to live on site
3
plugins built in one engagement
Auto
location pages created, drafted, refreshed
0
manual steps to keep job board current

Need your ATS talking to your website — and your website ranking everywhere you work?

We've built this system. We can build the right version of it for your platform and your markets.