# Changelog ## [Unreleased] ## [01.12.00] --- 2026-06-28 ## [01.12.00] --- 2026-06-28 ### Added - **Visual post calendar**: Monthly calendar grid view showing scheduled, queued, and posted cross-posts with status badges (#160) - **Calendar navigation**: Month-by-month navigation with today highlighting (#160) - **Posting analytics**: Best time to post heatmap with day-of-week and hour-of-day breakdown (#165) - **Analytics service filter**: Filter heatmap and stats by service type with configurable date range - **Analytics service breakdown**: Per-service success rate, failure count, and average posts per day - **Analytics AJAX endpoint**: JSON heatmap data for dynamic filtering without page reload - **Social image generator**: Generate branded 1200x630 OG images with article title overlay using PHP GD (#157) - **Social image config**: Background color, text color, font size, and site name branding options (#157) - **Generate Social Image button**: One-click image generation in the Share Content panel (#157) - **AI caption generation**: Generate platform-optimized cross-post captions from article content using Claude or OpenAI (#161) - **AI provider config**: New "AI Caption Generation" fieldset in component options with provider, API key, model, and tone settings - **AI Generate button**: One-click AI generation button in the Share Content panel that fills all caption fields - **X/Twitter threads**: Auto-split messages exceeding 280 chars into reply chains at sentence boundaries - **X/Twitter cost-optimized posting**: Optional mode to post text-only tweet first ($0.015) with URL as separate reply ($0.20) - **X/Twitter cost warning**: Language string documenting X API pricing for text vs URL posts - **Instagram carousel**: Multi-image/video posts via Meta carousel container flow (up to 10 items) - **Instagram Reels**: Short-form video publishing via REELS media type - **Instagram Stories**: Image and video story publishing via STORIES media type - **Instagram alt text**: Alt text support for image containers - **Nostr plugin**: Full NIP-01 WebSocket relay publishing with BIP-340 Schnorr signatures (pure PHP, requires ext-gmp) - **Nostr**: Publishes kind-1 text note events to multiple relays with automatic failover - **Nostr**: Raw WebSocket client using stream_socket_client (no external dependencies) - **Nostr**: Public key derivation and event signing via secp256k1 elliptic curve math - **Threads carousel**: Support up to 20-item carousel posts via Threads API multi-container flow - **Threads polls**: Poll creation support via poll_options parameter (2-4 options) - **Threads spoiler tags**: Content warning / spoiler flag support for Threads posts - **Threads text-only optimization**: Simplified single-step flow for text-only posts without media - **Facebook Reels**: Publish video Reels via Graph API video_reels endpoint (#162) - **Facebook Stories**: Publish image and video Stories via photo_stories/video_stories endpoints (#162) - **Facebook scheduled posts**: Schedule feed posts with scheduled_publish_time parameter (#162) - **Facebook draft posts**: Save feed posts as unpublished drafts (#162) - **TikTok video upload**: PULL_FROM_URL video publishing via video/init endpoint with status polling (#164) - **TikTok photo carousel**: Up to 35 image carousel posts via content/init endpoint (#164) - **TikTok posting mode**: Configurable DIRECT_POST or MEDIA_UPLOAD (sends to TikTok inbox for in-app editing) (#164) - **TikTok audit warning**: Language string explaining that unverified apps can only create private posts (#164) - **Link shortening**: Shorten URLs via Bitly, Rebrandly, or YOURLS with {url_short} placeholder (#159) - **Site frontend**: Public-facing cross-post list and detail views for site visitors (#133) - **Social preview**: AJAX platform mockups (Twitter, Facebook, LinkedIn, Instagram, Mastodon, Bluesky) in article editor (#156) - **PHPUnit test suite**: Unit tests for models, helpers, and service plugins (#132) ### Fixed - **Content plugin**: Remove Joomla 5 typed event hints -- Joomla 6 dispatches `Model\AfterSaveEvent` instead of `Content\AfterSaveEvent`, causing fatal TypeError on article save - **PreviewController**: Add ACL check and parameterized query to prevent unauthorized article access (IDOR) - Webservices plugin Joomla 6 compatibility -- `onBeforeApiRoute` receives `BeforeApiRouteEvent` object, extract router via `$event->getRouter()` ## [01.07.00] --- 2026-06-23 ## [01.07.00] --- 2026-06-23 ### Added - **Full ACL system**: 12 granular permissions in access.xml with permissions fieldset in config.xml - **ACL enforcement**: All controllers and views check permissions before allowing actions - **MokoSuiteCrossHelper::getActions()**: Centralized ACL helper for toolbar and view logic ### Fixed - **License warning**: Removed duplicate from system plugin (install script already shows it) - **Content plugin**: Fixed func_get_arg crash when non-article content is saved (e.g. update sites, installer) ## [01.05.00] --- 2026-06-23 ## [01.05.00] --- 2026-06-23 ### Added - **Instagram plugin**: Cross-post to Instagram via Meta Content Publishing API (2-step container flow) - **YouTube plugin**: Cross-post to YouTube via Data API v3 channel bulletins - **Share Content panel**: Per-article editor panel with platform-specific share text fields - **New placeholders**: {social}, {short}, {chat}, {email_subject}, {email_body} for platform-optimized templates - **Share image control**: Choose intro image, fulltext image, custom image, or no image per article - **Mailchimp templates**: Support Mailchimp saved templates with section injection, plus responsive email wrapper fallback - **Delete from platforms**: New MokoSuiteCrossDeleteInterface for removing cross-posted content from remote platforms - **Delete support**: Twitter, Mastodon, Bluesky, Facebook, LinkedIn, Telegram, Discord (7 of 38 plugins) - **Auto-delete on unpublish**: Component config option to delete from platforms when articles are unpublished or trashed - **UTM auto-tagging**: Append utm_source, utm_medium, utm_campaign to shared URLs with {platform} token support - **Caption rotation**: {random:opt1|opt2|opt3} placeholder picks a random option per post - **{url_raw} placeholder**: Clean article URL without UTM parameters - **Mastodon enhancements**: Visibility levels, content warnings, scheduled posts, polls, language tags - **Bluesky threads**: Auto-split long messages into reply chains at sentence boundaries - **Bluesky link cards**: External link card embeds with article title and description - **Ntfy default server**: Default server changed to ntfy.mokoconsulting.tech with configurable plugin params ### Changed - **Default templates**: Updated to use platform-specific placeholders (social/short/chat/email) with graceful fallback ### Fixed - **Mailchimp**: Fixed broken namespace placeholder in XML manifest - **ConvertKit**: Removed duplicate curl_setopt_array with undefined $token - **Brevo**: Removed duplicate curl_setopt_array with undefined $token and wrong auth header - **Constant Contact**: Removed duplicate curl_setopt_array - **Mailchimp**: Fixed campaign creation checking HTTP 200 instead of 2xx range - **Medium**: Fixed getUserId() returning array instead of string on error - **Bluesky**: Replaced md5() with hash('sha256', ...) for cache key - **ServiceController**: Exception details no longer exposed to client - **License warning**: Removed duplicate from system plugin -- install script already shows it with direct edit link