1. Overview
The Easystore XTD plugin group extends EasyStore functionality with custom content integration and enhancements. These plugins utilize Joomla’s modern plugin architecture, service providers, and event-driven patterns to create flexible and maintainable extensions.
Download Sample Plugin
Prerequisites
Before proceeding, ensure that you have the following:
- Basic knowledge of PHP and Joomla CMS.
 
- EasyStore is installed and configured on your Joomla site.
 
Getting Started
- Download the provided sample plugin from the documentation.
 
- Extract the downloaded file and open it in your preferred code editor.
 
- Familiarize yourself with the structure of the plugin files.
 
2. Plugin Group Structure
When creating a new plugin, follow the directory structure below. It ensures consistency and seamless integration with EasyStore.

1. [plugin-name].xml
- Defines the plugin metadata (name, version, author).
 
- Lists all files used in the plugin.
 
- Declares language files and parameters.
 
2. services/provider.php
- Registers your plugin's service provider.
 
- Ensures event handling is properly hooked into EasyStore.
 
3. src/Extension/[PluginName].php
- Main plugin class file.
 
- Implements event subscriptions and logic.
 
4. language/[lang-tag]/
- Stores language files for localization.
 
plg_easystore-xtd_[plugin-name].ini: Main translation strings. 
plg_easystore-xtd_[plugin-name].sys.ini: Backend system messages. 
3. Event System
3.1 Supported Events
Easystore XTD plugins respond to the following events:
| 
 Event Name 
 | 
 Description 
 | 
 Parameters 
 | 
| 
 onEasystorePaymentBeforeDisplay 
 | 
 Before payment display 
 | 
 subject, view 
 | 
| 
 onEasystorePaymentSuccessRender 
 | 
 On successful payment 
 | 
 subject, paymentType, orderId 
 | 
| 
 onEasystorePaymentComplete 
 | 
 When payment is complete 
 | 
 subject, paymentType, orderId 
 | 
| 
 onEasystorePaymentCancel 
 | 
 On payment cancellation 
 | 
 subject, orderId 
 | 
| 
 onEasystorePaymentError 
 | 
 On payment error 
 | 
 subject, orderId 
 | 
| 
 onEasystorePaymentAfterDisplay 
 | 
 After payment display 
 | 
 subject, view 
 | 
 
3.2 Event Handler Implementation
Each plugin must implement SubscriberInterface and define the subscribed events:
public static function getSubscribedEvents(): array
{
    return [
        'onEasystoreCartBeforeRender' => 'onEasystoreCartBeforeRender',
        // Add additional events here
    ];
}
4. Plugin Development
Step 1: Create Plugin Directory
mkdir -p plugins/easystore-xtd/[plugin-name]
- Create the folder structure for your plugin under 
plugins/easystore-xtd/. 
[plugin-name] is your actual plugin name. 
Step 2: Create Plugin Manifest ([plugin-name].xml)
<?xml version="1.0" encoding="utf-8"?>
<extension method="upgrade" type="plugin" group="easystore-xtd">
    <name>PLG_EASYSTOREXTD_[PLUGINNAME]</name>
    <version>1.0.0</version>
    <description>PLG_EASYSTOREXTD_[PLUGINNAME]_DESCRIPTION</description>
    <author>Your Name</author>
    <namespace path="src">YourVendor\Plugin\EasyStoreXtd\[PluginName]</namespace>
    <files>
        <folder plugin="[plugin-name]">services</folder>
        <folder>src</folder>
        <folder>language</folder>
    </files>
</extension>
- This XML file tells Joomla about your plugin.
 
- It includes:
- Name and description
- Version number
- Author information
- Namespace location for your code
- Files and folders that belong to the plugin 
- Joomla reads this file during installation or upgrade.
 
Step 3: Create Service Provider (services/provider.php)
<?php
namespace YourVendor\Plugin\EasyStoreXtd\[PluginName]\Service;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use YourVendor\Plugin\EasyStoreXtd\[PluginName]\Extension\[PluginName];
return new class () implements ServiceProviderInterface
{
    public function register(Container $container)
    {
        $container->set(
            PluginInterface::class,
            function (Container $container) {
                $dispatcher = $container->get(DispatcherInterface::class);
                $plugin = new [PluginName](
                    $dispatcher,
                    (array) PluginHelper::getPlugin('easystore-xtd', '[plugin-name]')
                );
                return $plugin;
            }
        );
    }
}; 
Step 4: Create Main Plugin Class (src/Extension/[PluginName].php)
<?php
namespace YourVendor\Plugin\EasyStoreXtd\[PluginName]\Extension;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\DispatcherInterface;
use Joomla\Event\Event;
use Joomla\Event\SubscriberInterface;
class [PluginName] extends CMSPlugin implements SubscriberInterface
{
    protected $autoloadLanguage = true;
    public static function getSubscribedEvents(): array
    {
        return [
            'onEasystorePaymentComplete' => 'onPaymentComplete',
            // Add other events as needed
        ];
    } 
    public function onPaymentComplete(Event $event)
    {
        $subject = $event->getArgument('subject');
        $paymentType = $event->getArgument('paymentType');
        $orderId = $event->getArgument('orderId');
        // Your custom logic here
        $event->setArgument('subject', $subject);
    }
}
5. Configuration and Parameters
Access plugin parameters in your plugin class:
$enableLogging = $this->params->get('enable_logging', 1);
$customMessage = $this->params->get('custom_message', 'Default message');
6. Debugging and Logging
6.1 Built-in Logging (Example Custom Plugin)
$this->logPaymentActivity('custom_action', [
    'order_id' => $orderId,
    'data' => $customData
]);
6.2 Debug Mode
- Go to System > Global Configuration > System
 
- Set Debug System to Yes
 
- Check the debug console for detailed event information
 
7. Best Practices
1. Event Naming
- Use descriptive names
 
- Prefix with plugin name
 
- Follow onEasystore[Action][When] pattern
 
2. Error Handling
try {
    // Your code
} catch (\Exception $e) {
    $this->logPaymentActivity('error', [
        'message' => $e->getMessage(),
        'trace' => $e->getTraceAsString()
    ]);
}
3. Performance Optimization
- Cache expensive operations
 
- Minimize database queries
 
4. Security
- Validate inputs
 
- Sanitize outputs
 
- Use Joomla input filtering
 
- Follow Joomla security guidelines
 
8. Testing
8.1 Unit Testing
class [PluginName]Test extends \PHPUnit\Framework\TestCase
{
    public function testEventHandler()
    {
        // Test your event handlers
    }
} 
8.2 Integration Testing
- Install the plugin
 
- Trigger EasyStore events
 
- Verify expected behavior
 
9. Deployment
9.1 Installation
- Package plugin as a ZIP file
 
- Install via Joomla Extension Manager
 
- Enable the plugin
 
9.2 Updates
- Follow semantic versioning
 
- Include update SQL if required
 
- Test in a staging environment
 
10. Resources
11. Example: Custom Payment Gateway Integration
public function onEasystorePaymentComplete(Event $event)
{
    $subject = $event->getArgument('subject');
    $paymentType = $event->getArgument('paymentType');
    $orderId = $event->getArgument('orderId');    
    if ($paymentType === 'custom_gateway') {
        $this->processCustomGateway($orderId, $subject);
    }
}