Sports API Hub acts as a data bridge between external sports APIs and your WordPress frontend. This page explains the architecture, data flow, and design decisions that shape how the plugin works.
🚀 Hub Architecture
The plugin follows a hub-and-spoke model: one central connector pulls data from external APIs and distributes it through WordPress.
| Layer | What It Does | Details |
|---|---|---|
| 🌐 External Sports API | Source of all sports data | AllSportsAPI2 (multi-sport), BasketAPI1 (basketball), BaseballAPI (baseball) |
| ↓ | ||
| 🔌 API Adapter | Connects to API, normalizes data | Authentication headers, rate limit handling, automatic retries, response mapping |
| ↓ | ||
| 🗃️ Custom DB Tables | Stores all sports data | 19 tables — entities, per-game stats, aggregate stats cache, logs. Queryable fields as real columns, display-only data as JSON |
| ↓ | ||
| 📄 WordPress Posts | WordPress integration layer | 6 thin CPTs with only sport_id + api_id meta. Provides permalinks, search, sitemaps |
| ↓ | ||
| 🎨 Frontend Pages | What visitors see | Game, Team, Player, Season pages + 13 shortcodes + live scores. Layout Builder or template-based |
Data Flow: From API to Frontend
1. API Request
When you trigger an import or the background sync runs, the plugin sends HTTP requests to the external API. All requests are server-side — your visitors’ browsers never contact the API directly.
2. Data Normalization
API responses are JSON objects with nested structures. The adapter extracts relevant fields and maps them to the plugin’s table schema. For example, an API “uniqueTournament” becomes a row in the leagues table.
3. Database Upsert
Data is inserted or updated using “upsert” operations — if the record already exists (matched by sport ID + API ID), it is updated; if not, it is created. This makes re-imports safe: running the same import twice does not create duplicate data.
4. Post Creation
After upserting a database record, the plugin creates a corresponding WordPress post if one does not already exist. These posts are minimal — just a title and two meta fields. Posts provide permalinks, WordPress search integration, and XML sitemap entries. The actual data is always read from the custom tables.
5. Cache Invalidation
After data changes, the plugin invalidates relevant caches (object cache groups, page cache) so that frontend pages show fresh data.
6. Template Rendering
When a visitor loads a game, team, or player page, the template system resolves the entity from the URL, fetches data from custom tables, prepares display-ready data (team names, logos, display order), and renders the appropriate template or Layout Builder layout.
Read-Only Philosophy
The plugin is designed around the principle that the API is the source of truth:
- Most data is fetched, not entered manually
- Re-importing a season updates existing records with the latest API data
- Manual edits to entity names are preserved through a translation system
- The plugin does not write data back to the API — it is a one-way data consumer
You can enrich data through the plugin (custom logos, translated names, Layout Builder pages, AI-generated content), but the core statistics, scores, and rosters come from the API.
Six Entity Types
The plugin manages six types of data entities:
| Entity | What It Represents | Frontend Page |
|---|---|---|
| Games | Individual matches with scores, stats, timeline | Yes |
| Teams | Team profiles with roster, colors, venue | Yes |
| Players | Player profiles with position, stats, photo | Yes |
| Seasons | Year-specific competitions (e.g., NBA 2025/26) | Yes |
| Venues | Stadiums and arenas | Admin only |
| Managers | Coaches and managers | Admin only |
Additionally, Categories (countries/regions) and Leagues are stored in their own tables but do not have frontend pages — they serve as organizational containers for seasons.
Multi-Sport in a Single Installation
All sports share the same entity tables with a sport_id column that separates them:
- Separate permalink bases —
/basketball/,/baseball/, etc. - Separate statistics tables — each sport has its own optimized stat schema
- Separate admin filters — lists can be filtered by sport
- Separate Layout Builder layouts — different page designs per sport
See Sports for a detailed capability matrix.
⚙️ Admin Menu Structure
The plugin adds four root menus to your WordPress admin sidebar:
| Menu | Contains |
|---|---|
| Sports API Hub | Dashboard, Support, Account |
| Hub Data | Games, Teams, Players, Venues, Managers, Seasons |
| API & Import | Import, API Config, Custom Logos |
| Settings & Tools | Settings, Translations, Shortcodes, Entity Links, Layout Builder, AI Writer |
Dual Data Sources: API + Database
Statistics blocks on team and season pages can pull data from two sources:
- API aggregates — pre-computed stats fetched directly from the sports API (season totals, leaderboards, advanced metrics like PER or WAR). Loaded on demand with stale-while-revalidate caching.
- Database — stats calculated from per-game data stored during import. Always available once games are imported.
In the Layout Builder, stats blocks offer a Data Source setting with four modes:
| Mode | Behavior |
|---|---|
| API | Always use API aggregates |
| DB | Always compute from imported game data |
| API first | Try API, fall back to DB if unavailable |
| DB first | Use DB if game data exists, otherwise try API |
This hybrid approach means you always have stats to show — even when the API doesn’t provide aggregate endpoints for a particular sport or league. Basketball defaults to DB-first (rich per-game data), while sports with limited DB coverage can rely on API aggregates.
Caching
The plugin uses WordPress object cache (Redis/Memcached) for data caching. Cached data is grouped by entity type and automatically invalidated when imports, live updates, or syncs change the underlying data.
For sites behind a page cache, the plugin can flush page caches when data changes. See Caching for configuration details.
📚 Related
- Sports — sport-by-sport capabilities
- Games — game data and statuses
- Entity Translations — customizing imported names
- Caching — cache configuration
- Import Workflow — how to import data
