ShahiAssist

Compliance and Data Management

Ensuring compliance with data protection regulations and implementing proper data management practices is crucial for ShahiAssist. This guide covers GDPR compliance, data retention policies, user rights, and secure data handling.

GDPR Compliance

Data Controller Responsibilities

`php
class ShahiAssistGDPRController {
public function __construct() {
// Register data processing
addaction(‘admininit’, [$this, ‘registerdataprocessing’]);

// Handle data subject requests
addaction(‘wpajaxshahiassistgdprrequest’, [$this, ‘handlegdprrequest’]);

// Data retention cleanup
addaction(‘shahiassistdailycleanup’, [$this, ‘cleanupexpireddata’]);
}

public function registerdataprocessing() {
// Register with WordPress privacy tools
addfilter(‘wpprivacypersonaldataexporters’, [$this, ‘registerexporter’], 10, 1);
addfilter(‘wpprivacypersonaldataerasers’, [$this, ‘registereraser’], 10, 1);
}

public function register_exporter($exporters) {
$exporters[‘shahi-assist’] = [
‘exporterfriendlyname’ => __(‘ShahiAssist Data’, ‘shahi-assist’),
‘callback’ => [$this, ‘exportuserdata’],
];
return $exporters;
}

public function register_eraser($erasers) {
$erasers[‘shahi-assist’] = [
‘eraserfriendlyname’ => __(‘ShahiAssist Data’, ‘shahi-assist’),
‘callback’ => [$this, ‘eraseuserdata’],
];
return $erasers;
}
}
`

Data Export Functionality

`php
// Export user data for GDPR
function exportuserdata($email_address, $page = 1) {
$user = getuserby(’email’, $email_address);
if (!$user) {
return [
‘data’ => [],
‘done’ => true,
];
}

$export_data = [];

// Export tickets
$tickets = get_posts([
‘post_type’ => ‘ticket’,
‘author’ => $user->ID,
‘postsperpage’ => 100,
‘paged’ => $page,
]);

foreach ($tickets as $ticket) {
$ticket_data = [
‘groupid’ => ‘shahiassist_tickets’,
‘grouplabel’ => _(‘Support Tickets’, ‘shahi-assist’),
‘item_id’ => ‘ticket-‘ . $ticket->ID,
‘data’ => [
[
‘name’ => __(‘Ticket Title’, ‘shahi-assist’),
‘value’ => $ticket->post_title,
],
[
‘name’ => __(‘Ticket Content’, ‘shahi-assist’),
‘value’ => $ticket->post_content,
],
[
‘name’ => __(‘Status’, ‘shahi-assist’),
‘value’ => getpostmeta($ticket->ID, ‘ticketstatus’, true),
],
[
‘name’ => __(‘Priority’, ‘shahi-assist’),
‘value’ => getpostmeta($ticket->ID, ‘ticketpriority’, true),
],
[
‘name’ => __(‘Created Date’, ‘shahi-assist’),
‘value’ => $ticket->post_date,
],
],
];

$exportdata[] = $ticketdata;
}

// Export user preferences
$preferences = getusermeta($user->ID, ‘shahiassistpreferences’, true);
if ($preferences) {
$export_data[] = [
‘groupid’ => ‘shahiassist_preferences’,
‘grouplabel’ => _(‘User Preferences’, ‘shahi-assist’),
‘item_id’ => ‘preferences-‘ . $user->ID,
‘data’ => [
[
‘name’ => __(‘Preferences’, ‘shahi-assist’),
‘value’ => json_encode($preferences),
],
],
];
}

return [
‘data’ => $export_data,
‘done’ => count($tickets) < 100, ]; } `

Data Erasure Functionality

