Guide

Document model

This document provides a comprehensive overview of the document model and relationships between post types, meta fields, and taxonomies across the PRC-* plugins in the Pew Research Center WordPress platform.

Architecture Overview

The PRC Platform uses a modular plugin architecture where:

  • Post types define content entities (articles, staff, datasets, etc.)
  • Taxonomies provide classification and organization (topics, teams, formats)
  • Meta fields store additional structured data on posts
  • Term Data Store (TDS) pattern links post types to taxonomies for hybrid content

Visual Diagram

erDiagram
    %% ===========================================
    %% CORE CONTENT POST TYPES
    %% ===========================================

    POST {
        int ID PK
        string post_title
        text post_content
        string post_status
        datetime post_date
    }

    FEATURE {
        int ID PK
        string post_title
        text post_content
        string _feature_dev_notes
        array _feature_rewrites
    }

    QUIZ {
        int ID PK
        string post_title
        text post_content
        object _report
    }

    CHART {
        int ID PK
        string post_title
        text post_content
    }

    DATASET {
        int ID PK
        string post_title
        text post_content
        int _download_attachment_id
        int _total_downloads
        boolean is_atp
        string dataset_schema
    }

    COLLECTIONS {
        int ID PK
        string post_title
        text post_content
        string kicker_pattern_slug
    }

    %% ===========================================
    %% STAFF & BYLINES
    %% ===========================================

    STAFF {
        int ID PK
        string post_title
        text post_content
        string jobTitle
        string jobTitleExtended
        boolean bylineLinkEnabled
        object _maelstrom
        array socialProfiles
    }

    %% ===========================================
    %% UTILITY POST TYPES
    %% ===========================================

    HOMEPAGE {
        int ID PK
        string post_title
        text post_content
    }

    BLOCK_MODULE {
        int ID PK
        string post_title
        text post_content
        array _story_item_ids
    }

    NOTE {
        int ID PK
        string post_title
        text post_content
        array shared_with_users
    }

    DATA_TABLE {
        int ID PK
        string post_title
        text post_content
    }

    DOCUMENTATION {
        int ID PK
        string post_title
        text post_content
    }

    RELEASE_NOTE {
        int ID PK
        string post_title
        text post_content
    }

    RLS_TEMPLATE {
        int ID PK
        string post_title
        text post_content
    }

    %% ===========================================
    %% TAXONOMIES
    %% ===========================================

    CATEGORY {
        int term_id PK
        string name
        string slug
        int parent
    }

    RESEARCH_TEAMS {
        int term_id PK
        string name
        string slug
        int parent
    }

    FORMATS {
        int term_id PK
        string name
        string slug
    }

    BYLINES {
        int term_id PK
        string name
        string slug
        boolean is_guest_author
    }

    COLLECTION_TAX {
        int term_id PK
        string name
        string slug
        int parent
    }

    DATASETS_TAX {
        int term_id PK
        string name
        string slug
        int parent
    }

    REGIONS_COUNTRIES {
        int term_id PK
        string name
        string slug
        int parent
    }

    LANGUAGES {
        int term_id PK
        string name
        string slug
    }

    AREAS_OF_EXPERTISE {
        int term_id PK
        string name
        string slug
        int parent
    }

    STAFF_TYPE {
        int term_id PK
        string name
        string slug
        int parent
    }

    FUND_POOLS {
        int term_id PK
        string name
        string slug
        string funder_url
        string funder_id
        float _funder_budget
    }

    MODE_OF_ANALYSIS {
        int term_id PK
        string name
        string slug
    }

    POST_VISIBILITY {
        int term_id PK
        string name
        string slug
    }

    BLOCK_AREA {
        int term_id PK
        string name
        string slug
        int parent
    }

    LEVEL_OF_EFFORT {
        int term_id PK
        string name
        string slug
    }

    PRIMARY_AUDIENCE {
        int term_id PK
        string name
        string slug
    }

    INFORMATION_TYPE {
        int term_id PK
        string name
        string slug
    }

    DECODED_CATEGORY {
        int term_id PK
        string name
        string slug
    }

    %% ===========================================
    %% RELATIONSHIPS - Core Post Type
    %% ===========================================

    POST ||--o{ CATEGORY : "has topics"
    POST ||--o{ RESEARCH_TEAMS : "belongs to"
    POST ||--o{ FORMATS : "has format"
    POST ||--o{ BYLINES : "authored by"
    POST ||--o{ COLLECTION_TAX : "part of"
    POST ||--o{ DATASETS_TAX : "has dataset"
    POST ||--o{ REGIONS_COUNTRIES : "covers"
    POST ||--o{ LANGUAGES : "written in"
    POST ||--o{ POST_VISIBILITY : "visibility"

    %% ===========================================
    %% RELATIONSHIPS - Feature
    %% ===========================================

    FEATURE ||--o{ CATEGORY : "has topics"
    FEATURE ||--o{ RESEARCH_TEAMS : "belongs to"
    FEATURE ||--o{ BYLINES : "authored by"
    FEATURE ||--o{ DATASETS_TAX : "has dataset"
    FEATURE ||--o{ COLLECTION_TAX : "part of"
    FEATURE ||--o{ REGIONS_COUNTRIES : "covers"

    %% ===========================================
    %% RELATIONSHIPS - Quiz
    %% ===========================================

    QUIZ ||--o{ CATEGORY : "has topics"
    QUIZ ||--o{ RESEARCH_TEAMS : "belongs to"
    QUIZ ||--o{ BYLINES : "authored by"
    QUIZ ||--o{ DATASETS_TAX : "has dataset"
    QUIZ ||--o{ COLLECTION_TAX : "part of"
    QUIZ ||--o{ LEVEL_OF_EFFORT : "effort level"
    QUIZ ||--o{ PRIMARY_AUDIENCE : "audience"
    QUIZ ||--o{ INFORMATION_TYPE : "info type"

    %% ===========================================
    %% RELATIONSHIPS - Chart
    %% ===========================================

    CHART ||--o{ CATEGORY : "has topics"
    CHART ||--o{ DATASETS_TAX : "has dataset"

    %% ===========================================
    %% TERM DATA STORE RELATIONSHIPS
    %% (Post Type <-> Taxonomy Hybrid Pattern)
    %% ===========================================

    STAFF ||--|| BYLINES : "TDS linked"
    COLLECTIONS ||--|| COLLECTION_TAX : "TDS linked"
    DATASET ||--|| DATASETS_TAX : "TDS linked"

    %% ===========================================
    %% STAFF RELATIONSHIPS
    %% ===========================================

    STAFF ||--o{ AREAS_OF_EXPERTISE : "expertise in"
    STAFF ||--o{ STAFF_TYPE : "type of"
    STAFF ||--o{ RESEARCH_TEAMS : "member of"

    %% ===========================================
    %% COLLECTIONS RELATIONSHIPS
    %% ===========================================

    COLLECTIONS ||--o{ POST_VISIBILITY : "visibility"
    COLLECTIONS ||--o{ BYLINES : "curated by"

    %% ===========================================
    %% DATASET RELATIONSHIPS
    %% ===========================================

    DATASET }o--|| POST : "associated with"
    DATASET }o--|| FEATURE : "associated with"
    DATASET }o--|| CHART : "associated with"
    DATASET }o--|| QUIZ : "associated with"

    %% ===========================================
    %% BLOCK MODULE RELATIONSHIPS
    %% ===========================================

    BLOCK_MODULE ||--o{ BLOCK_AREA : "placed in"
    BLOCK_MODULE ||--o{ CATEGORY : "for topic"
    BLOCK_MODULE ||--o{ REGIONS_COUNTRIES : "for region"
    BLOCK_MODULE ||--o{ COLLECTION_TAX : "for collection"

    %% ===========================================
    %% DECODED RELATIONSHIPS
    %% ===========================================

    POST ||--o{ DECODED_CATEGORY : "decoded in"

Post Types Reference

Content Post Types

Post TypePluginDescriptionKey Meta Fields
postCore WPStandard blog posts/articlesbylines, acknowledgements, displayBylines, reportMaterials, multiSectionReport
featureprc-interactive-featuresInteractive data visualizations_feature_rewrites, _feature_dev_notes
quizprc-quiz-builderInteractive quizzes_report
chartprc-chart-builderData visualizations/charts
datasetprc-datasetsDownloadable datasets_download_attachment_id, _total_downloads, is_atp, dataset_schema
collectionsprc-collectionsCurated content collectionskicker_pattern_slug
rls_templateprc-religious-landscape-studyRLS page templates

Staff & Bylines

Post TypePluginDescriptionKey Meta Fields
staffprc-staff-bylinesStaff member profilesjobTitle, jobTitleExtended, bylineLinkEnabled, _maelstrom, socialProfiles

Utility Post Types

Post TypePluginDescriptionKey Meta Fields
homepageprc-homepagesHomepage layouts
block_moduleprc-block-area-modulesReusable block modules_story_item_ids
noteprc-notesInternal editorial notesshared_with_users
documentationprc-wikiPlatform documentation
release-noteprc-wikiRelease notes

Post-Like Types (via prc-post-like-types)

These post types use date-based permalinks like standard posts:

  • short-read
  • fact-sheet
  • decoded
  • press-release
  • stub

Default taxonomies: category, collection, formats, languages, research-teams

Page-Like Types (via prc-page-like-types)

These post types behave like pages with hierarchical URLs.

Default taxonomies: category, collection, formats, languages, research-teams

Taxonomies Reference

Core Classification Taxonomies

TaxonomyPluginDescriptionPost Types
categoryprc-platform-coreTopics (renamed from "Categories")post, feature, quiz, chart, block_module, and post-like types
research-teamsprc-platform-coreResearch teams (primary for permalinks)post, feature, quiz, staff, dataset, fact-sheet, etc.
formatsprc-platform-coreContent formatspost, short-read, fact-sheet, feature, quiz, decoded, dataset, etc.
regions-countriesprc-platform-coreGeographic coveragepost, feature, fact-sheet, short-read, quiz, block_module
languagesprc-platform-coreContent languagepost, fact-sheet, stub, decoded, short-read
mode-of-analysisprc-platform-coreResearch methodologyVarious research post types
fund-poolsprc-platform-coreFunding sourcesVarious post types
decoded-categoryprc-platform-coreDecoded blog categoriesdecoded

Linked Taxonomies (Term Data Store Pattern)

TaxonomyPost TypePluginDescription
bylinesstaffprc-staff-bylinesLinks staff profiles to byline terms
collectioncollectionsprc-collectionsLinks collection posts to collection terms
datasetsdatasetprc-datasetsLinks dataset posts to dataset terms

Staff-Specific Taxonomies

TaxonomyPluginDescription
areas-of-expertiseprc-staff-bylinesStaff expertise areas
staff-typeprc-staff-bylinesStaff classification (staff, executive-team, managing-directors, former)

Utility Taxonomies

TaxonomyPluginDescription
_post_visibilityprc-platform-coreControls post visibility (hidden-on-index, hidden-on-search)
block_areaprc-block-area-modulesBlock module placement areas

Lookbook Taxonomies

TaxonomyPluginDescription
level_of_effortprc-lookbookProject effort classification
primary_audienceprc-lookbookTarget audience
information_typeprc-lookbookContent information type

Key Patterns & Relationships

Term Data Store (TDS) Pattern

The TDS pattern creates a one-to-one relationship between a post type and a taxonomy term, enabling hybrid content where:

  • The post stores rich content (editor blocks, meta fields)
  • The term provides taxonomy relationships to other content
staff (post) <--TDS--> bylines (taxonomy)
collections (post) <--TDS--> collection (taxonomy)
dataset (post) <--TDS--> datasets (taxonomy)

This allows posts to be attached to the taxonomy term automatically, and the term archive acts as the public URL.

Plugin Opt-In System

Plugins opt their post types into features using the WordPress native post_type_supports() pattern via the supports array in register_post_type():

// Register a post type with feature supports
register_post_type( 'my-post-type', array(
    'supports' => array(
        'title',
        'editor',
        'thumbnail',
        // PRC Platform feature supports
        'prc-schema-seo',      // SEO meta fields and schema.org output
        'prc-bylines',         // Staff bylines and acknowledgements
        'prc-art-direction',   // Art direction image slots
        'prc-sitemap',         // Include in XML sitemap
        'prc-related-posts',   // Related posts functionality
        'prc-datasets',        // Datasets taxonomy attachment
        'prc-collections',     // Collections taxonomy attachment
        'prc-publish-workflows', // Watchers + publish-pipeline REST/meta on this CPT
    ),
    // ... other args
));

You can also add support after registration using add_post_type_support():

// Add support after registration
add_action( 'init', function() {
    add_post_type_support( 'my-post-type', 'prc-bylines' );
    add_post_type_support( 'my-post-type', 'prc-art-direction' );
}, 5 );

For publication listing and the main RSS feed, declare post type support (see prc-publication-listing):

add_post_type_support( 'my-post-type', 'prc-publication-listing' );

That opts the type into publication listing queries and into the main site feed. You can still use prc_platform_pub_listing_default_args for other query tweaks if needed.

Available Support Keys:

Support KeyDescriptionProvider Plugin
prc-schema-seoSEO meta fields and schema.org outputprc-schema-seo
prc-socialSocial sharing metadataprc-social
prc-bylinesStaff bylines and acknowledgementsprc-staff-bylines
prc-art-directionArt direction image slotsprc-art-direction
prc-sitemapInclude in XML sitemapprc-schema-sitemap
prc-related-postsRelated posts functionalityprc-related-posts
prc-datasetsDatasets taxonomy attachmentprc-datasets
prc-collectionsCollections taxonomy attachmentprc-collections
prc-publish-workflowsWatchers list, workflow notifications, and related REST fields on supported postsprc-publish-workflows

The built-in post type gets this support from prc-publish-workflows automatically (add_post_type_support( 'post', 'prc-publish-workflows' ) on init). Custom post types must add the key to their supports array (or call add_post_type_support()) so get_post_types_by_support( 'prc-publish-workflows' ) includes them when registering meta and REST fields.

Common Meta Fields Across Post Types

Several meta fields are registered across multiple post types:

Meta KeyDescriptionRegistered By
bylinesArray of byline term referencesprc-staff-bylines
acknowledgementsArray of acknowledgement referencesprc-staff-bylines
displayBylinesBoolean to show/hide bylinesprc-staff-bylines
reportMaterialsReport package materialsprc-report-package
multiSectionReportMulti-section report chaptersprc-report-package
package_parts__enabledEnable TOC partsprc-report-package
package_partsTOC parts dataprc-report-package
_datacite_doiDataCite DOIprc-schema-academic-identity
prc_shortlinkShort link URLprc-platform-core
primary_term_idPrimary category termprc-platform-core

Post Type Registration Diagram

flowchart TB
    subgraph Core["prc-platform-core"]
        direction TB
        Taxonomies["Shared Taxonomies
        - category
        - research-teams
        - formats
        - regions-countries
        - languages
        - fund-pools
        - mode-of-analysis
        - _post_visibility"]
    end

    subgraph PostLike["prc-post-like-types"]
        direction TB
        PLRegistry["Registry System"]
        ShortRead["short-read"]
        FactSheet["fact-sheet"]
        Decoded["decoded"]
        PressRelease["press-release"]
        Stub["stub"]
    end

    subgraph PageLike["prc-page-like-types"]
        direction TB
        PGRegistry["Registry System"]
    end

    subgraph StaffBylines["prc-staff-bylines"]
        direction TB
        Staff["staff (post type)"]
        Bylines["bylines (taxonomy)"]
        Expertise["areas-of-expertise"]
        StaffType["staff-type"]
        Staff <-.TDS.-> Bylines
    end

    subgraph Collections["prc-collections"]
        direction TB
        CollPT["collections (post type)"]
        CollTax["collection (taxonomy)"]
        CollPT <-.TDS.-> CollTax
    end

    subgraph Datasets["prc-datasets"]
        direction TB
        DataPT["dataset (post type)"]
        DataTax["datasets (taxonomy)"]
        DataPT <-.TDS.-> DataTax
    end

    subgraph Interactive["prc-interactive-features"]
        Feature["feature (post type)"]
    end

    subgraph ChartBuilder["prc-chart-builder"]
        Chart["chart (post type)"]
    end

    subgraph QuizBuilder["prc-quiz-builder"]
        Quiz["quiz (post type)"]
    end

    subgraph BlockArea["prc-block-area-modules"]
        BlockModule["block_module (post type)"]
        BlockAreaTax["block_area (taxonomy)"]
    end

    subgraph Homepages["prc-homepages"]
        Homepage["homepage (post type)"]
    end

    subgraph Notes["prc-notes"]
        Note["note (post type)"]
    end

    Core --> PostLike
    Core --> PageLike
    Core --> StaffBylines
    Core --> Collections
    Core --> Datasets
    Core --> Interactive
    Core --> ChartBuilder
    Core --> QuizBuilder
    Core --> BlockArea
    Core --> Homepages
    Core --> Notes

    StaffBylines --> PostLike
    Collections --> PostLike
    Datasets --> Interactive
    Datasets --> ChartBuilder
    Datasets --> QuizBuilder

Publication Listing Integration

The Publication Listing system (prc-platform-core) manages which post types appear in archive and search results:

flowchart LR
    subgraph Query["Publication Listing Query"]
        WPQuery["WP_Query"]
        CoreQuery["core/query block"]
        RestQuery["REST API"]
    end

    subgraph Filter["prc_platform_pub_listing_default_args"]
        PostTypes["Included Post Types"]
        TaxQuery["Tax Query (visibility)"]
        PostParent["post_parent = 0"]
    end

    subgraph PostTypes["Default Post Types"]
        Post["post"]
        Feature["feature"]
        Quiz["quiz"]
        Collections["collections"]
        Dataset["dataset (search only)"]
        Staff["staff (search only)"]
    end

    Query --> Filter
    Filter --> PostTypes

Notes

  • All custom post types support custom-fields for block editor meta
  • Most content post types support revisions for version history
  • The notes editor support allows internal notes on posts
  • Research Teams taxonomy drives permalink structure for most content
  • The TDS pattern enables rich taxonomy pages with full editor content

Was this helpful?