{% extends "baseTemplate/index.html" %} {% load i18n %} {% load static %} {% block title %}{% trans "Plugin Development Help - CyberPanel" %}{% endblock %} {% block header_scripts %} {% endblock %} {% block content %}
{% trans "Back to Installed Plugins" %}

{% trans "Plugin Development Guide" %}

{% trans "Comprehensive guide to creating plugins for CyberPanel. Learn how to build, package, and distribute your own plugins." %}

{% trans "Introduction" %}

{% trans "CyberPanel's plugin system allows developers to extend the control panel's functionality with custom features. Plugins integrate seamlessly with CyberPanel's Django-based architecture, providing access to the full power of the platform while maintaining security and consistency." %}

{% trans "What Can Plugins Do?" %}

  • {% trans "Add new administrative features" %}
  • {% trans "Integrate with external services (APIs, webhooks, etc.)" %}
  • {% trans "Customize the user interface" %}
  • {% trans "Extend database functionality" %}
  • {% trans "Add automation and monitoring capabilities" %}
  • {% trans "Create custom reporting tools" %}
  • {% trans "Integrate security features" %}

{% trans "Prerequisites" %}

{% trans "Required Knowledge" %}

  • Python 3.6+: {% trans "Basic to intermediate Python knowledge" %}
  • Django Framework: {% trans "Understanding of Django views, URLs, templates, and models" %}
  • HTML/CSS/JavaScript: {% trans "For creating user interfaces" %}
  • Linux/Unix: {% trans "Basic command-line familiarity" %}
  • XML: {% trans "Understanding of XML structure for meta.xml" %}

{% trans "Plugin Architecture Overview" %}

{% trans "How Plugins Work" %}

  1. {% trans "Plugin Source Location" %}: /home/cyberpanel/plugins/
    • {% trans "Plugins are stored here before installation" %}
    • {% trans "Can be uploaded as ZIP files or placed directly" %}
  2. {% trans "Installed Location" %}: /usr/local/CyberCP/
    • {% trans "After installation, plugins are copied here" %}
    • {% trans "This is where CyberPanel loads plugins from" %}

{% trans "Creating Your First Plugin" %}

{% trans "Step 1: Create Plugin Directory Structure" %}

# Navigate to plugins directory
cd /home/cyberpanel/plugins

# Create your plugin directory
mkdir myFirstPlugin
cd myFirstPlugin

# Create required subdirectories
mkdir -p templates/myFirstPlugin
mkdir -p static/myFirstPlugin/css
mkdir -p static/myFirstPlugin/js
mkdir -p migrations

{% trans "Step 2: Create meta.xml (REQUIRED)" %}

<?xml version="1.0" encoding="UTF-8"?>
<cyberpanelPluginConfig>
    <name>My First Plugin</name>
    <type>Utility</type>
    <description>A simple example plugin</description>
    <version>1.0.0</version>
    <url>/plugins/myFirstPlugin/</url>
    <settings_url>/plugins/myFirstPlugin/settings/</settings_url>
</cyberpanelPluginConfig>
{% trans "Required: Category (type)" %}: {% trans "The <type> field is required. See the Plugin Categories section below for valid options. Plugins without a valid category will not appear in the Plugin Store." %}

{% trans "Step 3: Create urls.py" %}

from django.urls import path
from . import views

app_name = 'myFirstPlugin'

urlpatterns = [
    path('', views.main_view, name='main'),
    path('settings/', views.settings_view, name='settings'),
]

{% trans "Step 4: Create views.py" %}

from django.shortcuts import render, redirect
from functools import wraps

def cyberpanel_login_required(view_func):
    """Custom decorator for CyberPanel session authentication"""
    @wraps(view_func)
    def _wrapped_view(request, *args, **kwargs):
        try:
            userID = request.session['userID']
            return view_func(request, *args, **kwargs)
        except KeyError:
            from loginSystem.views import loadLoginPage
            return redirect(loadLoginPage)
    return _wrapped_view

@cyberpanel_login_required
def main_view(request):
    context = {
        'plugin_name': 'My First Plugin',
        'version': '1.0.0'
    }
    return render(request, 'myFirstPlugin/main.html', context)