`php
// Erase user data for GDPR
function eraseuserdata($email_address, $page = 1) {
$user = getuserby(’email’, $email_address);
if (!$user) {
return [
‘items_removed’ => 0,
‘items_retained’ => 0,
‘messages’ => [],
‘done’ => true,
];
}

$items_removed = 0;
$items_retained = 0;
$messages = [];

// Anonymize tickets (don’t delete, for legal/compliance reasons)
$tickets = get_posts([
‘post_type’ => ‘ticket’,
‘author’ => $user->ID,
‘postsperpage’ => 100,
‘paged’ => $page,
‘fields’ => ‘ids’,
]);

foreach ($tickets as $ticket_id) {
// Anonymize ticket content
wpupdatepost([
‘ID’ => $ticket_id,
‘posttitle’ => _(‘[Anonymized Ticket]’, ‘shahi-assist’),
‘postcontent’ => _(‘Content removed at user request’, ‘shahi-assist’),
‘post_author’ => 0, // Anonymous user
]);

// Remove personal meta data
deletepostmeta($ticketid, ‘customer_email’);
deletepostmeta($ticketid, ‘customer_phone’);
deletepostmeta($ticketid, ‘customer_name’);

$items_removed++;
}

// Remove user preferences
deleteusermeta($user->ID, ‘shahiassistpreferences’);
$items_removed++;

// Remove activity logs
global $wpdb;
$wpdb->delete(
$wpdb->prefix . ‘shahiassistactivity_log’,
[‘user_id’ => $user->ID]
);

return [
‘itemsremoved’ => $itemsremoved,
‘itemsretained’ => $itemsretained,
‘messages’ => $messages,
‘done’ => count($tickets) < 100, ]; } `

Privacy Policy Content

