Renamed .sys.ini to .ini and added en-US translation to match all other
membership gateway plugins, fixing install failure.
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Added explicit API call after release creation to force prerelease flag.
The moko-platform release_create.php was not honoring --prerelease for
RC releases, causing them to appear as stable releases.
Authored-by: Moko Consulting
Every extension manifest now has a <languages> tag pointing to its
.sys.ini file. This fixes Joomla showing language constants instead
of translated values.
Changes:
- Created 13 missing .sys.ini files for community/admin modules
- Fixed Instagram plugin language files (renamed from Facebook)
- Added <languages> to all 8 payment gateway plugin manifests
- Added <languages> to membership component, system plugin, webservices
- Added <languages> to offline payment plugin (new .sys.ini)
- Added <languages> to webservices membership plugin (new .sys.ini)
- Added language folder to webservices manifest <files>
0 manifests remain without language registration.
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pre-release workflow now triggers on:
- PR merged to dev → development channel (existing)
- PR opened/synced targeting main → release-candidate channel (new)
- Manual workflow_dispatch (existing)
When a PR to main is open, every push to the PR branch automatically
rebuilds the RC release package. This keeps the RC always up-to-date
with the latest changes before merge.
Changes:
- Added pull_request_target trigger for main branch
- Auto-detect stability as release-candidate for PRs to main
- Checkout PR head SHA for pull_request_target events
- Updated job condition to include new trigger
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Removed update-server.yml workflow (not needed)
- Removed wiki/ directory — wiki content belongs in Gitea wiki feature,
not committed to git
- Cleaned build/ and dist/ artifacts
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bug fixes for Joomla installation:
- Fixed media folder attribute: folder="css" -> folder="." to prevent
css/css path duplication that caused "File does not exist" error
- Fixed all TEXT NOT NULL columns to TEXT DEFAULT NULL across all SQL
files — MySQL strict mode rejects TEXT NOT NULL without a default
value on INSERT. Affects install.mysql.sql and all migration files.
Removed Community Builder references:
- README.md: removed "fork of Community Builder" and Joomlapolis credit
- CLAUDE.md: removed "fork of Community Builder" from description
- composer.json: cleaned description
- Language files: cleaned package description
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Push Notifications (#88):
- PushHelper: save/remove subscription, send push, get VAPID key
- ServiceWorker (service-worker.js): handles push events, notification
click opens URL, vibrate pattern, badge icon
- Subscriptions stored in profile params JSON (no new table)
- Config: push_enabled, push_vapid_public, push_vapid_private
- Note: full VAPID JWT signing needs minishlink/web-push composer package
Cross-Post to Facebook/Twitter (#93):
- CrossPostHelper: post to Facebook Graph API and Twitter API v2
- Uses social login OAuth tokens from linked accounts
- Only public posts can be cross-posted
- getAvailablePlatforms() checks which providers user has connected
- Config: crosspost_enabled toggle
- Rate limiting via platform API limits
Report Button on Messages:
- Added report link to conversation messages (message template)
- Completes #91 — report buttons now on: activity, forum topics,
forum replies, group posts, profiles, and messages
Workflow Sync:
- Imported branch-cleanup.yml from MokoOnyx template
- Synced ci-joomla.yml to latest version from MokoOnyx
- Synced all common workflows from moko-platform templates
Config Updates:
- Added Push Notifications fieldset (enabled, VAPID keys)
- Added Chat enabled toggle
- Added Cross-post enabled toggle
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Removed persistent session-based license key warnings from all 3 system
plugins (community, membership, sociallogin). The old approach checked
#__update_sites on every admin page load and showed a dismissible warning
once per session — annoying and ineffective.
New approach:
- License key stored in component config (config.xml License fieldset)
- Admin dashboard shows prominent alert if no valid key entered
- Green confirmation with masked key when valid
- Post-install message directs admin to config to enter key
- No session-based persistence, no repeated warnings
Changes:
- plg_system_mokojoomcommunity: removed warnMissingLicenseKey() + constants
- plg_system_mokojoommembership: removed warnMissingLicenseKey()
- plg_system_mokojoomsociallogin: removed warnMissingLicenseKey()
- config.xml: added License fieldset with license_key text field
- dashboard/default.php: license status alert (warning or success)
- script.php: post-install message with link to config
- 8 new language strings for license UI
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Chat Widget (JavaScript + CSS):
- Floating blue bubble in bottom-right corner (Messenger-style)
- Click to open conversation list with unread indicators
- Open conversation for real-time message thread
- AJAX polling: 5s when chat open, 15s background badge updates
- Safe DOM rendering — no innerHTML with user data (XSS-safe)
- Desktop notifications via Notification API (permission requested)
- Mobile responsive: full-screen on small screens
- Own messages right-aligned (blue), others left (gray)
- Online status based on last_activity (5-minute window)
ChatController (AJAX JSON endpoints):
- chat.status: unread count + conversation list
- chat.messages: message thread for a conversation
- chat.send: send message (POST)
- chat.start: create/get direct conversation with a user
- chat.online: list online users (last_activity < 5min)
- All endpoints return JSON and terminate
System Plugin Integration:
- onAfterRender injects chat CSS/JS before </body>
- Only for logged-in site users (not admin/API/guests)
- Updates last_activity on every page load for online status
- Respects chat_enabled config toggle
Created Gitea issue #93 for cross-posting to Facebook/Twitter.
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reusable report button partial (report_button.php):
- Dropdown with 5 reason options (spam, harassment, inappropriate,
misinformation, other) + optional details textarea
- Posts to moderation.report controller via CSRF-protected form
- Two styles: 'dropdown' (flag icon button) and 'link' (text link)
- Only shown to logged-in users viewing others' content
Report buttons added to:
- Activity posts (activity/default.php)
- Forum topics (forum/topic.php — on the topic body)
- Forum replies (forum/topic.php — on each reply)
- Group posts (group/detail.php)
- User profiles (profile/default.php)
Also added:
- Edit Profile button on own profile view
- 8 new language strings for report reasons and UI
Remaining templates needing report buttons (follow-up):
- Message conversations
- Gallery images
- Event pages
- Activity comments
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Full admin interface for creating/managing custom profile fields,
matching Community Builder's field management capabilities.
FieldController (admin):
- save(): create/update fields with validation (title required,
JSON params validated, auto-slug from title)
- delete(): removes field + all user values + privacy prefs
- savegroup(): create/update field groups
- deletegroup(): deletes group, ungroups contained fields
Form XML definitions:
- field.xml: title, name, type (text/textarea/select/date/email/url/number),
group, description, default value, visibility, required, registration,
published, ordering, params (JSON for type-specific options)
- fieldgroup.xml: title, description, ordering, published
Admin View + Template:
- Fields HtmlView with toolbar
- Split-panel template: fields table (left) + field groups (right)
- Inline create forms for both fields and groups
- Delete with confirmation (warns about data loss)
- Type badges, visibility labels, required/registration/published indicators
Supported field types:
- text, textarea, select (with JSON options array), date, email, url, number
- Params JSON for type-specific config:
select: {"options":["Option A","Option B"]}
number: {"min":0,"max":100,"maxlength":10}
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PHPUnit Setup (#43):
- Added phpunit/phpunit ^10.5 to composer.json require-dev
- Created phpunit.xml with Unit test suite targeting Helper directory
- Created tests/bootstrap.php with Joomla stub classes for isolated testing
(Factory, ComponentHelper, Registry, OutputFilter, Uri)
- PSR-4 autoload-dev for MokoJoomCommunity\Tests namespace
Test Cases (5 test files, 35+ test methods):
- RegGuardHelperTest: birthday validation (valid, future, too young, too old,
suspicious pattern, empty, invalid), username checks (normal, short,
excessive digits, mostly digits, custom pattern), email domain checks
(blocked, allowed, not in allowlist, empty), risk scoring and classification,
suggestion generation, IP detection
- ConditionalHelperTest: all 8 operators (equals, not_equals, contains, empty,
not_empty, greater_than, in, regex), match modes (all, any), empty conditions,
missing field handling
- ProgressHelperTest: progress bar HTML output, public static method signature
- PrivacyHelperTest: level constants, labels, map coverage
- TaxServiceTest: exclusive/inclusive tax, zero tax, discount + tax,
discount exceeding price, formatted breakdown
Language File Completion (#44):
- Added missing key COM_MOKOJOOMCOMMUNITY_FORUM_TOPIC
- Synced en-US from en-GB for both site and admin
- Audited: 108 used site keys, 138 defined (all covered)
- Audited: 57 used membership keys, 130 defined (all covered)
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Site Modules (8):
- mod_mokojoomcommunity_activity: Recent activity stream posts
- mod_mokojoomcommunity_members: Member directory (newest/active/popular sort)
- mod_mokojoomcommunity_groups: Groups listing with member counts
- mod_mokojoomcommunity_events: Upcoming events with dates and RSVP counts
- mod_mokojoomcommunity_login: Login form with social login integration
- mod_mokojoomcommunity_profile: Mini profile card with avatar and connection count
- mod_mokojoomcommunity_forum: Recent forum topics with reply counts
- mod_mokojoomcommunity_notifications: Bell dropdown with unread count and list
All modules use Joomla 5 AbstractModuleDispatcher pattern with
configurable max_items and sort options.
Admin Dashboard (cpanel):
- plg_quickicon_mokojoomcommunity: Quick icon stats on Joomla admin home
- Profile count, pending reports (warning), pending ID verifications,
forum topics, groups, upcoming events
- Links to community admin views
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instagram Login Provider (#12):
- New plg_mokosociallogin_instagram plugin
- Uses Facebook Login with Instagram scopes (same App ID)
- Fetches Instagram business account username and avatar
- Falls back to Facebook profile data if no IG account linked
- Full OAuth2 flow with CSRF state protection
Google One Tap (#13):
- Injects Google Identity Services One Tap prompt when enabled
- Configurable via plugin params (enable_one_tap toggle)
- Uses existing Google client_id and callback URL
- Script loaded with crossorigin="anonymous"
Security:
- Added crossorigin="anonymous" to external scripts
(Google GSI client, Telegram widget)
- SRI not feasible for dynamically-versioned provider scripts
Migration Tool (MigrationHelper):
- importCommunityBuilder(): profiles, custom fields, connections
- importAkeebaSocialLogin(): both #__user_profiles and #__sociallogin formats
- disableLegacyExtensions(): disables CB + all Akeeba sociallogin plugins
- runFullMigration(): one-call import + disable workflow
- CB fields auto-created with type mapping (text, select, date, etc.)
- Skips duplicates, reports errors per-record
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Social Login (#8-15):
- Telegram email fallback (#8): stores auth in session, signals needs_email
for system plugin to show collection form
- SocialAccountHelper: covers #9-#11, #14-#15
- User group assignment by provider (#9): reads provider_group_X from params
- Admin dashboard data (#10): stats by provider, recent linked accounts, search
- Account linking/unlinking (#11): linkAccount(), unlinkAccount(), getLinkedAccounts()
- Discord guild verification (#14): verifyDiscordGuild() via Discord API
- Discord role restrictions (#15): verifyDiscordRoles() via guild member API
- Instagram (#12) and Google One Tap (#13) need provider-level changes (kept open)
RegGuard:
- GeoIP country filtering (#22): ip-api.com lookup, allow/block country lists
- Admin dashboard (#24): getAdminDashboard() with stats by risk level and recent logs
Membership:
- Group/family memberships (#34): GroupMembershipService with add/remove/list members,
group_max_members in plan params, access grant/revoke for secondary members
- Verified #38 Dolibarr: plugin stub already exists
- Verified #45 Menu items: Router already registers plans/plan/subscribe/profile views
- Verified #47 Modules: both modules already implemented with Dispatchers
- Verified #48-49 Assets: media folder and CSS exist
- Verified #51 SEF Router: already implemented with MenuRules/StandardRules/NomenuRules
Migration:
- MigrationHelper: import from Community Builder and Akeeba Social Login
- CB profiles -> community profiles (avatar, canvas)
- CB custom field values -> community field values (auto-creates fields)
- CB connections -> community connections
- Akeeba Social Login -> mokojoomsociallogin_accounts (both #__user_profiles
and #__sociallogin table formats supported)
- Skips duplicates, reports errors, maps CB field types
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>