{% trans "Step 5: Create Templates" %}

{% trans "Templates must extend baseTemplate/index.html:" %}

{% verbatim %}
{% extends "baseTemplate/index.html" %}
{% load static %}
{% load i18n %}

{% block title %}
    My First Plugin - {% trans "CyberPanel" %}
{% endblock %}

{% block content %}
    

{{ plugin_name }}

Version {{ version }}

{% endblock %}
{% endverbatim %}
{% trans "Important" %}: {% trans "Always use the @cyberpanel_login_required decorator for all views to ensure users are authenticated." %}

{% trans "Plugin Structure & Files" %}

{% trans "Required Files" %}

  • __init__.py - {% trans "Required" %} - {% trans "Python package marker" %}
  • meta.xml - {% trans "Required" %} - {% trans "Plugin metadata" %}
  • urls.py - {% trans "Required" %} - {% trans "URL routing" %}
  • views.py - {% trans "Required" %} - {% trans "View functions" %}

{% trans "Optional Files" %}

  • models.py - {% trans "Optional" %} - {% trans "Database models" %}
  • forms.py - {% trans "Optional" %} - {% trans "Django forms" %}
  • utils.py - {% trans "Optional" %} - {% trans "Utility functions" %}
  • templates/ - {% trans "Optional" %} - {% trans "HTML templates" %}
  • static/ - {% trans "Optional" %} - {% trans "CSS, JS, images" %}

{% trans "Version Numbering (Semantic Versioning)" %}

{% trans "CyberPanel plugins use semantic versioning (SemVer) with a three-number format (X.Y.Z) to help users understand the impact of each update:" %}

{% trans "Major Version (X.0.0)" %}

{% trans "Breaking changes that may require action from users. New major features, complete redesigns, or changes that break existing functionality." %}

{% trans "Example" %}: 2.8.0 → 3.0.0

{% trans "Minor Version (0.X.0)" %}

{% trans "New features added in a backward-compatible manner. Enhancements and improvements that don't break existing functionality." %}

{% trans "Example" %}: 3.0.0 → 3.1.0

{% trans "Patch Version (0.0.X)" %}

{% trans "Bug fixes and minor improvements. Backward-compatible fixes that address issues without adding new features." %}

{% trans "Example" %}: 3.1.0 → 3.1.1

{% trans "Important" %}: {% trans "Always use the three-number format (X.Y.Z) in your meta.xml file. This makes it easier to track updates and understand the scope of changes. Start with version 1.0.0 for your first release." %}

{% trans "Version Format in meta.xml" %}

<version>1.0.0</version>

{% trans "Never use formats like '1.0' or 'v1.0'. Always use the full semantic version: '1.0.0'" %}

{% trans "Plugin Categories" %}

{% trans "The <type> field in meta.xml determines how your plugin is grouped in the Plugin Store. Use exactly one of these values (case-sensitive):" %}

{% trans "Category" %} {% trans "Purpose" %}
Utility{% trans "General-purpose tools, helpers, and utilities" %}
Security{% trans "Security features: firewalls, fail2ban, SSL, etc." %}
Backup{% trans "Backup, snapshot, and restore functionality" %}
Performance{% trans "Caching, optimization, and performance tuning" %}
Monitoring{% trans "Monitoring, alerts, and health checks" %}
Integration{% trans "Third-party integrations: Discord, Slack, webhooks, APIs" %}
Email{% trans "Email marketing, SMTP, mail management" %}
Development{% trans "Developer tools: PM2, Node.js, deployment" %}
Analytics{% trans "Analytics, tracking, and reporting" %}

{% trans "Freshness Badges" %}

{% trans "The Plugin Store and Installed Plugins views display freshness badges based on the last update date (modify_date from GitHub commit or meta.xml file mtime). These help users quickly see how actively maintained a plugin is:" %}

{% trans "Badge" %} {% trans "Condition" %} {% trans "Meaning" %}
NEW{% trans "Updated within last 90 days" %}{% trans "Recently released or actively maintained" %}
Stable{% trans "Updated within last 365 days" %}{% trans "Updated within the past year" %}
Unstable{% trans "1–2 years since last update" %}{% trans "May need maintenance; consider forking or updating" %}
STALE{% trans "Over 2 years since last update" %}{% trans "Not updated recently; use with caution" %}