`php
// Add privacy policy content
function addprivacypolicy_content() {
if (!functionexists(‘wpaddprivacypolicy_content’)) {
return;
}

$content = sprintf(
__(

ShahiAssist Support System

When you submit a support ticket through ShahiAssist, we collect:

      1. Your name and email address
      2. The content of your support request
      3. Technical information about your browser and device
      4. Communication history related to your support request

    This information is used solely for providing customer support and improving our services.

    Data Retention: Support tickets and related data are retained for %d years after the ticket is closed, unless legally required otherwise.

    Your Rights: You have the right to access, rectify, erase, or restrict processing of your personal data. Contact us to exercise these rights.

    Data Controller: %s

    ‘,
    ‘shahi-assist’
    ),
    getoption(‘shahiassistdataretention_years’, 3),
    get_bloginfo(‘name’)
    );

    wpaddprivacypolicycontent(‘ShahiAssist’, wpksespost($content));
    }
    addaction(‘admininit’, ‘addprivacypolicy_content’);
    `

    Data Retention Policies

    Automated Data Cleanup

    `php
    class ShahiAssistDataRetention {
    private $retention_periods = [
    ‘tickets’ => 3 * YEARINSECONDS, // 3 years
    ‘logs’ => 1 * YEARINSECONDS, // 1 year
    ‘tempfiles’ => 30 * DAYIN_SECONDS, // 30 days
    ‘cache’ => 7 * DAYINSECONDS, // 7 days
    ];

    public function __construct() {
    addaction(‘shahiassistdailycleanup’, [$this, ‘cleanupexpireddata’]);
    addaction(‘shahiassistmonthlycleanup’, [$this, ‘cleanupolddata’]);
    }

    public function cleanupexpireddata() {
    $this->cleanupoldtickets();
    $this->cleanupoldlogs();
    $this->cleanuptempfiles();
    $this->cleanup_cache();
    }

    private function cleanupoldtickets() {
    $cutoffdate = date(‘Y-m-d H:i:s’, time() – $this->retentionperiods[‘tickets’]);

    $oldtickets = getposts([
    ‘post_type’ => ‘ticket’,
    ‘date_query’ => [
    [
    ‘before’ => $cutoff_date,
    ‘column’ => ‘post_modified’,
    ]
    ],
    ‘meta_query’ => [
    [
    ‘key’ => ‘ticketstatus’,
    ‘value’ => ‘closed’,
    ]
    ],
    ‘fields’ => ‘ids’,
    ‘postsperpage’ => -1,
    ]);

    foreach ($oldtickets as $ticketid) {
    // Move to archive instead of deleting
    $this->archiveticket($ticketid);
    }

    ShahiAssist_Debug::info(‘Cleaned up old tickets’, [
    ‘count’ => count($old_tickets),
    ‘cutoffdate’ => $cutoffdate
    ]);
    }

    private function archiveticket($ticketid) {
    global $wpdb;

    // Create archive table if it doesn’t exist
    $archivetable = $wpdb->prefix . ‘shahiassistticketarchive’;

    $wpdb->query(“
    CREATE TABLE IF NOT EXISTS $archive_table (
    id int(11) NOT NULL AUTO_INCREMENT,
    ticket_id bigint(20) NOT NULL,
    data longtext NOT NULL,
    archivedat datetime DEFAULT CURRENTTIMESTAMP,
    PRIMARY KEY (id),
    KEY ticketid (ticketid)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    “);

    // Archive ticket data
    $ticket_data = [
    ‘post’ => getpost($ticketid, ARRAY_A),
    ‘meta’ => getpostmeta($ticket_id),
    ‘comments’ => getcomments([‘postid’ => $ticket_id]),
    ];

    $wpdb->insert($archive_table, [
    ‘ticketid’ => $ticketid,
    ‘data’ => jsonencode($ticketdata),
    ]);

    // Delete original ticket
    wpdeletepost($ticket_id, true);
    }

    private function cleanupoldlogs() {
    global $wpdb;
    $cutoffdate = date(‘Y-m-d H:i:s’, time() – $this->retentionperiods[‘logs’]);

    $wpdb->query($wpdb->prepare(“
    DELETE FROM {$wpdb->prefix}shahiassistlogs
    WHERE created_at < %s ", $cutoff_date)); } private function cleanuptempfiles() {
    $tempdir = wpupload_dir()[‘basedir’] . ‘/shahi-assist/temp/’;
    if (!isdir($tempdir)) {
    return;
    }

    $files = glob($temp_dir . ‘*’);
    $cutofftime = time() – $this->retentionperiods[‘temp_files’];

    foreach ($files as $file) {
    if (filemtime($file) < $cutoff_time) { unlink($file); } } } private function cleanup_cache() { global $wpdb; $cutofftime = time() – $this->retentionperiods[‘cache’];

    // Clear old transients
    $wpdb->query($wpdb->prepare(“
    DELETE FROM {$wpdb->options}
    WHERE optionname LIKE ‘transientshahiassist_%’
    AND option_value < %s ", $cutoff_time)); } } `

    Data Retention Settings

    `php
    // Admin settings for data retention
    function adddataretention_settings($settings) {
    $settings[‘data_retention’] = [
    ‘title’ => __(‘Data Retention’, ‘shahi-assist’),
    ‘fields’ => [
    ‘retention_tickets’ => [
    ‘label’ => __(‘Ticket Retention (years)’, ‘shahi-assist’),
    ‘type’ => ‘number’,
    ‘default’ => 3,
    ‘min’ => 1,
    ‘max’ => 10,
    ],
    ‘retention_logs’ => [
    ‘label’ => __(‘Log Retention (months)’, ‘shahi-assist’),
    ‘type’ => ‘number’,
    ‘default’ => 12,
    ‘min’ => 1,
    ‘max’ => 24,
    ],
    ‘auto_cleanup’ => [
    ‘label’ => __(‘Enable Automatic Cleanup’, ‘shahi-assist’),
    ‘type’ => ‘checkbox’,
    ‘default’ => true,
    ],
    ],
    ];

    return $settings;
    }
    addfilter(‘shahiassistsettingssections’, ‘adddataretention_settings’);
    `

    Data Encryption

    Database Encryption

    `php
    class ShahiAssistDataEncryption {
    private $key;

    public function __construct() {
    $this->key = getoption(‘shahiassistencryptionkey’);
    if (!$this->key) {
    $this->key = $this->generate_key();
    updateoption(‘shahiassistencryptionkey’, $this->key);
    }
    }

    private function generate_key() {
    return bin2hex(random_bytes(32));
    }

    public function encrypt($data) {
    $iv = random_bytes(16);
    $encrypted = openssl_encrypt(
    $data,
    ‘aes-256-cbc’,
    $this->key,
    0,
    $iv
    );

    return base64_encode($iv . $encrypted);
    }

    public function decrypt($encrypted_data) {
    $data = base64decode($encrypteddata);
    $iv = substr($data, 0, 16);
    $encrypted = substr($data, 16);

    return openssl_decrypt(
    $encrypted,
    ‘aes-256-cbc’,
    $this->key,
    0,
    $iv
    );
    }
    }

    // Encrypt sensitive ticket data
    function saveencryptedticketmeta($ticketid, $meta_key, $value) {
    $encryption = new ShahiAssistDataEncryption();
    $encrypted_value = $encryption->encrypt($value);

    updatepostmeta($ticketid, $metakey, $encrypted_value);
    updatepostmeta($ticketid, $metakey . ‘_encrypted’, true);
    }

    // Decrypt when retrieving
    function getdecryptedticketmeta($ticketid, $meta_key) {
    $value = getpostmeta($ticketid, $metakey, true);
    $isencrypted = getpostmeta($ticketid, $metakey . ‘encrypted’, true);

    if ($is_encrypted && $value) {
    $encryption = new ShahiAssistDataEncryption();
    return $encryption->decrypt($value);
    }

    return $value;
    }
    `

    Audit Logging

    Compliance Audit Trail

    `php
    class ShahiAssistAuditLog {
    public static function logdataaccess($action, $datatype, $dataid, $user_id = null) {
    $userid = $userid ?? getcurrentuser_id();

    global $wpdb;
    $wpdb->insert(
    $wpdb->prefix . ‘shahiassistaudit_log’,
    [
    ‘timestamp’ => current_time(‘mysql’),
    ‘userid’ => $userid,
    ‘action’ => $action,
    ‘datatype’ => $datatype,
    ‘dataid’ => $dataid,
    ‘ipaddress’ => $SERVER[‘REMOTE_ADDR’] ?? ”,
    ‘useragent’ => $SERVER[‘HTTPUSERAGENT’] ?? ”,
    ]
    );
    }

    public static function loggdprrequest($requesttype, $useremail) {
    self::logdataaccess(
    ‘gdpr‘ . $requesttype,
    ‘user_data’,
    $user_email,
    0 // System action
    );
    }

    public static function getaudittrail($datatype = null, $dataid = null, $limit = 100) {
    global $wpdb;

    $where = [];
    $params = [];

    if ($data_type) {
    $where[] = ‘data_type = %s’;
    $params[] = $data_type;
    }

    if ($data_id) {
    $where[] = ‘data_id = %s’;
    $params[] = $data_id;
    }

    $where_clause = $where ? ‘WHERE ‘ . implode(‘ AND ‘, $where) : ”;

    return $wpdb->get_results($wpdb->prepare(“
    SELECT * FROM {$wpdb->prefix}shahiassistaudit_log
    $where_clause
    ORDER BY timestamp DESC
    LIMIT %d
    “, array_merge($params, [$limit])));
    }
    }

    // Log all data access
    addaction(‘shahiassistbeforeticketaccess’, function($ticketid) {
    ShahiAssistAuditLog::logdataaccess(‘view’, ‘ticket’, $ticket_id);
    });

    addaction(‘shahiassistbeforeticketupdate’, function($ticketid) {
    ShahiAssistAuditLog::logdataaccess(‘update’, ‘ticket’, $ticket_id);
    });
    `

    Data Backup and Recovery

    Automated Backups

    `php
    class ShahiAssistBackupManager {
    private $backup_dir;

    public function __construct() {
    $this->backupdir = wpupload_dir()[‘basedir’] . ‘/shahi-assist/backups/’;
    wpmkdirp($this->backup_dir);

    addaction(‘shahiassistweeklybackup’, [$this, ‘create_backup’]);
    }

    public function create_backup() {
    $backupfile = $this->backupdir . ‘backup-‘ . date(‘Y-m-d-H-i-s’) . ‘.sql.gz’;

    // Use mysqldump if available
    if ($this->has_mysqldump()) {
    $this->createmysqlbackup($backup_file);
    } else {
    $this->createphpbackup($backup_file);
    }

    // Clean old backups (keep last 10)
    $this->cleanupoldbackups();

    ShahiAssistDebug::info(‘Backup created’, [‘file’ => basename($backupfile)]);
    }

    private function has_mysqldump() {
    exec(‘which mysqldump’, $output);
    return !empty($output);
    }

    private function createmysqlbackup($file) {
    $command = sprintf(
    ‘mysqldump –host=%s –user=%s –password=%s %s | gzip > %s’,
    DB_HOST,
    DB_USER,
    DB_PASSWORD,
    DB_NAME,
    escapeshellarg($file)
    );

    exec($command, $output, $return_var);

    if ($return_var !== 0) {
    throw new Exception(‘mysqldump failed’);
    }
    }

    private function createphpbackup($file) {
    global $wpdb;

    $tables = $wpdb->getcol(“SHOW TABLES LIKE ‘{$wpdb->prefix}shahiassist_%'”);
    $sql = ”;

    foreach ($tables as $table) {
    $createtable = $wpdb->getrow(“SHOW CREATE TABLE $table”, ARRAY_N);
    $sql .= $create_table[1] . “;\n\n”;

    $rows = $wpdb->getresults(“SELECT * FROM $table”, ARRAYN);
    foreach ($rows as $row) {
    $sql .= “INSERT INTO $table VALUES (“;
    $sql .= “‘” . implode(“‘,'”, array_map([$wpdb, ‘escape’], $row)) . “‘”;
    $sql .= “);\n”;
    }
    $sql .= “\n”;
    }

    fileputcontents(‘php://temp’, $sql, FILEAPPEND | LOCKEX);
    // Compress and save
    $gz = gzopen($file, ‘w9’);
    gzwrite($gz, $sql);
    gzclose($gz);
    }

    private function cleanupoldbackups() {
    $files = glob($this->backup_dir . ‘backup-*.sql.gz’);
    usort($files, function($a, $b) {
    return filemtime($b) – filemtime($a);
    });

    // Remove all but the last 10
    $filestodelete = array_slice($files, 10);
    foreach ($filestodelete as $file) {
    unlink($file);
    }
    }
    }
    `

    Compliance Reporting

    `php
    // Generate compliance reports
    function generatecompliancereport() {
    $report = [
    ‘generatedat’ => currenttime(‘mysql’),
    ‘data_retention’ => [
    ‘ticketsretained’ => wpcount_posts(‘ticket’)->publish,
    ‘oldticketsarchived’ => self::countarchivedtickets(),
    ‘logscleaned’ => self::countcleaned_logs(),
    ],
    ‘gdpr_requests’ => [
    ‘exportrequests’ => self::countgdpr_requests(‘export’),
    ‘eraserequests’ => self::countgdpr_requests(‘erase’),
    ],
    ‘securityincidents’ => self::getsecurity_incidents(),
    ‘data_encryption’ => [
    ‘encryptedfields’ => [‘customeremail’, ‘customerphone’, ‘personaldata’],
    ‘encryption_method’ => ‘AES-256-CBC’,
    ],
    ];

    // Save report
    updateoption(‘shahiassistlastcompliance_report’, $report);

    return $report;
    }

    function countgdprrequests($type) {
    global $wpdb;
    return $wpdb->get_var($wpdb->prepare(“
    SELECT COUNT(*) FROM {$wpdb->prefix}shahiassistaudit_log
    WHERE action = %s
    “, ‘gdpr_’ . $type));
    }

    function countarchivedtickets() {
    global $wpdb;
    return $wpdb->get_var(“
    SELECT COUNT(*) FROM {$wpdb->prefix}shahiassistticket_archive
    “);
    }
    `

    Resources

  • GDPR Official Text
  • WordPress Privacy Tools
  • Data Protection Impact Assessment
  • CCPA Compliance Guide

Share this article

Was this article helpful?

Help us improve our documentation

Still need help?

Our support team is ready to assist you with personalized guidance for your workspace.

Submit a support ticket