From 962752035c500e1b373821a0e15ca9ce22f62e09 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <1+jmiller@noreply.git.mokoconsulting.tech> Date: Mon, 29 Jun 2026 16:35:19 +0000 Subject: [PATCH] Add "Database Schema" --- Database-Schema.-.md | 60 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 Database-Schema.-.md diff --git a/Database-Schema.-.md b/Database-Schema.-.md new file mode 100644 index 0000000..bb1ccc1 --- /dev/null +++ b/Database-Schema.-.md @@ -0,0 +1,60 @@ +# Database Schema + +## Table: `#__mokoog_tags` + +Single table storing all OG tag data for articles, menu items, categories, and shop products. Supports multilingual content with per-language records. + +### Columns + +| Column | Type | Default | Description | +|---|---|---|---| +| `id` | INT(11) UNSIGNED | AUTO_INCREMENT | Primary key | +| `content_type` | VARCHAR(100) | `''` | Content context (e.g. `com_content`, `com_content.category`, `menu`, `com_mokoshop`) | +| `content_id` | INT(11) UNSIGNED | `0` | ID of the associated content item | +| `og_title` | VARCHAR(255) | `''` | Custom Open Graph title | +| `og_description` | TEXT | — | Custom Open Graph description | +| `og_image` | VARCHAR(512) | `''` | Path or URL to the OG image | +| `og_type` | VARCHAR(50) | `'article'` | OG type (`article`, `website`, `product`, `profile`, `book`, `music`, `video`) | +| `og_video` | VARCHAR(512) | `''` | Video URL (YouTube, Vimeo, or direct file) | +| `event_data` | TEXT | NULL | JSON — Event schema fields (dates, venue, tickets) | +| `recipe_data` | TEXT | NULL | JSON — Recipe schema fields (times, ingredients, nutrition) | +| `custom_schema` | TEXT | NULL | JSON — Custom JSON-LD schema (any schema.org type) | +| `seo_title` | VARCHAR(70) | `''` | Custom HTML `` override | +| `meta_description` | VARCHAR(200) | `''` | Custom meta description | +| `robots` | VARCHAR(100) | `''` | Robots directives (noindex, nofollow, noarchive, etc.) | +| `canonical_url` | VARCHAR(512) | `''` | Custom canonical URL (http/https only) | +| `language` | CHAR(7) | `'*'` | Language code (`en-GB`, `*` for all) | +| `published` | TINYINT(1) | `1` | Publish state | +| `created` | DATETIME | `'0000-00-00 00:00:00'` | Record creation timestamp | +| `modified` | DATETIME | `'0000-00-00 00:00:00'` | Last modification timestamp | + +### Indexes + +| Index | Type | Columns | Purpose | +|---|---|---|---| +| `PRIMARY` | Primary Key | `id` | Row identifier | +| `idx_content_lang` | UNIQUE | `content_type`, `content_id`, `language` | One OG record per content item per language | +| `idx_published` | INDEX | `published` | Filter by publish state | + +### Relationships + +- **`content_type` + `content_id`** — polymorphic reference to any Joomla content item: + - `com_content` → `#__content.id` (articles) + - `com_content.category` → `#__categories.id` (categories) + - `menu` → `#__menu.id` (menu items) + - `com_mokoshop` → MokoSuiteShop product ID +- **`language`** — references Joomla's `#__languages.lang_code`; `*` matches all languages + +### Language Fallback + +Queries prefer a specific language match over the `*` wildcard. When loading OG data, the system plugin first looks for a record matching the current language, then falls back to `language = '*'`. + +### JSON Columns + +The `event_data`, `recipe_data`, and `custom_schema` columns store JSON objects. Values are validated as objects or arrays on save. Malformed data is guarded on render to prevent frontend errors. + +### Engine + +- **Engine:** InnoDB +- **Charset:** utf8mb4 +- **Collation:** utf8mb4_unicode_ci