From 4ac9ceb50e631054884b802d34a114b64dc0e9e5 Mon Sep 17 00:00:00 2001 From: Pascal Martineau Date: Thu, 25 Sep 2025 13:55:12 -0400 Subject: [PATCH] chore: ARCHITECTURE.md --- .claude/ARCHITECTURE.md | 343 ++++++++++++++++++ .../themes/ccat/acf-json/acf-translations.php | 2 +- .../ccat/acf-json/group_post_contributor.json | 8 +- 3 files changed, 348 insertions(+), 5 deletions(-) create mode 100644 .claude/ARCHITECTURE.md diff --git a/.claude/ARCHITECTURE.md b/.claude/ARCHITECTURE.md new file mode 100644 index 0000000..716158b --- /dev/null +++ b/.claude/ARCHITECTURE.md @@ -0,0 +1,343 @@ +# 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 \ No newline at end of file diff --git a/wp-content/themes/ccat/acf-json/acf-translations.php b/wp-content/themes/ccat/acf-json/acf-translations.php index 41f8c99..1615b96 100644 --- a/wp-content/themes/ccat/acf-json/acf-translations.php +++ b/wp-content/themes/ccat/acf-json/acf-translations.php @@ -85,7 +85,7 @@ __( "Interprète", 'ccat' ); __( "Is asynchronous", 'ccat' ); __( "Language(s)", 'ccat' ); __( "Last name", 'ccat' ); -__( "Locality", 'ccat' ); +__( "Localities", 'ccat' ); __( "Location", 'ccat' ); __( "Location type", 'ccat' ); __( "MRC", 'ccat' ); diff --git a/wp-content/themes/ccat/acf-json/group_post_contributor.json b/wp-content/themes/ccat/acf-json/group_post_contributor.json index 3246e7e..c23b39c 100644 --- a/wp-content/themes/ccat/acf-json/group_post_contributor.json +++ b/wp-content/themes/ccat/acf-json/group_post_contributor.json @@ -139,8 +139,8 @@ }, { "key": "field_685aa158687d2", - "label": "Locality", - "name": "locality", + "label": "Localities", + "name": "localities", "aria-label": "", "type": "repeater", "instructions": "", @@ -160,7 +160,7 @@ "button_label": "Ajouter un élément", "show_in_graphql": 1, "graphql_description": "", - "graphql_field_name": "locality", + "graphql_field_name": "localities", "graphql_non_null": 0, "rows_per_page": 20, "sub_fields": [ @@ -343,5 +343,5 @@ "graphql_types": "", "acfe_meta": "", "acfe_note": "", - "modified": 1758811648 + "modified": 1758822397 }