# Database Schema **Updated:** 2026-05-05 | **Total tables:** ~32 | **Engine:** MySQL InnoDB | **Prefix:** `pp_` Schema inferred from Medoo ORM queries in PHP source files. No migration files found — schema managed manually. --- ## Content — Articles **`pp_articles`** — Main article/content records | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `hash` | VARCHAR | Unique identifier for external reference | | `status` | TINYINT | Published/draft/archived | | `date_add` | DATETIME | Creation timestamp | | `views` | INT | View counter | | `password` | VARCHAR | Optional password protection | | `pixieset` | VARCHAR | Pixieset gallery identifier | **`pp_articles_langs`** — Language-specific article content | Column | Type | Notes | |--------|------|-------| | `article_id` | INT | FK → `pp_articles.id` | | `lang_id` | INT | FK → `pp_langs.id` | | `title` | VARCHAR | Article title | | `content` | LONGTEXT | Rich text content | | `seo_link` | VARCHAR | URL slug | | `noindex` | TINYINT | SEO noindex flag | **`pp_articles_images`** — Article gallery images | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `article_id` | INT | FK → `pp_articles.id` | | `src` | VARCHAR | Image filename/path | | `o` | INT | Sort order | | `favorite` | TINYINT | Flagged as favorite | | `to_delete` | TINYINT | Soft-delete flag | **`pp_articles_files`** — Downloadable file attachments | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `article_id` | INT | FK → `pp_articles.id` | | `src` | VARCHAR | File path | | `name` | VARCHAR | Display name | | `to_delete` | TINYINT | Soft-delete flag | **`pp_articles_pages`** — Article-to-Page assignments | Column | Type | Notes | |--------|------|-------| | `article_id` | INT | FK → `pp_articles.id` | | `page_id` | INT | FK → `pp_pages.id` | | `o` | INT | Sort order on page | | `status` | TINYINT | Visibility on this page | **`pp_articles_tags`** — Many-to-many: Articles ↔ Tags | Column | Type | Notes | |--------|------|-------| | `article_id` | INT | FK → `pp_articles.id` | | `tag_id` | INT | FK → `pp_tags.id` | **`pp_articles_additional_params`** — Custom field definitions per article | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `article_id` | INT | FK → `pp_articles.id` | | `name` | VARCHAR | Field name | | `language` | VARCHAR | Language code | | `status` | TINYINT | Active/inactive | **`pp_articles_additional_values`** — Custom field values | Column | Type | Notes | |--------|------|-------| | `param_id` | INT | FK → `pp_articles_additional_params.id` | | `article_id` | INT | FK → `pp_articles.id` | | `value` | TEXT | Field value | | `language_id` | INT | FK → `pp_langs.id` | --- ## Content — Pages & Layouts **`pp_pages`** — Website page hierarchy | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `menu_id` | INT | FK → `pp_menus.id` | | `parent_id` | INT | Self-referencing for nested pages | | `page_type` | VARCHAR | Type identifier | | `sort_type` | VARCHAR | Article sort order | | `status` | TINYINT | Published/hidden | | `start` | TINYINT | Homepage flag | | `o` | INT | Sort order in navigation | | `cache` | TINYINT | Page-level cache toggle | **`pp_pages_langs`** — Page language translations | Column | Type | Notes | |--------|------|-------| | `page_id` | INT | FK → `pp_pages.id` | | `lang_id` | INT | FK → `pp_langs.id` | | `title` | VARCHAR | Page title | | `seo_link` | VARCHAR | URL slug | **`pp_layouts`** — Template layout containers | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `layout_id` | INT | Parent layout reference | | `name` | VARCHAR | Layout name | | `html` | LONGTEXT | Desktop HTML with `[PLACEHOLDER:id]` tags | | `m_html` | LONGTEXT | Mobile HTML | | `css` | TEXT | Inline CSS | | `m_css` | TEXT | Mobile inline CSS | | `js` | TEXT | Inline JS | | `m_js` | TEXT | Mobile inline JS | | `status` | TINYINT | Active/inactive | **`pp_layouts_pages`** — Layout-to-page assignments | Column | Type | Notes | |--------|------|-------| | `layout_id` | INT | FK → `pp_layouts.id` | | `page_id` | INT | FK → `pp_pages.id` | --- ## Content — Static Containers & Banners **`pp_scontainers`** — Reusable static content blocks | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `status` | TINYINT | Active/inactive | **`pp_scontainers_langs`** — Static container translations | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `scontainer_id` | INT | FK → `pp_scontainers.id` | | `lang_id` | INT | FK → `pp_langs.id` | | `html` | LONGTEXT | Content HTML | **`pp_banners`** — Promotional banners | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `name` | VARCHAR | Banner name | | `status` | TINYINT | Active/inactive | **`pp_banners_langs`** — Banner language versions | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `id_banner` | INT | FK → `pp_banners.id` | | `id_lang` | INT | FK → `pp_langs.id` | | `title` | VARCHAR | Banner title | | `content` | TEXT | Banner content/HTML | --- ## Navigation & Taxonomy **`pp_menus`** — Navigation menu definitions | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `name` | VARCHAR | Menu name | **`pp_tags`** — Article tags/categories | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `name` | VARCHAR | Tag name | **`pp_authors`** — Article author profiles | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | **`pp_authors_langs`** — Author translations | Column | Type | Notes | |--------|------|-------| | `author_id` | INT | FK → `pp_authors.id` | | `lang_id` | INT | FK → `pp_langs.id` | --- ## Users & Access Control **`pp_users`** — Admin panel users | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `login` | VARCHAR | Username | | `password` | VARCHAR | MD5 hash (security concern — see concerns.md) | | `status` | TINYINT | Active/inactive | | `active_to` | DATE | Account expiry date | | `admin` | TINYINT | Super-admin flag | | `error_logged_count` | INT | Failed login counter | **`pp_users_privileges`** — User permission assignments | Column | Type | Notes | |--------|------|-------| | `id_user` | INT | FK → `pp_users.id` | | `name` | VARCHAR | Privilege name (string key) | --- ## Multi-language **`pp_langs`** — Available language configurations | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `start` | TINYINT | Default language flag | | `domain` | VARCHAR | Domain for this language | | `main_domain` | VARCHAR | Primary domain | | `o` | INT | Sort order | | `status` | TINYINT | Active/inactive | **`pp_langs_translations`** — UI string translations | Column | Type | Notes | |--------|------|-------| | Dynamic columns per language ID | VARCHAR | Translation strings | --- ## Newsletter **`pp_newsletter`** — Email subscribers | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `email` | VARCHAR | Subscriber email | | `status` | TINYINT | Active/unsubscribed | **`pp_newsletter_send`** — Sent campaign log | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `email_template_id` | INT | FK → `pp_newsletter_templates.id` | **`pp_newsletter_templates`** — Email campaign templates | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | | `name` | VARCHAR | Template name | | `subject` | VARCHAR | Email subject | | `html` | LONGTEXT | Email HTML body | --- ## Contacts & Locations **`pp_contacts_maps`** — Location/contact point entries | Column | Type | Notes | |--------|------|-------| | `id` | INT | PK, AUTO_INCREMENT | **`pp_contacts_maps_products`** — Product associations for locations | Column | Type | Notes | |--------|------|-------| | `map_id` | INT | FK → `pp_contacts_maps.id` | | `product_id` | INT | Product reference | **`pp_contacts_maps_provinces`** — Province associations for locations | Column | Type | Notes | |--------|------|-------| | `map_id` | INT | FK → `pp_contacts_maps.id` | | `province_id` | INT | Province reference | **`pp_contact_emails`** — Contact form submissions | Column | Type | Notes | |--------|------|-------| | `email` | VARCHAR | Sender email | | `phone` | VARCHAR | Sender phone | | `title` | VARCHAR | Subject | | `mail` | TEXT | Message body | | `add_date` | DATETIME | Submission timestamp | --- ## SEO & Settings **`pp_seo_additional`** — Per-article SEO metadata | Column | Type | Notes | |--------|------|-------| | `article_id` | INT | FK → `pp_articles.id` | | `lang_id` | INT | FK → `pp_langs.id` | **`pp_settings`** — Global CMS configuration (key-value store) | Column | Type | Notes | |--------|------|-------| | `param` | VARCHAR | Setting key (e.g., `google_map_key`, `email_host`) | | `value` | TEXT | Setting value | --- ## Schema Characteristics | Property | Value | |----------|-------| | Engine | MySQL InnoDB | | Table prefix | `pp_` | | Soft deletes | `to_delete` column on `pp_articles_images`, `pp_articles_files` | | Multi-language | All content tables have `_langs` counterpart | | Migrations | None — schema managed manually | | Timestamps | `date_add` on articles; not standardized across all tables | ## Key Relationships - **1:N** — `pp_articles` → `pp_articles_images`, `pp_articles_files`, `pp_articles_langs` - **N:N** — `pp_articles` ↔ `pp_tags` (via `pp_articles_tags`) - **N:N** — `pp_articles` ↔ `pp_pages` (via `pp_articles_pages`) - **Hierarchical** — `pp_pages.parent_id` self-reference for nested page tree - **Language join** — all content tables join `pp_langs` on `lang_id` for translation