Maintainer overview of the hybrid content type, DRM download path, and telemetry.
Objects and relationship
| Object | Slug | Notes |
|---|---|---|
| Post type | dataset | Content and meta for each dataset |
| Taxonomy | datasets (rewrite slug dataset) | Term archives at /dataset/{slug}/ |
\PRC\TDS\add_relationship() links each term to its dataset post. CPT archive paths use custom rewrites for /datasets/ and /datasets/{year}/, plus research-team-prefixed URLs from prc_research_teams_rewrite_config.
Post types with prc-datasets support (post, feature, chart by default) can be tagged. Extend via add_post_type_support or prc_platform__datasets_enabled_post_types.
Download DRM
includes/class-rest-api.php resolves the file from _download_attachment_id or legacy dataset_download_url meta. Public get-download verifies Firebase identity via User_Data before returning a URL, then calls PRC\Platform\User_Accounts\Protected_Files::grant_for_user(). That stamps _prc_protected on the attachment, runs extra gates (ATP via prc_user_accounts_can_grant_protected_file), and returns the file URL. When the generic /protected-files/download route omits dataset_id, the same ATP gate looks up datasets that use the attachment. Ability callers keep the default (false) and do not stamp _download_unavailable. User-facing endpoints require Firebase headers (not page nonces). ATP state still lives on the Firebase user record.
get-download enforces per-IP rate limiting through \PRC\Platform\rate_limit_hit().
Telemetry meta
| Key | Purpose |
|---|---|
_total_downloads | All-time count |
_downloads_{year} | Monthly buckets |
_downloads_daily_{year} | Day buckets (from 2026-08-01) |
new_data_uploaded | Datetime for before/after month splits |
is_atp | ATP gate flag |
_download_attachment_id | Media attachment ID |
_download_unavailable | Public download resolve failed (DataViews filter) |
_roper_archive_id | Roper archive ID stamped by prc-roper when a survey question matches this dataset |
Stats responses are cached 24h via dataset_downloads_{id} transient (invalidated on relevant meta changes). The _downloads REST field exposes the same structure on the dataset post type.
Admin DataViews
Datasets > All Datasets exposes zipStatus (attachment meta) and downloadUnavailable (_download_unavailable) filters via includes/class-dataset-list.php and src/admin-dataview/fields.jsx.
Search and packages
Datasets opt into sitewide search and ElasticPress archive faceting. Dataset terms append to prc_platform_post_report_package_materials for report sidebars.
CLI
wp prc datasets atp-downloads [--year=<year>] [--detailed] [--per-dataset]
wp prc datasets build-audience --dataset-id=<id> [--dry-run]
wp prc datasets missing-files [--dry-run]
build-audience starts a Firebase enqueue job and waits at the terminal until the list is ready. --dry-run still scans and reports counts, but WordPress does not write options. The Dataset Options sidebar can Generate / Rebuild / Delete audiences via REST. The inspector polls the job; it does not wait on a 540s HTTP call.
Key files
| Path | Role |
|---|---|
includes/class-content-type.php | CPT, taxonomy, rewrites, meta |
includes/class-audience-service.php | Downloader audience build / list / delete |
includes/class-rest-api.php | Download / ATP / stats / audience routes |
includes/class-ability.php | Abilities API tools |
includes/inspector-sidebar-panel/ | Editor Dataset Options (file, stats, audience, plus a prc-datasets/options-after slot) |
src/download-block/ | Download Interactivity block |
src/dataset-atp-legal-acceptance-block/ | ATP form block |