# ARCHITECTURE.md - CCAT Data Structure Reference ## Table of Contents - [Custom Post Types Overview](#custom-post-types-overview) - [Taxonomies Overview](#taxonomies-overview) - [Custom Post Type Fields](#custom-post-type-fields) - [Abstract Field Groups](#abstract-field-groups) - [Field Relationships](#field-relationships) - [Technical Implementation](#technical-implementation) --- ## Custom Post Types Overview | CPT Name | Label | GraphQL Single | Rewrite Slug | Hierarchical | Description | |----------|--------|----------------|--------------|--------------|-------------| | `contributor` | Contributor | `Contributor` | -- | No | Artist/organization profiles | | `event` | Event | `Event` | `evenement` | Yes | Base event descriptions without specific dates | | `listing` | Listing | `Listing` | `offre` | No | Job offers and opportunities | | `location` | Location | `Location` | `lieu` | Yes | Venue information with hierarchical structure | | `page` | Page | `Page` | `page` | Yes | WordPress default pages with flexible content | | `profile` | Profile | `Profile` | `profil` | No | User cultural profiles for members | | `project` | Project | `Project` | `projet` | No | CCAT projects and initiatives | | `representation` | Representation | `Representation` | -- | No | Specific event instances with dates/times/locations | | `resource` | Resource | `Resource` | `ressource` | No | Document/link repository | | `template` | Template | `Template` | -- | No | Reusable content blocks for flexible layouts | --- ## Taxonomies Overview | Taxonomy Name | Label | Associated CPTs | Hierarchical | GraphQL Single | Description | |---------------|--------|----------------|--------------|----------------|-------------| | `discipline` | Discipline | `contributor`, `event` | Yes | `Discipline` | Artistic/cultural categories | | `listing-category` | Listing Category | `listing` | Yes | `ListingCategory` | Job/proposal types | | `project-category` | Project Category | `project` | Yes | `ProjectCategory` | CCAT project types | | `resource-category` | Resource Category | `resource` | Yes | `ResourceCategory` | Resource organization categories | --- ## Custom Post Type Fields ### Contributor (`group_post_contributor`) **Purpose:** Artist/organization profiles that can be linked to events | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `contributor_type` | Contributor type | select | Yes | Type of contributor (individual, organisation) | | `alternative_titles` | Alternative titles | repeater | No | Alternative names for the contributor | | `alternative_titles.name` | Name | text | Yes | Alternative name entry | | `description` | Description | wysiwyg | No | Rich text description of contributor | | `localities` | Localities | repeater | No | Physical locations associated with contributor | | `localities.address` | Address | clone | Yes | Clones city address field for location | | `disciplines` | Discipline(s) | taxonomy | No | Links to discipline taxonomy terms | | `entity` | Entity | clone | No | External identifiers | | `gallery` | Gallery | clone | No | Media gallery | | `social` | Social | clone | No | Social media profiles | ### Event (`group_post_event`) **Purpose:** Base event information without specific dates/times | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `event_type` | Event type | select | Yes | Type of event (Exposition, Festival, Spectacle) | | `target_audience` | Target audience | select | Yes | Age group (Tout public, Enfants, Familial, Adultes 18+) | | `description` | Description | wysiwyg | No | Rich text event description | | `disciplines` | Discipline(s) | taxonomy | No | Links to discipline taxonomy terms | | `is_wordless` | Wordless | true_false | No | Indicates if event is wordless | | `languages` | Language(s) | acfe_languages | No | Event languages (conditional: shown if not wordless) | | `entity` | Entity | clone | No | Clones abstract entity group (external identifiers) | | `social` | Social | clone | No | Clones abstract social group (social media profiles) | | `gallery` | Gallery | clone | No | Clones abstract gallery group (images/videos) | | `credits` | Credits | clone | No | Clones abstract credits group (contributors and roles) | ### Listing (`group_post_listing`) **Purpose:** Job offers and opportunities | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `listing_category` | Listing category | taxonomy | Yes | Links to listing_category taxonomy | | `deadline` | Application deadline | date_picker | No | Application deadline date | | `external_link` | External link | url | No | Link to external application | ### Location (`group_post_location`) **Purpose:** Venue information for events | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `location_type` | Location type | select | Yes | Type of location (virtual, Bar, Salle de spectacle) | | `description` | Description | wysiwyg | No | Rich text description of location | | `address` | Address | clone | No | Clones geo address field (conditional: not shown for virtual) | | `configurations` | Possible configurations | repeater | No | Different setup configurations for venue | | `configurations.name` | Configuration name | text | Yes | Name of the configuration | | `universal_access` | Universal access | checkbox | No | Accessibility features available | | `entity` | Entity | clone | No | External identifiers | | `social` | Social | clone | No | Social media profiles | | `gallery` | Gallery | clone | No | Media gallery | ### Page (`group_post_page`) **Purpose:** WordPress default pages with flexible content capabilities | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `builder` | Builder | clone | No | Clones abstract builder group (flexible content sections) | **Note:** This field group extends WordPress's default `page` post type with flexible content capabilities. The default content editor is hidden (`hide_on_screen: the_content`) in favor of the flexible builder system. ### Profile (`group_post_profile`) **Purpose:** User profile information for members | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `contact` | Contact | clone | Yes | Clones abstract contact group (personal info & address) | | `billing_same` | Same as contact | true_false | No | Whether billing matches contact info | | `billing` | Billing | clone | No | Separate billing contact info (conditional: shown if billing_same is false) | | `profile_type` | Profile type | select | Yes | Type of profile (individual, collective, organization, institution) | | `email_preferences` | Email preferences | group | No | Group containing email subscription preferences | | `email_preferences.categories` | Categories | checkbox | No | Email categories to subscribe to | | `email_preferences.disciplines` | Disciplines | checkbox | No | Discipline-based email preferences | | `email_preferences.event_types` | Event types | checkbox | No | Event type email preferences | | `email_preferences.mrc` | MRC | checkbox | No | Regional email preferences | ### Project (`group_post_project`) **Purpose:** CCAT projects and initiatives | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `project_categories` | Project categories | taxonomy | Yes | Links to project_category taxonomy | | `period` | Period | group | No | Project timeline | | `period.start_month` | Start month | date_picker | Yes | Project start (month/year format) | | `period.end_month` | End month | date_picker | No | Project end (month/year format) | | `builder` | Builder | clone | No | Clones abstract builder group (flexible content sections) | ### Representation (`group_post_representation`) **Purpose:** Specific event instances with dates/times | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `event` | Event | post_object | Yes | Links to base Event post | | `description` | Description | wysiwyg | No | Specific description for this representation | | `schedule_type` | Schedule type | select | Yes | Type of scheduling (range, days, multiple) | | `range` | Range | group | No | Date range fields (conditional: when schedule_type = range) | | `range.start_date` | Start date | date_picker | Yes | Range start date | | `range.end_date` | End date | date_picker | Yes | Range end date | | `days` | Days | repeater | No | Individual days (conditional: when schedule_type = days/multiple) | | `days.start_date_time` | Start date/time | date_time_picker | Yes | Event start with time | | `days.end_time` | End time | time_picker | No | Event end time | | `offer` | Offer | clone | No | Clones abstract offer group (pricing, location, registration) | ### Resource (`group_post_resource`) **Purpose:** Document repository | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `resource_category` | Resource category | taxonomy | Yes | Links to resource_category taxonomy | | `documents` | Documents | repeater | No | List of documents | | `documents.title` | Title | text | Yes | Document title | | `documents.document_type` | Document type | select | Yes | Type of document (file, url) | | `documents.file` | File | file | Yes | File upload (conditional: when document_type = file) | | `documents.url` | URL | url | Yes | External URL (conditional: when document_type = url) | ### Template (`group_post_template`) **Purpose:** Reusable content templates | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `builder` | Builder | clone | No | Clones abstract builder group (flexible content sections) | --- ## Abstract Field Groups ### Address City (`group_abstract_address_city`) **Purpose:** City-level address information | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `address` | Address | acfe_address | Yes | Address with city-level search, Canada only | ### Address Contact (`group_abstract_address_contact`) **Purpose:** Full contact address information | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `address` | Address | acfe_address | Yes | Complete address with street details, Canada only | ### Address Geo (`group_abstract_address_geo`) **Purpose:** Geographic address with coordinates | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `address` | Address | acfe_address | Yes | Address with establishment search and lat/lng coordinates | ### Builder (`group_abstract_builder`) **Purpose:** Flexible content builder with layout sections | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `sections` | Sections | flexible_content | No | Flexible content with layouts: | | `sections.text_block` | Text block | layout | - | WYSIWYG content block | | `sections.text_block.content` | Content | wysiwyg | Yes | Rich text content | | `sections.template` | Template | layout | - | Reference to template post | | `sections.template.template` | Template | post_object | Yes | Links to Template post type | ### Contact (`group_abstract_contact`) **Purpose:** Personal contact information | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `first_name` | First name | text | Yes | Contact's first name | | `last_name` | Last name | text | Yes | Contact's last name | | `email` | Email | email | Yes | Contact email address | | `phone` | Phone | acfe_phone_number | Yes | Phone number (Canada format) | | `address` | Address | clone | Yes | Clones contact address field | ### Credits (`group_abstract_credits`) **Purpose:** Attribution and contributor roles | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `contributions` | Contributions | repeater | No | List of contributor roles | | `contributions.contributionTypes` | Contribution types | checkbox | Yes | Types of contribution (Auteur, Compositeur, Interprète) | | `contributions.contributor` | Contributor | post_object | Yes | Links to Contributor post | ### Entity (`group_abstract_entity`) **Purpose:** External entity identifiers | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `identifiers` | Identifiers | repeater | No | External identifier URLs | | `identifiers.uri` | URI | url | Yes | External identifier URL | ### Gallery (`group_abstract_gallery`) **Purpose:** Media gallery with images and videos | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `medias` | Medias | repeater | No | List of media items | | `medias.mediaType` | Media type | select | Yes | Type of media (image, youtube) | | `medias.image` | Image | image | Yes | Image upload (conditional: when mediaType = image) | | `medias.youtube_url` | YouTube URL | url | Yes | YouTube video URL (conditional: when mediaType = youtube) | ### Offer (`group_abstract_offer`) **Purpose:** Event offering details (pricing, registration, location) | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `attendance_mode` | Attendance mode | select | Yes | How event is attended (offline, online, mixed) | | `is_async` | Is asynchronous | true_false | No | Whether online event is asynchronous | | `offer_status` | Offer status | select | Yes | Event status (upcoming, confirmed, complete, cancelled, postponed) | | `where` | Where | group | No | Location details (conditional: for offline/mixed events) | | `where.location` | Location | post_object | Yes | Links to Location post | | `where.configuration` | Configuration | select | No | Venue configuration | | `pricing` | Pricing | group | No | Price information | | `pricing.is_free` | Free | true_false | No | Whether event is free | | `pricing.min_price` | Minimum price | number | Yes | Minimum price (conditional: if not free) | | `registration` | Registration | group | No | Registration details | | `registration.form` | Form | select | No | Registration form | | `registration.url` | URL | url | No | Registration URL | | `registration.email` | Email | email | No | Registration email | | `registration.phone` | Phone | acfe_phone_number | No | Registration phone | | `notifications` | Notifications | repeater | No | Scheduled notifications | | `notifications.date_time` | Date/time | date_time_picker | Yes | When to send notification | | `notifications.subject` | Subject | text | Yes | Email subject | | `notifications.message` | Message | wysiwyg | Yes | Email message content | | `notifications.sent_status` | Sent status | select | Yes | Notification status (planned, sent, failed) | ### Social (`group_abstract_social`) **Purpose:** Social media profiles | Field Name | Label | Type | Required | Description | |------------|-------|------|----------|-------------| | `profiles` | Profiles | repeater | No | List of social media profiles | | `profiles.url` | URL | url | Yes | Social media profile URL | --- ## Field Relationships ### Post Object Relationships - **Event → Representation**: Base events are instantiated through representations - **Representation → Event**: Each representation references one base event - **Representation → Location**: Event instances specify venue through offer.where.location - **Contributor → Credits**: Contributors are linked to events through credits system - **Template → Builder**: Templates contain flexible content sections that can be referenced ### Taxonomy Relationships - **Discipline**: Applied to both `event` and `contributor` CPTs - **Resource Category**: Applied to `resource` CPTs only - **Project Category**: Applied to `project` CPTs only - **Listing Category**: Applied to `listing` CPTs only ### Clone Field Usage | Abstract Group | Used By CPTs | |----------------|--------------| | Address City | Contributor (locality) | | Address Contact | Profile (contact, billing) | | Address Geo | Location (address) | | Builder | Project, Template, Page | | Contact | Profile (contact, billing) | | Credits | Event | | Entity | Event, Contributor, Location | | Gallery | Event, Contributor, Location | | Offer | Representation | | Social | Event, Contributor, Location, Options Page | --- ## Technical Implementation ### GraphQL Integration - All CPTs enabled for GraphQL with custom single/plural names - All fields set `show_in_graphql: 1` for API exposure - Required fields use `graphql_non_null: 1` for schema validation - Custom GraphQL field names follow camelCase convention ### ACF Extended Pro Features - **Advanced Address Fields**: Google Places integration, Canada-specific - **Phone Number Fields**: Country-specific formatting (Canada) - **Language Selection**: Multi-language support with conditional logic - **Flexible Content**: Modal editing, preview capabilities - **Template System**: Reusable content blocks with clone functionality ### Conditional Logic Patterns - Address fields hidden for virtual locations (`location_type != 'virtual'`) - Language fields hidden for wordless events (`is_wordless != 1`) - Billing fields conditional on "same as contact" toggle - Pricing fields conditional on free/paid status - Schedule layouts vary based on schedule type selection ### WordPress Integration - Custom rewrite slugs in French for public-facing URLs - Hierarchical structure for events and locations - Thumbnail and excerpt support for content display - Page attributes for ordering and parent-child relationships - Translation-ready with `__()` functions and 'ccat' text domain ### Performance Considerations - Clone fields reduce field duplication and maintain consistency - Taxonomy relationships indexed for efficient querying - GraphQL schema optimized with proper field exposure - Conditional field loading reduces unnecessary data transfer