
Privacy Plugin
- 1 installs
- 1 repo stars
- Updated July 21, 2026
- advansit/joomla
privacy-plugin is a Claude Code skill holding domain knowledge of the Joomla plg_privacy_j2commerce GDPR/DSGVO privacy plugin.
About
privacy-plugin holds domain knowledge of the plg_privacy_j2commerce plugin, which extends Joomla's com_privacy with J2Commerce-specific GDPR/DSGVO data handling. A developer uses it when working on retention logic, lifetime-license detection, checkout consent, data export or deletion, or the MyProfile privacy tab. It documents the privacy event handlers, key files, and a scheduled auto-cleanup task that anonymizes orders outside the retention period.
- Domain knowledge of a Joomla J2Commerce GDPR/DSGVO privacy plugin
- Covers retention logic, anonymization, consent, and data export/deletion
- Maps privacy events, key files, and a scheduled auto-cleanup task
Privacy Plugin by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,834 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Jul 22, 2026 (Skillselion catalog sync)
privacy-plugin capabilities & compatibility
- Capabilities
- gdpr compliance · data retention · consent management · data anonymization
- Use cases
- security audit
What privacy-plugin says it does
Deep knowledge of the plg_privacy_j2commerce plugin. Use when working on GDPR/DSGVO compliance, retention logic, lifetime license detection, template integration, checkout consent, or the MyProfile pr
Anonymizes orders outside the retention period instead of deleting them
npx skills add https://github.com/advansit/joomla --skill privacy-pluginAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 1 |
| Last updated | July 21, 2026 |
| Repository | advansit/joomla ↗ |
How do you correctly handle GDPR data export, retention, and consent in a Joomla J2Commerce store?
Work on GDPR retention, consent, anonymization, or data export in the Joomla J2Commerce privacy plugin.
Who is it for?
Developers maintaining GDPR/DSGVO data handling, retention, and consent in a Joomla J2Commerce store.
Skip if: Non-Joomla stacks or privacy work outside the J2Commerce/com_privacy ecosystem.
When should I use this skill?
Working on GDPR/DSGVO compliance, retention logic, consent, anonymization, or the MyProfile privacy tab.
What you get
Correct privacy export, retention-gated deletion, anonymization, and consent handling for J2Commerce data.
- Correct privacy event handling
- Retention, anonymization, and consent implementation
By the numbers
- 5 documented privacy events handled (export, canRemove, remove, afterRender, ajax)
- 4 reference docs (architecture, retention-logic, template-integration, known-issues)
Files
Privacy Plugin — Domain Knowledge
Location
j2commerce/plg_privacy_j2commerce/
What This Plugin Does
Extends Joomla's com_privacy with J2Commerce-specific data handling:
- Exports J2Commerce orders, addresses, cart data on privacy export requests
- Enforces configurable retention periods before allowing data deletion
- Anonymizes orders outside the retention period instead of deleting them
- Detects lifetime licenses to preserve email after retention expires
- Adds a consent checkbox to the J2Commerce checkout
- Renders a self-service privacy tab in the J2Commerce MyProfile page
- Runs a scheduled automatic cleanup task
Key Files
| File | Purpose |
|---|---|
src/Extension/J2Commerce.php | Main plugin class — all event handlers |
src/Task/AutoCleanupTask.php | Scheduled cleanup task |
script.php | Install/update/uninstall, post-install message |
language/en-GB/plg_privacy_j2commerce.ini | All translatable strings |
Events Handled
| Event | Purpose |
|---|---|
onPrivacyExportRequest | Collect J2Commerce data for export |
onPrivacyCanRemoveData | Check if retention blocks deletion |
onPrivacyRemoveData | Anonymize/delete data |
onAfterRender | Inject consent checkbox + privacy section (fallback) |
onAjaxJ2commercePrivacy | Handle address deletion AJAX requests |
See references/architecture.md for full details.
Plugin Architecture
Relationship to Joomla Core
This plugin is a privacy group plugin that extends com_privacy. It does not replace the core privacy system — it adds J2Commerce data on top.
Joomla core handles: request management UI, export/deletion workflow, consent tracking (#__privacy_consents), action logging.
This plugin handles: J2Commerce-specific data in exports, retention enforcement, order anonymization, lifetime license detection, checkout consent, MyProfile tab.
Reference: Joomla Privacy Suite Guide
Class Structure
J2Commerce extends CMSPlugin (via PrivacyPlugin)
├── onPrivacyExportRequest() — collect export domains
│ └── collectExportDomains()
│ ├── createOrdersDomain()
│ ├── createAddressesDomain()
│ └── createCartDomain()
├── onPrivacyCanRemoveData() — check retention
│ └── checkRetentionPeriod() — NOT checkOrderRetention()
├── onPrivacyRemoveData() — anonymize/delete
│ ├── anonymizeOrders()
│ ├── deleteAddresses()
│ └── deleteCartData()
├── onAfterRender() — fallback injection
│ ├── injectConsentCheckbox()
│ ├── injectDeleteAddressButtons()
│ └── injectPrivacySection()
└── onAjaxJ2commercePrivacy() — AJAX address deletion
AutoCleanupTask extends CMSPlugin
└── autoCleanup() — scheduled task
├── hasLifetimeLicense()
├── partialAnonymizeUserData()
└── anonymizeUserData()AJAX
Address deletion uses Joomla's com_ajax:
index.php?option=com_ajax&plugin=j2commerce_privacy&group=privacy&format=json&task=deleteAddress&address_id={id}No dependency on plg_ajax_joomlaajaxforms — uses Joomla Core com_ajax only.
Language Loading
The privacy plugin group is not auto-imported in the Joomla frontend. The plugin has $autoloadLanguage = true which loads the language when the plugin is triggered. For template overrides that need language strings before the plugin fires, load manually:
Factory::getLanguage()->load('plg_privacy_j2commerce', JPATH_PLUGINS . '/privacy/j2commerce');Database Tables Used
| Table | Purpose |
|---|---|
#__j2store_orders | Order data, anonymization target |
#__j2store_orderinfos | Billing/shipping addresses per order |
#__j2store_orderitems | Order line items |
#__j2store_addresses | Saved user addresses |
#__j2store_carts | Active carts |
#__j2store_cartitems | Cart line items |
#__j2store_product_customfields | Lifetime license flag per product |
#__license_keys | Issued license keys per user (separate from J2Commerce UI) |
#__privacy_consents | Joomla core consent records |
Known Issues and Decisions
Language Overrides Not Working in Emails
Issue: Language overrides created via Joomla's Language Manager do not apply to email tags like [ORDERSTATUS], [BILLING_COUNTRY], [SHIPPING_METHOD].
Root cause (confirmed, GitHub Issue #273): 1. helpers/email.php loads overrides into $jlang = JFactory::getLanguage() (global instance, Factory::$language) 2. Tag resolution uses $language = JLanguage::getInstance($order->customer_language) (separate instance, Language::$languages[]) 3. These are two distinct static caches — overrides loaded into one are not visible to the other 4. Additionally, loadLanguageOverrides() only loads from JPATH_ADMINISTRATOR, but Joomla Language Manager writes overrides to JPATH_SITE/language/overrides/
Status: Reported upstream to j2commerce/j2cart#273. Fix pending from j2commerce team.
Workaround: None currently — JavaScript-based workarounds are fragile.
onAfterRender and Privacy Plugin Group
The privacy plugin group IS able to hook into onAfterRender. The plugin explicitly registers this event. The README previously stated otherwise — this was corrected in v1.5.0.
Custom Field vs License Keys Table
Two separate tables are involved in lifetime license detection:
#__j2store_product_customfields— marks products as lifetime licenses (populated via J2Commerce Custom Fields UI)#__license_keys— stores issued license keys per user (separate table, not visible in J2Commerce UI, created via SQL in post-install message)
Updates Not Shown in Joomla Backend
Issue: System → Update → Extensions does not show available updates for our plugins.
Root cause: Plugins without <client> in update.xml get client_id=1 in jos_updates. Our plugins install with client_id=0. Joomla cannot match the update record to the installed extension.
Fix: All plugin update.xml files must include <client>site</client>. See joomla-extensions/references/repo-structure.md.
Discovered: 2026-04-29, fixed in PR #69.
Minimum Requirements
- Joomla 5.0+ (uses DI container,
Factory::getContainer()) - PHP 8.1+
- J2Commerce 4.0+
script.php enforces these via $minimumJoomla and $minimumPhp.
Recurring Subscriptions
Automated handling of recurring subscription products is not implemented. Subscription lifecycle management requires manual intervention.
Retention Logic
How Retention Works
checkRetentionPeriod(int $userId): array checks all orders for the user:
1. For each order, calculate order_date + retention_years 2. If any order is within the retention period → block deletion 3. Return array with can_remove (bool) and details per order
Anonymization (orders outside retention)
anonymizeOrders(int $userId) sets these fields on expired orders:
| Field | Value |
|---|---|
user_email | anonymized@example.com |
billing_first_name | Anonymized |
billing_last_name | User |
shipping_first_name | '' (cleared) |
shipping_last_name | '' (cleared) |
customer_note | '' (cleared) |
ip_address | '' (cleared) |
| Phone, address fields | '' (cleared) |
Order numbers, dates, amounts, and product information are preserved (required for accounting).
Lifetime License Exception
If a user has a lifetime license (#__license_keys + #__j2store_product_customfields.is_lifetime_license = Yes):
- After retention expires: orders are anonymized BUT email is preserved
- Reason: email is needed for license activation/verification
partialAnonymizeUserData()handles this case (email kept, all other PII cleared)anonymizeUserData()handles the normal case (email also cleared)
Retention Periods by Country
| Country | Years | Legal Basis |
|---|---|---|
| Switzerland | 10 | OR Art. 958f, MWSTG Art. 70 |
| Germany | 10 | AO §147, HGB §257 |
| Austria | 7 | BAO §132, UGB §212 |
| France | 10 | Code de commerce |
| Spain | 6 | Código de Comercio |
| UK | 6 | Companies Act 2006 |
| USA | 7 | IRS guidelines |
Default: 10 years (Swiss standard).
Scheduled Cleanup
AutoCleanupTask runs via Joomla Scheduler. It processes all users with expired retention periods automatically, without requiring a manual deletion request. Configure under System → Scheduled Tasks → J2Commerce - Automatic Data Cleanup.
Template Integration
Two Rendering Mechanisms
| Mechanism | Recommended | How |
|---|---|---|
| Template override | Yes | default.php checks for plugin via PluginHelper, renders default_privacy.php |
onAfterRender fallback | No | Plugin injects HTML by searching rendered output for CSS selectors |
Use the template override. The onAfterRender fallback is fragile — it searches for patterns like j2store-myprofile in the rendered HTML and silently fails if the markup differs.
Files to Copy
From advansit/advans.ch repo, src/template/html/com_j2store/:
MyProfile privacy tab:
myprofile/default.php
myprofile/default_privacy.php
myprofile/orderitems.phpCheckout consent checkbox:
checkout/default_shipping_payment.phpTarget: templates/{your-template}/html/com_j2store/
Requirements
- Bootstrap 5 template (the override uses BS5 tab markup)
- Plugin installed and enabled
How default.php Activates the Tab
$privacyPlugin = PluginHelper::getPlugin('privacy', 'j2commerce');
if ($privacyPlugin) {
$privacyParams = new \Joomla\Registry\Registry($privacyPlugin->params);
$showPrivacyTab = (bool) $privacyParams->get('show_privacy_section', 1);
Factory::getLanguage()->load('plg_privacy_j2commerce', JPATH_PLUGINS . '/privacy/j2commerce');
}If the plugin is disabled or not installed, $showPrivacyTab is false — no errors, tab simply hidden.
Checkout Consent
default_shipping_payment.php reads plugin params directly from #__extensions (not via PluginHelper) because the privacy plugin group is not imported during checkout AJAX requests:
$_privacyPlugin = PluginHelper::getPlugin('privacy', 'j2commerce');
if ($_privacyPlugin) {
$_pp = new Registry($_privacyPlugin->params);
if ($_pp->get('show_consent_checkbox', 1)) {
// render checkbox
}
}Consent is recorded in #__privacy_consents when the user reaches the confirm step.
Related skills
FAQ
What does the privacy plugin do?
It extends Joomla's com_privacy to export, retain, anonymize, and consent-gate J2Commerce orders, addresses, and cart data.
What happens to old orders?
Orders outside the retention period are anonymized instead of deleted, with a scheduled auto-cleanup task.