{% trans "Badges are calculated automatically from the plugin's modify_date. For plugins in the Plugin Store, this comes from the GitHub repository's last commit. For installed plugins, it uses the meta.xml file modification time." %}

{% trans "Premium/Paid Plugin Creation" %}

{% trans "You can create premium (paid) plugins and implement your own verification system. This includes optional encryption between the plugin and your verification site to prevent unauthorized bypass." %}

{% trans "1. Mark Your Plugin as Paid in meta.xml" %}

<paid>true</paid>
<patreon_tier>Your Tier Name</patreon_tier>
<patreon_url>https://www.patreon.com/your-page</patreon_url>

{% trans "Set <paid>true</paid> to display the Premium badge and subscription prompts in the Plugin Store." %}

{% trans "2. Build Your Own Verification System" %}

{% trans "Premium plugins typically verify access via a remote API. You can host this on your own site. Common verification methods:" %}

  • {% trans "Patreon" %}: {% trans "Verify membership via Patreon OAuth/API" %}
  • {% trans "PayPal" %}: {% trans "Verify one-time or recurring payments" %}
  • {% trans "Plugin Grants" %}: {% trans "Admin panel where you manually grant access by email, IP, or domain" %}
  • {% trans "Activation Keys" %}: {% trans "Generate unique keys when granting access; users enter the key in the plugin" %}

{% trans "3. Optional: Encrypt Plugin–API Communication" %}

{% trans "To protect against users modifying your plugin to bypass verification, you can encrypt the communication between the plugin and your verification API using AES-256-CBC. This ensures:" %}

  • {% trans "Verification requests cannot be easily intercepted or forged" %}
  • {% trans "Responses cannot be tampered with" %}
  • {% trans "Your verification logic remains on your server; the plugin only encrypts/decrypts with a shared key" %}

{% trans "Implementation outline:" %}

  1. {% trans "Generate a 32-byte secret key and store it in your API config (e.g. config.php)" %}
  2. {% trans "In your plugin (Python), encrypt outgoing requests and decrypt responses using the same key" %}
  3. {% trans "On your API (PHP/Python), decrypt incoming requests and encrypt responses" %}
  4. {% trans "Use the X-Encrypted: 1 header to indicate encrypted payloads" %}

{% trans "Both sides must use the same AES-256-CBC key. Keep the key secret and never commit it to public repositories. Store it in a protected config file outside the web root or in environment variables." %}

{% trans "4. Typical Premium Plugin Flow" %}

  1. {% trans "User installs your premium plugin" %}
  2. {% trans "Plugin shows an activation screen (Patreon/PayPal links, or activation key input)" %}
  3. {% trans "Plugin calls your verification API with user identifier (email, domain, IP) or activation key" %}
  4. {% trans "Your API checks: Plugin Grants, activation key, Patreon, or PayPal — in your preferred order" %}
  5. {% trans "If access is granted, API returns success; plugin unlocks features and optionally stores the key locally" %}
{% trans "Tip" %}: {% trans "Provide multiple verification paths: Patreon for subscribers, PayPal for one-time purchasers, Plugin Grants for beta testers or sponsors, and activation keys for manual grants. Encryption is optional but recommended for paid plugins to deter bypass attempts." %}

{% trans "Core Components" %}

{% trans "1. Authentication & Security" %}

{% trans "Always use the cyberpanel_login_required decorator:" %}

@cyberpanel_login_required
def my_view(request):
    # Your view code
    pass

{% trans "2. URL Routing" %}

from django.urls import path
from . import views

app_name = 'myPlugin'

urlpatterns = [
    path('', views.main_view, name='main'),
    path('item/<int:item_id>/', views.item_detail, name='item_detail'),
]

{% trans "3. Templates" %}

{% trans "Always extend baseTemplate/index.html:" %}

{% verbatim %}
{% extends "baseTemplate/index.html" %}
{% load static %}
{% load i18n %}
{% endverbatim %}

{% trans "Advanced Features" %}

