diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5e87ebd..4676243 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- Fix multilingual data corruption in content plugin load/save (#41)
### Added
+- Fediverse/Mastodon `fediverse:creator` meta tag — first extension on any CMS to support this (#57)
+- Live character count indicators on OG title, OG description, SEO title, meta description fields with color-coded warnings (#58)
+- LinkedIn social preview card in article/menu editor alongside Facebook and Twitter/X previews (#61)
- Site-wide default OG title and description plugin parameters
- Discord embed color via `theme-color` meta tag (color picker in plugin config)
- LinkedIn article tags: `article:published_time`, `article:modified_time`, `article:author`
diff --git a/source/packages/plg_content_mokoog/media/css/preview.css b/source/packages/plg_content_mokoog/media/css/preview.css
index 0ad41bb..ae0a8af 100644
--- a/source/packages/plg_content_mokoog/media/css/preview.css
+++ b/source/packages/plg_content_mokoog/media/css/preview.css
@@ -102,3 +102,46 @@
color: #536471;
margin-top: 2px;
}
+
+/* LinkedIn card */
+.mokoog-card-li {
+ border: 1px solid #e0dfdc;
+ border-radius: 2px;
+}
+
+.mokoog-card-li .mokoog-card-body {
+ border-top-color: #e0dfdc;
+}
+
+.mokoog-card-li .mokoog-card-title {
+ font-size: 14px;
+ font-weight: 600;
+ color: rgba(0, 0, 0, 0.9);
+}
+
+.mokoog-card-li .mokoog-card-domain {
+ font-size: 12px;
+ color: rgba(0, 0, 0, 0.6);
+ text-transform: none;
+}
+
+/* Character count indicators */
+.mokoog-char-count {
+ display: block;
+ font-size: 12px;
+ margin-top: 4px;
+ font-variant-numeric: tabular-nums;
+}
+
+.mokoog-char-ok {
+ color: #2e7d32;
+}
+
+.mokoog-char-warn {
+ color: #f57c00;
+}
+
+.mokoog-char-over {
+ color: #d32f2f;
+ font-weight: 600;
+}
diff --git a/source/packages/plg_content_mokoog/media/js/preview.js b/source/packages/plg_content_mokoog/media/js/preview.js
index a10c3f1..6cc4e1a 100644
--- a/source/packages/plg_content_mokoog/media/js/preview.js
+++ b/source/packages/plg_content_mokoog/media/js/preview.js
@@ -15,9 +15,44 @@ document.addEventListener('DOMContentLoaded', function () {
ogDesc: document.getElementById('jform_mokoog_og_description'),
ogImage: document.getElementById('jform_mokoog_og_image'),
articleTitle: document.getElementById('jform_title'),
- metaDesc: document.getElementById('jform_metadesc')
+ metaDesc: document.getElementById('jform_metadesc'),
+ seoTitle: document.getElementById('jform_mokoog_seo_title'),
+ metaDescription: document.getElementById('jform_mokoog_meta_description')
};
+ // Character count indicators
+ var charLimits = [
+ { field: fields.ogTitle, optimal: 60, max: 90 },
+ { field: fields.ogDesc, optimal: 155, max: 200 },
+ { field: fields.seoTitle, optimal: 60, max: 70 },
+ { field: fields.metaDescription, optimal: 155, max: 160 }
+ ];
+
+ charLimits.forEach(function (cfg) {
+ if (!cfg.field) return;
+
+ var counter = document.createElement('span');
+ counter.className = 'mokoog-char-count';
+ cfg.field.parentNode.appendChild(counter);
+
+ function refresh() {
+ var len = cfg.field.value.length;
+ counter.textContent = len + '/' + cfg.optimal;
+
+ if (len > cfg.max) {
+ counter.className = 'mokoog-char-count mokoog-char-over';
+ } else if (len > cfg.optimal) {
+ counter.className = 'mokoog-char-count mokoog-char-warn';
+ } else {
+ counter.className = 'mokoog-char-count mokoog-char-ok';
+ }
+ }
+
+ cfg.field.addEventListener('input', refresh);
+ cfg.field.addEventListener('change', refresh);
+ refresh();
+ });
+
// Find the mokoog fieldset and insert preview after it
var fieldset = document.querySelector('[data-showon-id="mokoog"]') ||
document.getElementById('attrib-mokoog') ||
@@ -110,6 +145,36 @@ document.addEventListener('DOMContentLoaded', function () {
twCard.appendChild(twBody);
wrapper.appendChild(twCard);
+ // LinkedIn preview card
+ var liLabel = document.createElement('small');
+ liLabel.className = 'mokoog-platform-label';
+ liLabel.textContent = 'LinkedIn';
+ wrapper.appendChild(liLabel);
+
+ var liCard = document.createElement('div');
+ liCard.className = 'mokoog-card mokoog-card-li';
+
+ var liImg = document.createElement('div');
+ liImg.id = 'mokoog-li-img';
+ liImg.className = 'mokoog-card-img';
+ liCard.appendChild(liImg);
+
+ var liBody = document.createElement('div');
+ liBody.className = 'mokoog-card-body';
+
+ var liTitle = document.createElement('div');
+ liTitle.id = 'mokoog-li-title';
+ liTitle.className = 'mokoog-card-title';
+ liBody.appendChild(liTitle);
+
+ var liDomain = document.createElement('div');
+ liDomain.id = 'mokoog-li-domain';
+ liDomain.className = 'mokoog-card-domain';
+ liBody.appendChild(liDomain);
+
+ liCard.appendChild(liBody);
+ wrapper.appendChild(liCard);
+
preview.appendChild(wrapper);
fieldset.parentNode.insertBefore(preview, fieldset.nextSibling);
@@ -152,6 +217,18 @@ document.addEventListener('DOMContentLoaded', function () {
} else {
twImgEl.style.display = 'none';
}
+
+ // LinkedIn (shorter truncation: title 70, no description shown in card)
+ var liTitle = title.length > 70 ? title.substring(0, 67) + '...' : title;
+ document.getElementById('mokoog-li-title').textContent = liTitle;
+ document.getElementById('mokoog-li-domain').textContent = domain;
+ var liImgEl = document.getElementById('mokoog-li-img');
+ if (img) {
+ liImgEl.style.backgroundImage = 'url(' + encodeURI(img) + ')';
+ liImgEl.style.display = '';
+ } else {
+ liImgEl.style.display = 'none';
+ }
}
Object.values(fields).forEach(function (el) {
diff --git a/source/packages/plg_system_mokoog/language/en-GB/plg_system_mokoog.ini b/source/packages/plg_system_mokoog/language/en-GB/plg_system_mokoog.ini
index 3d1c0f6..e6fdb6b 100644
--- a/source/packages/plg_system_mokoog/language/en-GB/plg_system_mokoog.ini
+++ b/source/packages/plg_system_mokoog/language/en-GB/plg_system_mokoog.ini
@@ -23,6 +23,8 @@ PLG_SYSTEM_MOKOOG_FIELD_FB_APP_ID="Facebook App ID"
PLG_SYSTEM_MOKOOG_FIELD_FB_APP_ID_DESC="Your Facebook App ID for fb:app_id meta tag."
PLG_SYSTEM_MOKOOG_FIELD_DISCORD_COLOR="Discord Embed Color"
PLG_SYSTEM_MOKOOG_FIELD_DISCORD_COLOR_DESC="The color of the embed sidebar when shared on Discord. Sets the theme-color meta tag. Leave blank to use Discord defaults."
+PLG_SYSTEM_MOKOOG_FIELD_FEDIVERSE_CREATOR="Fediverse Creator"
+PLG_SYSTEM_MOKOOG_FIELD_FEDIVERSE_CREATOR_DESC="Your Fediverse/Mastodon handle (e.g. @user@mastodon.social). Outputs a fediverse:creator meta tag for author attribution on Mastodon and other Fediverse platforms."
PLG_SYSTEM_MOKOOG_FIELD_AUTO_GENERATE="Auto-generate Tags"
PLG_SYSTEM_MOKOOG_FIELD_AUTO_GENERATE_DESC="Automatically generate OG tags from article content when no custom tags are set."
PLG_SYSTEM_MOKOOG_FIELD_STRIP_HTML="Strip HTML from Description"
diff --git a/source/packages/plg_system_mokoog/language/en-US/plg_system_mokoog.ini b/source/packages/plg_system_mokoog/language/en-US/plg_system_mokoog.ini
index 3d1c0f6..e6fdb6b 100644
--- a/source/packages/plg_system_mokoog/language/en-US/plg_system_mokoog.ini
+++ b/source/packages/plg_system_mokoog/language/en-US/plg_system_mokoog.ini
@@ -23,6 +23,8 @@ PLG_SYSTEM_MOKOOG_FIELD_FB_APP_ID="Facebook App ID"
PLG_SYSTEM_MOKOOG_FIELD_FB_APP_ID_DESC="Your Facebook App ID for fb:app_id meta tag."
PLG_SYSTEM_MOKOOG_FIELD_DISCORD_COLOR="Discord Embed Color"
PLG_SYSTEM_MOKOOG_FIELD_DISCORD_COLOR_DESC="The color of the embed sidebar when shared on Discord. Sets the theme-color meta tag. Leave blank to use Discord defaults."
+PLG_SYSTEM_MOKOOG_FIELD_FEDIVERSE_CREATOR="Fediverse Creator"
+PLG_SYSTEM_MOKOOG_FIELD_FEDIVERSE_CREATOR_DESC="Your Fediverse/Mastodon handle (e.g. @user@mastodon.social). Outputs a fediverse:creator meta tag for author attribution on Mastodon and other Fediverse platforms."
PLG_SYSTEM_MOKOOG_FIELD_AUTO_GENERATE="Auto-generate Tags"
PLG_SYSTEM_MOKOOG_FIELD_AUTO_GENERATE_DESC="Automatically generate OG tags from article content when no custom tags are set."
PLG_SYSTEM_MOKOOG_FIELD_STRIP_HTML="Strip HTML from Description"
diff --git a/source/packages/plg_system_mokoog/mokoog.xml b/source/packages/plg_system_mokoog/mokoog.xml
index 759220c..d6ea7e0 100644
--- a/source/packages/plg_system_mokoog/mokoog.xml
+++ b/source/packages/plg_system_mokoog/mokoog.xml
@@ -106,6 +106,14 @@
description="PLG_SYSTEM_MOKOOG_FIELD_DISCORD_COLOR_DESC"
default=""
/>
+