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:
- Your name and email address
- The content of your support request
- Technical information about your browser and device
- Communication history related to your support request
- GDPR Official Text
- WordPress Privacy Tools
- Data Protection Impact Assessment
- CCPA Compliance Guide
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
Share this article
Still need help?
Our support team is ready to assist you with personalized guidance for your workspace.