{% trans "Database Models" %}

from django.db import models

class MyModel(models.Model):
    name = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        db_table = 'my_plugin_mymodel'

{% trans "Forms" %}

from django import forms

class MyForm(forms.Form):
    name = forms.CharField(max_length=255, required=True)
    email = forms.EmailField(required=True)

{% trans "API Endpoints" %}

from django.http import JsonResponse

@cyberpanel_login_required
def api_endpoint(request):
    data = {'status': 'success'}
    return JsonResponse(data)

{% trans "Best Practices" %}

  • {% trans "Keep files under 500 lines - split into modules if needed" %}
  • {% trans "Use descriptive names for functions and variables" %}
  • {% trans "Follow PEP 8 Python style guide" %}
  • {% trans "Add comments for complex logic" %}
  • {% trans "Always validate user input" %}
  • {% trans "Use Django ORM instead of raw SQL" %}
  • {% trans "Test your plugin thoroughly before distribution" %}

{% trans "Security Guidelines" %}

{% trans "Security is Critical" %}: {% trans "Always validate input, use parameterized queries, sanitize output, and check user permissions." %}
  • {% trans "Always validate and sanitize user input" %}
  • {% trans "Use Django ORM or parameterized queries" %}
  • {% trans "Escape HTML in templates (Django does this by default)" %}
  • {% trans "Validate file uploads (type, size, content)" %}
  • {% trans "Use HTTPS for sensitive operations" %}
  • {% trans "Implement rate limiting for API endpoints" %}

{% trans "Testing & Debugging" %}

{% trans "Common Issues" %}

  • {% trans "Template Not Found" %}: {% trans "Check template path and name" %}
  • {% trans "URL Not Found" %}: {% trans "Verify URL patterns and app_name" %}
  • {% trans "Import Errors" %}: {% trans "Check Python syntax and import paths" %}
  • {% trans "Static Files Not Loading" %}: {% trans "Run collectstatic command" %}

{% trans "Debugging Commands" %}

# Check Python syntax
python3 -m py_compile views.py

# Check XML validity
xmllint --noout meta.xml

# View logs
tail -f /usr/local/lscp/logs/error.log

{% trans "Packaging & Distribution" %}

{% trans "Create Plugin Package" %}

cd /home/cyberpanel/plugins/myPlugin
zip -r myPlugin-v1.0.0.zip . \
    -x "*.pyc" \
    -x "__pycache__/*" \
    -x "*.log"

{% trans "Troubleshooting" %}

{% trans "Installation Issues" %}

  • {% trans "Check meta.xml format and validity" %}
  • {% trans "Verify plugin directory exists" %}
  • {% trans "Check file permissions" %}
  • {% trans "Review CyberPanel logs" %}

{% trans "Runtime Issues" %}

  • {% trans "Verify URL routing" %}
  • {% trans "Check authentication decorator" %}
  • {% trans "Review template paths" %}
  • {% trans "Check for JavaScript errors" %}

{% trans "Examples & References" %}

{% trans "Reference Plugins" %}

  • examplePlugin: {% trans "Basic plugin structure" %}
    • {% trans "Location" %}: /usr/local/CyberCP/examplePlugin/
    • {% trans "URL" %}: /plugins/examplePlugin/
  • testPlugin: {% trans "Comprehensive example" %}
    • {% trans "Location" %}: /usr/local/CyberCP/testPlugin/
    • {% trans "URL" %}: /plugins/testPlugin/
    • {% trans "Author" %}: usmannasir
  • discordWebhooks: {% trans "Discord webhook integration plugin" %}
    • {% trans "Location" %}: /usr/local/CyberCP/discordWebhooks/
    • {% trans "URL" %}: /plugins/discordWebhooks/
    • {% trans "Author" %}: Master3395

{% trans "Useful Resources" %}

{% trans "Ready to Start?" %} {% trans "Begin with a simple plugin and gradually add more features as you become familiar with the system. Check the examplePlugin and testPlugin directories for complete working examples." %}

{% trans "Author" %}: master3395 | {% trans "Version" %}: 2.1.0 | {% trans "Last Updated" %}: 2026-02-02

{% endblock %}