get_charset_collate(); // Remediation jobs — the WP-side mirror of /v1 jobs (polling state machine). $jobs = "CREATE TABLE {$wpdb->prefix}a11yfy_jobs ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, attachment_id BIGINT UNSIGNED NOT NULL, job_id VARCHAR(64) NULL, idempotency_key VARCHAR(128) NOT NULL, file_hash CHAR(64) NOT NULL, file_name VARCHAR(255) NOT NULL, status VARCHAR(20) NOT NULL DEFAULT 'queued', credits_used INT UNSIGNED NULL, treatment VARCHAR(20) NULL, compliant TINYINT(1) NULL, before_issues INT UNSIGNED NULL, before_pages INT UNSIGNED NULL, error_code VARCHAR(64) NULL, error_message TEXT NULL, source VARCHAR(10) NOT NULL DEFAULT 'manual', poll_attempts INT UNSIGNED NOT NULL DEFAULT 0, submitted_at DATETIME NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, PRIMARY KEY (id), KEY attachment_id (attachment_id), KEY status (status), KEY job_id (job_id) ) $charset;"; // original attachment → remediated file mapping (report, restore, hash-gate). $map = "CREATE TABLE {$wpdb->prefix}a11yfy_map ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, attachment_id BIGINT UNSIGNED NOT NULL, job_row_id BIGINT UNSIGNED NULL, mode VARCHAR(20) NOT NULL DEFAULT 'inplace', backup_path VARCHAR(1024) NULL, remediated_path VARCHAR(1024) NULL, remediated_backup_path VARCHAR(1024) NULL, remediated_hash CHAR(64) NULL, original_hash CHAR(64) NOT NULL, treatment VARCHAR(20) NULL, compliant TINYINT(1) NULL, before_issues INT UNSIGNED NULL, credits_used INT UNSIGNED NULL, source VARCHAR(10) NOT NULL DEFAULT 'manual', status VARCHAR(20) NOT NULL DEFAULT 'active', opt_out TINYINT(1) NOT NULL DEFAULT 0, remediated_at DATETIME NULL, PRIMARY KEY (id), UNIQUE KEY attachment_id (attachment_id), KEY remediated_path (remediated_path(191)) ) $charset;"; // Visitor on-demand requests: one row per (attachment, email) subscriber. $requests = "CREATE TABLE {$wpdb->prefix}a11yfy_requests ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, attachment_id BIGINT UNSIGNED NOT NULL, email VARCHAR(190) NOT NULL, status VARCHAR(20) NOT NULL DEFAULT 'queued', ip_hash CHAR(64) NULL, locale VARCHAR(16) NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, notified_at DATETIME NULL, PRIMARY KEY (id), UNIQUE KEY attachment_email (attachment_id,email), KEY attachment_status (attachment_id,status), KEY status (status) ) $charset;"; dbDelta( $jobs ); dbDelta( $map ); dbDelta( $requests ); } /** * uploads/a11yfy-backups with directory-listing + direct-access protection. */ public static function ensure_backup_dir() { $dir = self::backup_dir(); if ( ! is_dir( $dir ) ) { wp_mkdir_p( $dir ); } if ( ! file_exists( $dir . '/index.php' ) ) { @file_put_contents( $dir . '/index.php', "