docs(wiki): full rebuild — fix slugs/nav, refresh all pages for v01.05.x, add Admin Guide / JSON-LD Schemas / Troubleshooting / sidebar
+67
@@ -0,0 +1,67 @@
|
||||
# Admin Guide
|
||||
|
||||
Open **Components → MokoSuiteOpenGraph** in the Joomla administrator.
|
||||
|
||||
## Dashboard (default view)
|
||||
|
||||
The dashboard is the landing screen. It shows:
|
||||
|
||||
- **Coverage donut** — percentage of published articles that have an OG tag (green ≥ 80%, amber ≥ 50%, red below)
|
||||
- **Field coverage gaps** — how many tags are missing a custom title, description, or image
|
||||
- **Coverage by content type** — a per-`content_type` breakdown (com_content, menu, category, com_mokoshop)
|
||||
- **Articles missing OG tags** — the most recent published articles with no tag, each linking to the article editor, plus a **Batch Generate** shortcut
|
||||
|
||||
Switch between the dashboard and the tag list using the component submenu (**Dashboard** / **Tags**).
|
||||
|
||||
## Tag Manager (Tags)
|
||||
|
||||
Lists every OG tag record. From here you can:
|
||||
|
||||
- **Search and filter** by OG title and content type
|
||||
- **Open the editor** by clicking a tag's title
|
||||
- **New** — create a tag manually (you choose the content type, content ID, and language)
|
||||
- **Edit** — select a row and edit it
|
||||
- **Publish / Unpublish / Delete** — standard toolbar actions
|
||||
- **SEO health badges** — flags for missing description, overly long title, or noindex
|
||||
- **Debug links** — quick links to the Facebook Debugger, LinkedIn Inspector, and Google Rich Results test
|
||||
|
||||
### Editing a tag
|
||||
|
||||
The edit screen has two tabs:
|
||||
|
||||
- **Details** — content type, content ID, language, OG title/description/image/type, og:video, published state
|
||||
- **SEO Meta Tags** — SEO title, meta description, robots, canonical URL
|
||||
|
||||
`maxlength` hints match the database limits (SEO title 70, meta description 200). Required fields are validated on save.
|
||||
|
||||
## Batch Generation
|
||||
|
||||
Click **Batch Generate** (toolbar or dashboard). The component:
|
||||
|
||||
1. Counts published articles that have no OG tag
|
||||
2. Processes them in chunks, generating OG title/description/image from the article content
|
||||
3. Shows a live progress bar
|
||||
|
||||
Requires the `mokoog.batch` permission (or core `create`).
|
||||
|
||||
## CSV Import / Export
|
||||
|
||||
- **Export CSV** — downloads all OG tags (including `og_video`, `event_data`, `recipe_data`, `custom_schema`)
|
||||
- **Import CSV** — click **Import**, choose a `.csv` file, and upload. New columns are appended, so older exports still import. JSON columns are validated (objects/arrays only) and `og_video` is restricted to http/https.
|
||||
|
||||
The CSV header row defines the columns; `content_type`, `content_id`, and `language` form the unique key used to update-or-insert each row.
|
||||
|
||||
Requires the `mokoog.import` permission (or core `create` + `edit`).
|
||||
|
||||
## Permissions
|
||||
|
||||
Open **Options → Permissions** to grant per-group access to the custom actions:
|
||||
|
||||
- `mokoog.batch` — batch generation
|
||||
- `mokoog.import` — CSV import/export
|
||||
|
||||
These complement the standard core actions (`core.create`, `core.edit`, `core.delete`, `core.manage`).
|
||||
|
||||
## Plugin Settings
|
||||
|
||||
Site-wide behaviour (defaults, JSON-LD, sitemap, AI, LocalBusiness) is configured in the **System - MokoSuiteOpenGraph** plugin — see [Configuration](Configuration).
|
||||
+40
-29
@@ -4,48 +4,57 @@
|
||||
|
||||
```
|
||||
pkg_mokoog
|
||||
com_mokoog -- Admin component (dashboard, CRUD, batch, CSV)
|
||||
plg_system_mokoog -- System plugin (frontend meta tag injection)
|
||||
plg_content_mokoog -- Content plugin (editor form fields, live preview)
|
||||
plg_webservices_mokoog -- WebServices plugin (REST API routes)
|
||||
com_mokoog -- Admin component (dashboard, tag CRUD, batch, CSV, ACL)
|
||||
plg_system_mokoog -- System plugin (frontend meta tag injection, sitemap, AI)
|
||||
plg_content_mokoog -- Content plugin (editor form fields, live preview)
|
||||
plg_webservices_mokoog -- WebServices plugin (REST API routes)
|
||||
```
|
||||
|
||||
Targets **Joomla 6+** and **PHP 8.2+**. All extensions use the modern namespaced DI architecture: `services/provider.php` providers, `SubscriberInterface` event subscribers, and namespaced MVC. No deprecated `Factory::getDbo/getUser/getSession/getLanguage`, `Joomla\CMS\Filesystem`, or `jexit()` calls remain (forward-compatible with Joomla 7).
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Frontend (onBeforeCompileHead)
|
||||
1. System plugin detects current page (`option`, `view`, `id`)
|
||||
### Frontend (`onBeforeCompileHead`)
|
||||
1. System plugin detects the current page (`option`, `view`, `id`)
|
||||
2. Loads custom OG data from `#__mokoog_tags` (language-aware)
|
||||
3. Falls back to category/menu OG data if available
|
||||
4. Auto-generates missing fields from article/product content
|
||||
5. Resolves image URL, auto-resizes if enabled
|
||||
6. Emits OG, Twitter, LinkedIn, Discord, Telegram meta tags
|
||||
7. Builds JSON-LD schema (Article, Product, or WebPage)
|
||||
5. Resolves the image URL, auto-resizes if enabled
|
||||
6. Emits OG, Twitter, LinkedIn, Discord, Telegram, Fediverse, Pinterest meta tags
|
||||
7. Builds JSON-LD schema(s) (Article/Product/WebPage + FAQ/HowTo/Event/Recipe/LocalBusiness/Video/custom)
|
||||
8. Fires `onMokoOGAfterRender` for third-party extensions
|
||||
|
||||
### Admin (content plugin)
|
||||
1. Content plugin adds OG fields tab to article/menu/category editor forms
|
||||
2. On save, stores custom OG data to `#__mokoog_tags` with language
|
||||
3. Live preview updates Facebook/Twitter card preview in real-time
|
||||
### Editor (content plugin)
|
||||
1. Content plugin adds the OG fields tab to article/menu/category editor forms
|
||||
2. On save, stores custom OG data to `#__mokoog_tags` keyed by language; JSON fields are validated as objects/arrays
|
||||
3. Live preview updates the Facebook/Twitter/LinkedIn/Discord/Mastodon/Slack cards in real time
|
||||
|
||||
### Admin component
|
||||
1. **Dashboard** (default view) — `DashboardModel` computes coverage stats; `View/Dashboard` renders a donut + breakdown + missing-articles list
|
||||
2. **Tags** — list view with publish/unpublish/delete (`TagsController`) and a single-record create/edit screen (`TagController` → `View/Tag` → `tmpl/tag/edit.php`)
|
||||
3. **Batch / Import-Export** — `BatchController`, `ImportExportController` (CSRF + ACL gated)
|
||||
|
||||
### API
|
||||
1. WebServices plugin registers routes on `onBeforeApiRoute`
|
||||
2. JSON:API controller provides full CRUD + content lookup endpoint
|
||||
3. Field whitelist prevents information leakage
|
||||
2. JSON:API controller provides full CRUD plus a content-lookup endpoint
|
||||
3. A field whitelist (`JsonapiView`) prevents information leakage
|
||||
|
||||
## Key Classes
|
||||
|
||||
| Class | Location | Purpose |
|
||||
|-------|----------|---------|
|
||||
| MokoOG | plg_system_mokoog | Main system plugin, meta tag injection |
|
||||
|---|---|---|
|
||||
| MokoOG | plg_system_mokoog | Meta tag injection, sitemap trigger, AI AJAX endpoint |
|
||||
| MokoOGContent | plg_content_mokoog | Editor form injection, OG data save/load |
|
||||
| MokoOGWebServices | plg_webservices_mokoog | API route registration |
|
||||
| TagsController | com_mokoog (admin) | Admin list publish/delete operations |
|
||||
| BatchController | com_mokoog | Batch OG generation for existing articles |
|
||||
| ImportExportController | com_mokoog | CSV import/export with language support |
|
||||
| DisplayController | com_mokoog | Default view dispatch (→ dashboard) |
|
||||
| DashboardModel | com_mokoog | Coverage metrics queries |
|
||||
| TagController / TagsController | com_mokoog | Single-record edit / list operations |
|
||||
| BatchController | com_mokoog | Batch OG generation |
|
||||
| ImportExportController | com_mokoog | CSV import/export (JSON/URL validated) |
|
||||
| TagTable | com_mokoog | DB table with field validation |
|
||||
| ImageHelper | plg_system_mokoog | Image resize, center-crop, validation |
|
||||
| ImageGenerator | plg_system_mokoog | Text overlay image generation (GD) |
|
||||
| JsonLdBuilder | plg_system_mokoog | Article, Product, WebPage, Breadcrumb schemas |
|
||||
| ImageHelper | plg_system_mokoog | Image resize, center-crop, per-platform crops, prune |
|
||||
| JsonLdBuilder | plg_system_mokoog | All JSON-LD schema builders + `toScriptTag()` |
|
||||
| SitemapBuilder | plg_system_mokoog | Access-filtered XML sitemap, atomic write |
|
||||
|
||||
## Database
|
||||
|
||||
@@ -53,11 +62,13 @@ Single table: `#__mokoog_tags`
|
||||
|
||||
- Unique key: `(content_type, content_id, language)`
|
||||
- Supports: `com_content`, `com_content.category`, `menu`, `com_mokoshop`
|
||||
- Language-aware queries prefer specific language over `*` wildcard
|
||||
- Columns include `og_*`, `seo_title`, `meta_description`, `robots`, `canonical_url`, `og_video`, `event_data`, `recipe_data`, `custom_schema`, `language`, `published`
|
||||
- Language-aware queries prefer a specific language over the `*` wildcard
|
||||
|
||||
## Performance
|
||||
## Performance & Safety
|
||||
|
||||
- `loadArticle()` and `loadShopProduct()` use static per-request caching
|
||||
- Article pages: 1 DB query instead of 5 (consolidated in v1.0)
|
||||
- Batch processing capped at 200 per request
|
||||
- Generated images cached by content hash in `images/mokoog/generated/`
|
||||
- `loadArticle()` / `loadShopProduct()` use static per-request caching (including negative lookups) — one query instead of several when the image finder, date extractor, and JSON-LD builder all need the same record
|
||||
- Batch processing is capped per request
|
||||
- Generated images are cached under `images/mokoog/generated/` and pruned after 30 days
|
||||
- The sitemap excludes non-public content and writes via a temp file + atomic rename
|
||||
- Custom JSON-LD is validated as an object/array on save **and** guarded on render, so malformed data cannot crash the public page
|
||||
|
||||
+83
-34
@@ -1,52 +1,101 @@
|
||||
# Configuration
|
||||
|
||||
Navigate to **Extensions > Plugins > System - MokoSuiteOpenGraph** to configure the plugin.
|
||||
Settings live in two places:
|
||||
|
||||
## Basic Settings
|
||||
- **System plugin** — site-wide defaults and behaviour. Navigate to **Extensions → Plugins → System - MokoSuiteOpenGraph**.
|
||||
- **Component Options** — permissions only. Open **Components → MokoSuiteOpenGraph → Options** (the gear icon).
|
||||
|
||||
---
|
||||
|
||||
## System Plugin
|
||||
|
||||
### Basic
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|-------------|
|
||||
| **Site Name** | The `og:site_name` value. Leave blank to use the Joomla site name. |
|
||||
| **Default OG Title** | Site-wide fallback title for social sharing. |
|
||||
| **Default OG Description** | Site-wide fallback description. |
|
||||
| **Default Image** | Fallback image. Recommended: 1200x630px. |
|
||||
| **Twitter Card Type** | Summary or Summary with Large Image. |
|
||||
| **Twitter @username** | Your site Twitter handle (e.g. @mokoconsulting). |
|
||||
| **Facebook App ID** | Your Facebook App ID for `fb:app_id` meta tag. |
|
||||
| **Telegram Channel** | Your Telegram channel handle for link previews. |
|
||||
| **Discord Embed Color** | The color of the embed sidebar when shared on Discord. |
|
||||
| **Fediverse Creator** | Your Fediverse/Mastodon handle (e.g. `@user@mastodon.social`). Outputs `fediverse:creator` meta tag. |
|
||||
|---|---|
|
||||
| **Site Name** (`og_site_name`) | The `og:site_name` value. Leave blank to use the Joomla site name. |
|
||||
| **Default OG Title** (`default_og_title`) | Site-wide fallback title for social sharing. |
|
||||
| **Default OG Description** (`default_og_description`) | Site-wide fallback description. |
|
||||
| **Default Image** (`default_image`) | Fallback image. Recommended: 1200×630px. |
|
||||
| **Twitter Card Type** (`twitter_card_type`) | `summary` or `summary_large_image`. |
|
||||
| **Twitter @username** (`twitter_site`) | Site Twitter/X handle (e.g. `@mokoconsulting`). |
|
||||
| **Facebook App ID** (`fb_app_id`) | Outputs the `fb:app_id` meta tag. |
|
||||
| **Telegram Channel** (`telegram_channel`) | Channel handle for link previews. |
|
||||
| **Discord Embed Color** (`discord_color`) | Sidebar color of the Discord embed (`theme-color`). |
|
||||
| **Fediverse Creator** (`fediverse_creator`) | Mastodon/Fediverse handle (e.g. `@user@mastodon.social`) → `fediverse:creator`. |
|
||||
|
||||
## Advanced Settings
|
||||
### Advanced
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|-------------|
|
||||
| **Auto-generate Tags** | Automatically generate OG tags from article content. |
|
||||
| **Strip HTML** | Remove HTML tags from auto-generated descriptions. |
|
||||
| **Description Length** | Maximum character length for `og:description` (50-300, default 160). |
|
||||
| **Auto-resize Images** | Resize images to 1200x630px using center crop. |
|
||||
| **Enable JSON-LD** | Output structured data for Google rich results. |
|
||||
| **JSON-LD Breadcrumbs** | Output BreadcrumbList schema from Joomla pathway. |
|
||||
|---|---|
|
||||
| **Auto-generate Tags** (`auto_generate`) | Generate OG tags from article content when no custom value is set. |
|
||||
| **Strip HTML** (`strip_html`) | Remove HTML from auto-generated descriptions. |
|
||||
| **Description Length** (`desc_length`) | Max characters for auto `og:description` (50–300, default 160). |
|
||||
| **Auto-resize Images** (`auto_resize`) | Resize images to 1200×630 using center crop. |
|
||||
| **Per-platform Resize** (`platform_resize`) | Additionally produce platform-specific crops (Twitter 1200×600, Pinterest 1000×1500, WhatsApp 400×400). |
|
||||
| **Enable JSON-LD** (`jsonld_enabled`) | Output structured data for Google rich results. |
|
||||
| **FAQ JSON-LD** (`jsonld_faq`) | Auto-detect FAQ pairs from article headings → FAQPage schema. |
|
||||
| **HowTo JSON-LD** (`jsonld_howto`) | Auto-detect steps from ordered lists → HowTo schema. |
|
||||
| **JSON-LD Breadcrumbs** (`jsonld_breadcrumbs`) | Output BreadcrumbList from the Joomla pathway. |
|
||||
|
||||
### LocalBusiness (`localbusiness`)
|
||||
|
||||
Enable (`lb_enabled`) to output a site-wide LocalBusiness schema. Fields: `lb_name`, `lb_type` (LocalBusiness/Restaurant/Store/…), `lb_street`, `lb_city`, `lb_region`, `lb_postal`, `lb_country`, `lb_phone`, `lb_email`, `lb_url`, `lb_opening_hours`, `lb_latitude`, `lb_longitude`, `lb_price_range`. Address, geo, and contact blocks are only emitted when their fields are filled.
|
||||
|
||||
### Sitemap (`sitemap`)
|
||||
|
||||
| Parameter | Description |
|
||||
|---|---|
|
||||
| **Enable Sitemap** (`sitemap_enabled`) | Regenerate `sitemap.xml` on article save. |
|
||||
| **Change Frequency** (`sitemap_changefreq`) | `daily`, `weekly`, or `monthly`. |
|
||||
|
||||
The sitemap includes only published articles at **public** view levels (registered/special-access content is excluded), skips `noindex` items, and is written atomically.
|
||||
|
||||
### AI Meta Generation (`ai`)
|
||||
|
||||
| Parameter | Description |
|
||||
|---|---|
|
||||
| **Enable AI** (`ai_enabled`) | Show the "Generate with AI" button in the editor. |
|
||||
| **Provider** (`ai_provider`) | `claude` or `openai`. |
|
||||
| **API Key** (`ai_api_key`) | Provider API key. |
|
||||
| **Model** (`ai_model`) | e.g. `claude-haiku-4-5-20251001`. |
|
||||
|
||||
> AI generation requires **article-edit** permission and uses an outbound HTTP call (20s timeout). Keep your API key private — anyone who can edit articles can spend credits.
|
||||
|
||||
---
|
||||
|
||||
## Component Options (Permissions)
|
||||
|
||||
The component ships an `access.xml` defining standard core actions plus two custom actions:
|
||||
|
||||
- **`mokoog.batch`** — run batch OG tag generation
|
||||
- **`mokoog.import`** — import/export OG tags via CSV
|
||||
|
||||
Configure them per user group under **Components → MokoSuiteOpenGraph → Options → Permissions**. Controllers fall back to the matching core action (`core.create` / `core.create`+`core.edit`) so existing setups keep working until you tighten the new actions.
|
||||
|
||||
---
|
||||
|
||||
## Fallback Chain
|
||||
|
||||
OG tag values are resolved in this order:
|
||||
|
||||
1. **Custom OG data** -- per-article/menu/category overrides set in the editor
|
||||
2. **Page metadata** -- Joomla page title, meta description, article images
|
||||
3. **Site-wide defaults** -- Default OG Title, Default OG Description, Default Image
|
||||
1. **Custom OG data** — per-article/menu/category overrides set in the editor
|
||||
2. **Page metadata** — Joomla page title, meta description, article images
|
||||
3. **Site-wide defaults** — Default OG Title, Default OG Description, Default Image
|
||||
|
||||
## Per-Content OG Fields
|
||||
|
||||
When editing an article, menu item, or category, you will see a **MokoSuiteOpenGraph** tab with:
|
||||
When editing an article, menu item, or category, the **MokoSuiteOpenGraph** tab provides:
|
||||
|
||||
- **OG Title** -- Custom title (60 optimal / 90 max chars)
|
||||
- **OG Description** -- Custom description (155 optimal / 200 max chars)
|
||||
- **OG Image** -- Custom image (Joomla media picker)
|
||||
- **OG Type** -- article, website, product, profile, book, music, video
|
||||
- **SEO Title** -- Custom `<title>` (60 optimal / 70 max chars)
|
||||
- **Meta Description** -- Custom meta description (155 optimal / 160 max chars)
|
||||
- **Robots** -- noindex, nofollow, noarchive, nosnippet, noimageindex
|
||||
- **Canonical URL** -- Custom canonical URL override
|
||||
- **OG Title** — custom title (60 optimal / 90 max chars)
|
||||
- **OG Description** — custom description (155 optimal / 200 max chars)
|
||||
- **OG Image** — custom image (Joomla media picker)
|
||||
- **OG Type** — article, website, product, profile, book, music, video
|
||||
- **og:video** — per-article video URL (YouTube/Vimeo/direct)
|
||||
- **SEO Title** — custom `<title>` (60 optimal / 70 max chars)
|
||||
- **Meta Description** — custom meta description (155 optimal / 200 max chars)
|
||||
- **Robots** — noindex, nofollow, noarchive, nosnippet, noimageindex
|
||||
- **Canonical URL** — custom canonical (http/https only)
|
||||
- **Custom JSON-LD / Event / Recipe** — per-article structured data (see [JSON-LD Schemas](JSON-LD-Schemas))
|
||||
|
||||
All text fields include live character count indicators with green/yellow/red color coding.
|
||||
All text fields include live character-count indicators with green/yellow/red color coding.
|
||||
|
||||
-120
@@ -1,120 +0,0 @@
|
||||
# Developer Guide
|
||||
|
||||
## REST API
|
||||
|
||||
The Web Services plugin exposes OG tags via Joomla JSON:API.
|
||||
|
||||
### Endpoints
|
||||
|
||||
| Method | URL | Description |
|
||||
|--------|-----|-------------|
|
||||
| GET | /api/v1/mokoog/tags | List all OG tags |
|
||||
| GET | /api/v1/mokoog/tags/:id | Get single OG tag |
|
||||
| POST | /api/v1/mokoog/tags | Create OG tag |
|
||||
| PATCH | /api/v1/mokoog/tags/:id | Update OG tag |
|
||||
| DELETE | /api/v1/mokoog/tags/:id | Delete OG tag |
|
||||
| GET | /api/v1/mokoog/lookup/:content_type/:content_id | Lookup by content |
|
||||
|
||||
### Authentication
|
||||
|
||||
All endpoints require Joomla API authentication (token or session).
|
||||
|
||||
### Fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| id | int | Primary key |
|
||||
| content_type | string | e.g. `com_content`, `menu`, `com_mokoshop` |
|
||||
| content_id | int | Content item ID |
|
||||
| og_title | string | OG title (max 255) |
|
||||
| og_description | string | OG description |
|
||||
| og_image | string | Image path |
|
||||
| og_type | string | article, website, product, profile, book |
|
||||
| seo_title | string | Page title override (max 70) |
|
||||
| meta_description | string | Meta description (max 200) |
|
||||
| robots | string | Robots directives |
|
||||
| canonical_url | string | Canonical URL |
|
||||
| language | string | Language tag (e.g. en-GB) or * |
|
||||
| published | int | 0 or 1 |
|
||||
|
||||
## Extending with Custom Plugins
|
||||
|
||||
### onMokoOGAfterRender Event
|
||||
|
||||
Third-party plugins can subscribe to the `onMokoOGAfterRender` event to add custom social meta tags for any platform.
|
||||
|
||||
```php
|
||||
use Joomla\Event\Event;
|
||||
use Joomla\Event\SubscriberInterface;
|
||||
|
||||
final class MyCustomSocialPlugin extends CMSPlugin implements SubscriberInterface
|
||||
{
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return ['onMokoOGAfterRender' => 'onMokoOGAfterRender'];
|
||||
}
|
||||
|
||||
public function onMokoOGAfterRender(Event $event): void
|
||||
{
|
||||
$doc = $event->getArgument('subject');
|
||||
$title = $event->getArgument('title');
|
||||
$image = $event->getArgument('image');
|
||||
|
||||
// Add Pinterest meta tag
|
||||
$doc->setMetaData('pinterest:media', $image);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Event Arguments
|
||||
|
||||
| Key | Type | Description |
|
||||
|-----|------|-------------|
|
||||
| subject | HtmlDocument | The Joomla document object |
|
||||
| title | string | Resolved OG title |
|
||||
| description | string | Resolved OG description |
|
||||
| image | string | Resolved image URL (absolute) |
|
||||
| url | string | Current page URL |
|
||||
| type | string | OG type (article, website, product, etc.) |
|
||||
| option | string | Component option (e.g. com_content, com_mokoshop) |
|
||||
| view | string | View name (e.g. article, product) |
|
||||
| id | int | Content item ID |
|
||||
|
||||
## MokoSuiteShop Integration
|
||||
|
||||
Product pages (`com_mokoshop`, view `product`) automatically receive:
|
||||
|
||||
- `og:type` set to `product`
|
||||
- `product:price:amount` and `product:price:currency` meta tags
|
||||
- JSON-LD `Product` schema with `offers`, `sku`, and `aggregateRating`
|
||||
- Image auto-extracted from the linked `#__content` article
|
||||
|
||||
Product data is loaded from `#__mokosuite_crm_products` joined to `#__content` via `article_id`.
|
||||
|
||||
## Database Schema
|
||||
|
||||
Table: `#__mokoog_tags`
|
||||
|
||||
| Column | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| id | INT UNSIGNED | Primary key |
|
||||
| content_type | VARCHAR(100) | e.g. com_content, menu, com_mokoshop |
|
||||
| content_id | INT UNSIGNED | ID of the content item |
|
||||
| og_title | VARCHAR(255) | Custom OG title |
|
||||
| og_description | TEXT | Custom OG description |
|
||||
| og_image | VARCHAR(512) | Image path relative to JPATH_ROOT |
|
||||
| og_type | VARCHAR(50) | article, website, product, etc. |
|
||||
| seo_title | VARCHAR(70) | Custom page title override |
|
||||
| meta_description | VARCHAR(200) | Custom meta description |
|
||||
| robots | VARCHAR(100) | Robots directive |
|
||||
| canonical_url | VARCHAR(512) | Canonical URL override |
|
||||
| language | CHAR(7) | Language tag (e.g. en-GB) or * |
|
||||
| published | TINYINT(1) | 0 or 1 |
|
||||
| created | DATETIME | Record creation time |
|
||||
| modified | DATETIME | Last modification time |
|
||||
|
||||
**Unique key:** `(content_type, content_id, language)`
|
||||
|
||||
## Performance
|
||||
|
||||
Article page OG generation uses a single cached DB query via `loadArticle()` with static per-request caching. Product data is similarly cached via `loadShopProduct()`. This avoids duplicate queries when multiple consumers (image finder, date extractor, JSON-LD builder) need the same article data.
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
# Developer Guide
|
||||
|
||||
## REST API
|
||||
|
||||
The Web Services plugin exposes OG tags via Joomla JSON:API. Full machine-readable spec: [`openapi.yaml`](openapi.yaml).
|
||||
|
||||
### Endpoints
|
||||
|
||||
| Method | URL | Description |
|
||||
|---|---|---|
|
||||
| GET | `/api/index.php/v1/mokoog/tags` | List all OG tags |
|
||||
| GET | `/api/index.php/v1/mokoog/tags/:id` | Get a single OG tag |
|
||||
| POST | `/api/index.php/v1/mokoog/tags` | Create an OG tag |
|
||||
| PATCH | `/api/index.php/v1/mokoog/tags/:id` | Update an OG tag |
|
||||
| DELETE | `/api/index.php/v1/mokoog/tags/:id` | Delete an OG tag |
|
||||
| GET | `/api/index.php/v1/mokoog/lookup/:content_type/:content_id` | Look up a tag by content |
|
||||
|
||||
### Authentication
|
||||
|
||||
All endpoints require Joomla API authentication (token or session) — the routes are registered as non-public.
|
||||
|
||||
### Fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|---|---|---|
|
||||
| id | int | Primary key |
|
||||
| content_type | string | e.g. `com_content`, `menu`, `com_mokoshop` |
|
||||
| content_id | int | Content item ID |
|
||||
| og_title | string | OG title |
|
||||
| og_description | string | OG description |
|
||||
| og_image | string | Image path |
|
||||
| og_type | string | article, website, product, profile, book… |
|
||||
| og_video | string | Video URL (YouTube/Vimeo/direct) |
|
||||
| seo_title | string | Page `<title>` override (max 70) |
|
||||
| meta_description | string | Meta description (max 200) |
|
||||
| robots | string | Robots directives |
|
||||
| canonical_url | string | Canonical URL (http/https) |
|
||||
| event_data | json | Event schema fields (object/array) |
|
||||
| recipe_data | json | Recipe schema fields (object/array) |
|
||||
| custom_schema | json | Arbitrary schema.org JSON-LD (object/array) |
|
||||
| language | string | Language tag (e.g. `en-GB`) or `*` |
|
||||
| published | int | 0 or 1 |
|
||||
|
||||
> JSON fields (`event_data`, `recipe_data`, `custom_schema`) must be JSON **objects/arrays** — scalars are rejected on save and via CSV import, and guarded on render.
|
||||
|
||||
## Extending with Custom Plugins
|
||||
|
||||
### `onMokoOGAfterRender` Event
|
||||
|
||||
Third-party plugins can subscribe to add custom social meta tags for any platform.
|
||||
|
||||
```php
|
||||
use Joomla\Event\Event;
|
||||
use Joomla\Event\SubscriberInterface;
|
||||
|
||||
final class MyCustomSocialPlugin extends CMSPlugin implements SubscriberInterface
|
||||
{
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return ['onMokoOGAfterRender' => 'onMokoOGAfterRender'];
|
||||
}
|
||||
|
||||
public function onMokoOGAfterRender(Event $event): void
|
||||
{
|
||||
$doc = $event->getArgument('subject');
|
||||
$image = $event->getArgument('image');
|
||||
|
||||
// Add a Pinterest meta tag
|
||||
$doc->setMetaData('pinterest:media', $image);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Event Arguments
|
||||
|
||||
| Key | Type | Description |
|
||||
|---|---|---|
|
||||
| subject | HtmlDocument | The Joomla document object |
|
||||
| title | string | Resolved OG title |
|
||||
| description | string | Resolved OG description |
|
||||
| image | string | Resolved image URL (absolute) |
|
||||
| url | string | Current page URL |
|
||||
| type | string | OG type (article, website, product…) |
|
||||
| option | string | Component option (e.g. com_content, com_mokoshop) |
|
||||
| view | string | View name (e.g. article, product) |
|
||||
| id | int | Content item ID |
|
||||
|
||||
## MokoSuiteShop Integration
|
||||
|
||||
Product pages (`com_mokoshop`, view `product`) automatically receive:
|
||||
|
||||
- `og:type` set to `product`
|
||||
- `product:price:amount` and `product:price:currency` meta tags
|
||||
- JSON-LD `Product` schema with `offers`, `sku`, and `aggregateRating`
|
||||
- Image auto-extracted from the linked `#__content` article
|
||||
|
||||
Product data is loaded from `#__mokosuite_crm_products` joined to `#__content` via `article_id`, with per-request caching.
|
||||
|
||||
## Database Schema
|
||||
|
||||
Table: `#__mokoog_tags` — unique key `(content_type, content_id, language)`. See [Architecture](Architecture) for the full column list. Fresh installs build the complete schema from `sql/install.mysql.sql`; upgrades apply incremental `sql/updates/mysql/*.sql` scripts.
|
||||
|
||||
## Forward Compatibility
|
||||
|
||||
The codebase is clean for Joomla 7: database access goes through `Factory::getContainer()->get(DatabaseInterface::class)`, language/app via `getApplication()`, filesystem via `Joomla\Filesystem\*`, and controllers throw exceptions instead of `jexit()`. The CI "deprecated Joomla API" check passes with zero findings.
|
||||
|
||||
## Testing
|
||||
|
||||
PHPUnit unit tests live under `tests/Unit/` (pure helpers — `JsonLdBuilder` schema builders and `toScriptTag()` escaping). Run via `vendor/bin/phpunit`. CI runs the suite on every PR.
|
||||
+15
-8
@@ -26,7 +26,7 @@ Open Graph, Twitter Card, and social sharing meta tag management for Joomla 6 an
|
||||
- **og:video** — YouTube, Vimeo, direct files with auto MIME detection
|
||||
|
||||
### JSON-LD Structured Data (11+ Types)
|
||||
Article, Product, WebPage, BreadcrumbList, Organization, VideoObject, FAQPage, HowTo, Event, Recipe, LocalBusiness + custom schema builder for any schema.org type
|
||||
Article, Product, WebPage, BreadcrumbList, Organization, VideoObject, FAQPage, HowTo, Event, Recipe, LocalBusiness + custom schema builder for any schema.org type. See [JSON-LD Schemas](JSON-LD-Schemas).
|
||||
|
||||
### Editor UX
|
||||
- **6 preview cards** — Facebook, Twitter/X, LinkedIn, Discord, Mastodon, Slack
|
||||
@@ -42,6 +42,8 @@ Article, Product, WebPage, BreadcrumbList, Organization, VideoObject, FAQPage, H
|
||||
- **Component permissions** — ACL actions (`mokoog.batch`, `mokoog.import`) in the component Options → Permissions
|
||||
- **XML sitemap** generation — respects noindex and public access levels
|
||||
|
||||
See the [Admin Guide](Admin-Guide).
|
||||
|
||||
### Developer Features
|
||||
- REST API — full CRUD via Joomla Web Services ([OpenAPI spec](openapi.yaml)); includes `og_video`, `event_data`, `recipe_data`, `custom_schema`
|
||||
- Per-platform image resizing (Twitter, Pinterest, WhatsApp); generated images auto-pruned after 30 days
|
||||
@@ -50,18 +52,23 @@ Article, Product, WebPage, BreadcrumbList, Organization, VideoObject, FAQPage, H
|
||||
- PHPUnit unit tests for JsonLdBuilder schema outputs and script-tag escaping
|
||||
- MokoSuiteShop integration with product JSON-LD
|
||||
|
||||
See the [Developer Guide](Developer-Guide).
|
||||
|
||||
---
|
||||
|
||||
## Wiki Structure
|
||||
## Documentation
|
||||
|
||||
### Guides
|
||||
- [Installation](guides/Installation)
|
||||
- [Configuration](guides/Configuration)
|
||||
- [Installation](Installation)
|
||||
- [Configuration](Configuration)
|
||||
- [Admin Guide](Admin-Guide)
|
||||
|
||||
### Reference
|
||||
- [Developer Guide](reference/Developer-Guide)
|
||||
- [Platform Support](reference/Platform-Support)
|
||||
- [Architecture](reference/Architecture)
|
||||
- [Developer Guide](Developer-Guide) — REST API, events, schema, MokoSuiteShop
|
||||
- [JSON-LD Schemas](JSON-LD-Schemas)
|
||||
- [Platform Support](Platform-Support)
|
||||
- [Architecture](Architecture)
|
||||
- [Troubleshooting](Troubleshooting)
|
||||
|
||||
---
|
||||
|
||||
@@ -71,7 +78,7 @@ Article, Product, WebPage, BreadcrumbList, Organization, VideoObject, FAQPage, H
|
||||
|
||||
| Revision | Date | Author | Description |
|
||||
|---|---|---|---|
|
||||
| 6.0 | 2026-06-29 | Moko Consulting | Joomla 6+/PHP 8.2+, rename to MokoSuiteOpenGraph, dashboard view, manual editor, ACL, security & forward-compat fixes |
|
||||
| 6.0 | 2026-06-29 | Moko Consulting | Joomla 6+/PHP 8.2+, rename to MokoSuiteOpenGraph, dashboard view, manual editor, ACL, security & forward-compat fixes; full wiki rebuild |
|
||||
| 5.0 | 2026-06-23 | Moko Consulting | v2.0: 11+ JSON-LD types, 6 preview cards, AI, sitemap, tests |
|
||||
| 4.0 | 2026-06-23 | Moko Consulting | v1.3: Fediverse, LinkedIn preview, character counters |
|
||||
| 3.0 | 2026-06-21 | Moko Consulting | Full assessment: MokoSuiteShop, JSON-LD Product, multilingual |
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
# JSON-LD Schemas
|
||||
|
||||
MokoSuiteOpenGraph emits [schema.org](https://schema.org) structured data as JSON-LD `<script type="application/ld+json">` blocks for Google rich results and other consumers. Enable it with **Enable JSON-LD** in the plugin's Advanced settings.
|
||||
|
||||
All output is encoded with `json_encode` and `</` is escaped to `<\/` to prevent `</script>` breakout (XSS-safe). Values pulled from content are never concatenated as raw strings.
|
||||
|
||||
## Automatic schemas
|
||||
|
||||
| Schema | When it's emitted | Source |
|
||||
|---|---|---|
|
||||
| **Article** | `com_content` article pages | Title, intro/full text, image, author, publish/modified dates |
|
||||
| **Product** | `com_mokoshop` product pages | Name, description, image, SKU, offers (price/currency/availability), aggregateRating |
|
||||
| **WebPage** | All pages | Page name, description, URL |
|
||||
| **BreadcrumbList** | All pages (optional) | Joomla pathway — toggle with **JSON-LD Breadcrumbs** |
|
||||
| **Organization** | Site-wide | Site name and URL |
|
||||
| **LocalBusiness** | Site-wide (optional) | The LocalBusiness fields in plugin config |
|
||||
|
||||
## Auto-detected schemas
|
||||
|
||||
| Schema | Trigger | Setting |
|
||||
|---|---|---|
|
||||
| **FAQPage** | Question/answer pairs detected from article `h3`/`h4` headings | **FAQ JSON-LD** |
|
||||
| **HowTo** | Steps detected from ordered (`<ol>`) lists | **HowTo JSON-LD** |
|
||||
|
||||
## Per-article schemas
|
||||
|
||||
Set in the article's **MokoSuiteOpenGraph** tab and stored in `#__mokoog_tags`:
|
||||
|
||||
| Schema | Field | Notes |
|
||||
|---|---|---|
|
||||
| **Event** | `event_data` | Dates, venue, ticket/offer info |
|
||||
| **Recipe** | `recipe_data` | Prep/cook times, ingredients, nutrition |
|
||||
| **VideoObject** | `og_video` | Built from the per-article video URL |
|
||||
| **Custom** | `custom_schema` | Any schema.org type — paste a JSON object |
|
||||
|
||||
> The Event/Recipe/Custom fields must contain a JSON **object** (e.g. `{ "startDate": "…" }`). Scalars (`42`, `"x"`, `true`) are rejected on save, on CSV import, and ignored on render — they previously caused a fatal page error and are now guarded.
|
||||
|
||||
## Custom schema example
|
||||
|
||||
Paste into the **Custom JSON-LD** field on an article:
|
||||
|
||||
```json
|
||||
{
|
||||
"@type": "SoftwareApplication",
|
||||
"name": "MokoSuiteOpenGraph",
|
||||
"applicationCategory": "Joomla Extension",
|
||||
"operatingSystem": "Joomla 6+",
|
||||
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" }
|
||||
}
|
||||
```
|
||||
|
||||
`@context` is added automatically if you omit it. The result is emitted as a standalone JSON-LD block on that page.
|
||||
|
||||
## Validating output
|
||||
|
||||
Use Google's [Rich Results Test](https://search.google.com/test/rich-results) or the Schema Markup Validator. The tag manager's per-row **G** debug link opens the Rich Results test pre-filled for that content item.
|
||||
@@ -1,12 +1,12 @@
|
||||
# Platform Support
|
||||
|
||||
MokoSuiteOpenGraph outputs platform-specific meta tags optimized for each social network.
|
||||
MokoSuiteOpenGraph outputs platform-specific meta tags optimized for each social network. See [JSON-LD Schemas](JSON-LD-Schemas) for structured-data details.
|
||||
|
||||
## Meta Tags by Platform
|
||||
|
||||
### Facebook / Meta
|
||||
- `og:title`, `og:description`, `og:image`, `og:url`, `og:type`, `og:site_name`, `og:locale`
|
||||
- `og:image:width`, `og:image:height` (dynamically detected from actual image)
|
||||
- `og:image:width`, `og:image:height` (dynamically detected from the actual image)
|
||||
- `og:video`, `og:video:secure_url`, `og:video:type`, `og:video:width`, `og:video:height` (per-article video URL)
|
||||
- `fb:app_id` (optional)
|
||||
|
||||
@@ -21,7 +21,7 @@ MokoSuiteOpenGraph outputs platform-specific meta tags optimized for each social
|
||||
|
||||
### Pinterest
|
||||
- `article:tag` for article rich pins (auto-extracted from Joomla content tags)
|
||||
- `product:price:amount`, `product:price:currency`, `product:availability` for product rich(pins (MokoSuiteShop)
|
||||
- `product:price:amount`, `product:price:currency`, `product:availability` for product rich pins (MokoSuiteShop)
|
||||
|
||||
### Discord
|
||||
- Reads standard `og:*` tags
|
||||
@@ -38,7 +38,7 @@ MokoSuiteOpenGraph outputs platform-specific meta tags optimized for each social
|
||||
|
||||
### WhatsApp
|
||||
- Reads standard `og:*` tags
|
||||
- Images auto-resized to meet minimum 300x200px requirement
|
||||
- Images auto-resized to meet the minimum 300×200px requirement
|
||||
|
||||
### Slack / Reddit
|
||||
- Read standard `og:*` tags natively — no special tags needed
|
||||
@@ -46,24 +46,9 @@ MokoSuiteOpenGraph outputs platform-specific meta tags optimized for each social
|
||||
### E-commerce / Product Pages
|
||||
- `og:type` set to `product` on MokoSuiteShop product pages
|
||||
- `product:price:amount` and `product:price:currency` for rich product previews
|
||||
- ~product:availability` derived from stock quantity (instock/outofstock)
|
||||
- `product:availability` derived from stock quantity (instock/outofstock)
|
||||
- Automatic on any `com_mokoshop` product view
|
||||
|
||||
## JSON-LD Structured Data
|
||||
|
||||
### Article pages (`com_content`)
|
||||
- `Article` schema with headline, description, image, author, datePublished, dateModified
|
||||
|
||||
### Product pages (`com_mokoshop`)
|
||||
- `Product` schema with name, description, image, sku
|
||||
- `Offer` with price, priceCurrency, availability (InStock/OutOfStock)
|
||||
- `AggregateRating` from approved reviews (if any)
|
||||
|
||||
### All pages
|
||||
- `WebPage` schema with name, description, URL
|
||||
- `BreadcrumbList` schema from Joomla pathway (optional)
|
||||
- `Organization` schema from site configuration
|
||||
|
||||
## Editor Preview Cards
|
||||
|
||||
When editing articles or menu items, live preview cards show how your content will appear on:
|
||||
@@ -71,5 +56,14 @@ When editing articles or menu items, live preview cards show how your content wi
|
||||
- **Facebook** — standard link preview card with image, title, description
|
||||
- **Twitter / X** — large image card with rounded corners
|
||||
- **LinkedIn** — professional card with image and title
|
||||
- **Discord** — embed with `theme-color` accent
|
||||
- **Mastodon** — Fediverse-style card
|
||||
- **Slack** — unfurl-style preview
|
||||
|
||||
All previews update in real-time as you type. Character count indicators show green/yellow/red warnings when text exceeds platform limits.
|
||||
All previews update in real time as you type. Character-count indicators show green/yellow/red warnings when text exceeds platform limits.
|
||||
|
||||
## Image Sizing
|
||||
|
||||
- Default OG image: 1200×630 (center crop)
|
||||
- Per-platform crops (when "Per-platform Resize" is enabled): Twitter 1200×600, Pinterest 1000×1500, WhatsApp 400×400
|
||||
- Generated images are cached and pruned after 30 days
|
||||
@@ -0,0 +1,47 @@
|
||||
# Troubleshooting
|
||||
|
||||
## Meta tags don't appear on the frontend
|
||||
|
||||
- Confirm the **System - MokoSuiteOpenGraph** plugin is **enabled** (Extensions → Plugins).
|
||||
- Meta tags are only injected on the **site** (frontend), on **HTML** documents — not in the admin or on JSON/feed views.
|
||||
- View the page source and search for `og:title`. If your template or another SEO plugin also sets OG tags, the last one to run wins — disable the duplicate.
|
||||
- Tags are emitted on `onBeforeCompileHead`; a template that builds its own `<head>` without calling the document head may bypass them.
|
||||
|
||||
## A page shows a 500 error after editing structured data
|
||||
|
||||
Older builds could crash if a **scalar** (e.g. `42`) was saved into the Custom JSON-LD / Event / Recipe field. This is fixed: such values are now rejected on save and ignored on render. If you hit it on an older version, edit the record (or re-import a corrected CSV) so the JSON field contains an **object** `{ … }` or is empty.
|
||||
|
||||
## OG image is missing or 404s
|
||||
|
||||
- Set a **Default Image** (1200×630) in the plugin config as a fallback.
|
||||
- Ensure the GD PHP extension is installed if you use auto-resize.
|
||||
- Auto-resized files are written to `images/mokoog/generated/` — that directory must be writable. Failed writes are logged (Joomla logs, category `mokoog`).
|
||||
|
||||
## Sitemap is empty or missing entries
|
||||
|
||||
- Enable **Sitemap** in the plugin config; `sitemap.xml` is regenerated when an article is saved.
|
||||
- Only **published** articles at **public** view levels are included — registered/special-access and `noindex` items are intentionally excluded.
|
||||
- `JPATH_ROOT/sitemap.xml` must be writable; failures are logged.
|
||||
|
||||
## AI generation returns nothing / an error
|
||||
|
||||
- AI must be enabled and an **API key** and **model** configured for the chosen provider.
|
||||
- The user must have **article-edit** permission — otherwise the request is rejected.
|
||||
- Non-200 responses from the provider now surface an error (HTTP status) instead of a blank result; check the message and your key/quota.
|
||||
- A hung provider times out after 20 seconds.
|
||||
|
||||
## "Forbidden" when running Batch or Import
|
||||
|
||||
Grant the relevant action under **Options → Permissions**: `mokoog.batch` for batch generation, `mokoog.import` for CSV import/export. Users with core `create` (batch) or core `create`+`edit` (import) also pass.
|
||||
|
||||
## The Options screen is empty
|
||||
|
||||
You're on an older build without `config.xml`. Update to the current version — the component now ships a `config.xml` with a Permissions tab. OG/SEO settings themselves live in the **System** plugin, not the component Options.
|
||||
|
||||
## Multilingual: wrong language tags
|
||||
|
||||
OG data is stored per language with the unique key `(content_type, content_id, language)`. Language-specific rows take priority over the `*` (All) wildcard. If an article's language is changed after saving, re-open and re-save its OG tab so the row is keyed to the new language.
|
||||
|
||||
## Reporting issues
|
||||
|
||||
Open an issue at the [repository](https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteOpenGraph/issues) with your Joomla and PHP versions and steps to reproduce.
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
### MokoSuiteOpenGraph
|
||||
|
||||
**Guides**
|
||||
- [Home](Home)
|
||||
- [Installation](Installation)
|
||||
- [Configuration](Configuration)
|
||||
- [Admin Guide](Admin-Guide)
|
||||
|
||||
**Reference**
|
||||
- [Developer Guide](Developer-Guide)
|
||||
- [JSON-LD Schemas](JSON-LD-Schemas)
|
||||
- [Platform Support](Platform-Support)
|
||||
- [Architecture](Architecture)
|
||||
- [Troubleshooting](Troubleshooting)
|
||||
Reference in New Issue
Block a user