Guide

Datasets architecture

Maintainer overview of the hybrid content type, DRM download path, and telemetry.

Objects and relationship

ObjectSlugNotes
Post typedatasetContent and meta for each dataset
Taxonomydatasets (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

KeyPurpose
_total_downloadsAll-time count
_downloads_{year}Monthly buckets
_downloads_daily_{year}Day buckets (from 2026-08-01)
new_data_uploadedDatetime for before/after month splits
is_atpATP gate flag
_download_attachment_idMedia attachment ID
_download_unavailablePublic download resolve failed (DataViews filter)
_roper_archive_idRoper 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

PathRole
includes/class-content-type.phpCPT, taxonomy, rewrites, meta
includes/class-audience-service.phpDownloader audience build / list / delete
includes/class-rest-api.phpDownload / ATP / stats / audience routes
includes/class-ability.phpAbilities 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

Was this helpful?