false, 'schedule' => 'daily', 'schedule_time' => '03:00', 'schedule_weekday' => 1, 'schedule_monthday' => 1, 'schedule_type' => 'full', 'file_scope' => 'content', 'exclude_default' => true, 'exclude_vcs' => true, 'exclude_custom' => '', 'max_file_mb' => 0, 'db_all_tables' => false, 'exclude_tables' => '', 'keep_local' => 5, 'notify_on' => 'failure', 'notify_email' => '', 'time_budget' => 20, 'step_pause' => 0, 'part_size_mb' => 0, ]; } public function all(): array { $stored = get_option(self::OPTION, []); return array_merge($this->defaults(), is_array($stored) ? $stored : []); } /** * @return mixed */ public function get(string $key) { $all = $this->all(); return $all[$key] ?? null; } /** * Merge and sanitize a (partial) set of values. Keys not present in $input keep their value. */ public function save(array $input): array { $current = $this->all(); $out = $current; if (array_key_exists('setup_done', $input)) { $out['setup_done'] = !empty($input['setup_done']); } if (isset($input['schedule'])) { $out['schedule'] = $this->pick((string)$input['schedule'], self::SCHEDULES, 'daily'); } if (isset($input['schedule_time'])) { $time = (string)$input['schedule_time']; $out['schedule_time'] = preg_match('/^([01]\d|2[0-3]):[0-5]\d$/', $time) ? $time : '03:00'; } if (isset($input['schedule_weekday'])) { $out['schedule_weekday'] = $this->clamp((int)$input['schedule_weekday'], 0, 6); } if (isset($input['schedule_monthday'])) { $out['schedule_monthday'] = $this->clamp((int)$input['schedule_monthday'], 1, 28); } if (isset($input['schedule_type'])) { $out['schedule_type'] = $this->pick((string)$input['schedule_type'], self::TYPES, 'full'); } if (isset($input['file_scope'])) { $out['file_scope'] = $this->pick((string)$input['file_scope'], self::SCOPES, 'content'); } foreach (['exclude_default', 'exclude_vcs', 'db_all_tables'] as $flag) { if (array_key_exists($flag, $input)) { $out[$flag] = !empty($input[$flag]); } } if (isset($input['exclude_custom'])) { $out['exclude_custom'] = $this->clean_lines((string)$input['exclude_custom']); } if (isset($input['exclude_tables'])) { $out['exclude_tables'] = $this->clean_lines((string)$input['exclude_tables']); } if (isset($input['max_file_mb'])) { $out['max_file_mb'] = $this->clamp((int)$input['max_file_mb'], 0, 100000); } if (isset($input['keep_local'])) { $out['keep_local'] = $this->clamp((int)$input['keep_local'], 0, 100); } if (isset($input['notify_on'])) { $out['notify_on'] = $this->pick((string)$input['notify_on'], self::NOTIFY, 'failure'); } if (isset($input['notify_email'])) { $emails = []; foreach (preg_split('/[\s,;]+/', (string)$input['notify_email']) as $email) { $email = sanitize_email($email); if ($email !== '' && is_email($email)) { $emails[] = $email; } } $out['notify_email'] = implode(', ', array_unique($emails)); } if (isset($input['time_budget'])) { $out['time_budget'] = $this->clamp((int)$input['time_budget'], 5, 120); } if (isset($input['step_pause'])) { $pause = (int)$input['step_pause']; $out['step_pause'] = in_array($pause, self::STEP_PAUSES, true) ? $pause : 0; } if (isset($input['part_size_mb'])) { $part = (int)$input['part_size_mb']; $out['part_size_mb'] = $part <= 0 ? 0 : $this->clamp($part, 50, 100000); } update_option(self::OPTION, $out, false); return $out; } /** * Recipients for notifications; falls back to the site admin email. */ public function notify_recipients(): array { $raw = trim((string)$this->get('notify_email')); if ($raw === '') { return [(string)get_option('admin_email')]; } return array_filter(array_map('trim', explode(',', $raw))); } public function lines(string $key): array { return array_values(array_filter(array_map('trim', explode("\n", (string)$this->get($key))))); } private function pick(string $value, array $allowed, string $fallback): string { return in_array($value, $allowed, true) ? $value : $fallback; } private function clamp(int $value, int $min, int $max): int { return max($min, min($max, $value)); } private function clean_lines(string $raw): string { $lines = []; foreach (preg_split('/\r\n|\r|\n/', $raw) as $line) { $line = trim(sanitize_text_field($line)); if ($line !== '') { $lines[] = $line; } } return implode("\n", array_unique($lines)); } }