true, 'login' => '', 'password_hash' => '', 'allowed_ips' => '', 'time_limit' => 20, 'file_limit_mb' => 32, 'use_zip' => true, 'response_charset' => 'cp1251', 'skip_unchanged' => true, 'image_sizes' => 'all', 'new_status' => 'publish', 'match_by_sku' => false, 'update_name' => true, 'update_description' => true, 'update_categories' => true, 'update_images' => true, 'update_sku' => true, 'update_weight' => true, 'update_price' => true, 'update_stock' => true, 'attributes_mode' => 'sync', 'import_attributes' => true, 'deleted_action' => 'draft', 'missing_action' => 'none', 'price_type' => '', 'sale_price_type' => '', 'manage_stock' => true, 'orders_enabled' => true, 'order_statuses' => ['processing', 'on-hold', 'completed', 'cancelled'], 'order_import_statuses' => false, 'order_currency' => '', 'debug' => false, ]; private static ?array $cache = null; public static function all(): array { if (self::$cache === null) { $stored = get_option(self::OPTION, []); $stored = is_array($stored) ? $stored : []; // Версия 1.1 хранила галочку update_attributes вместо режима. if (!isset($stored['attributes_mode']) && array_key_exists('update_attributes', $stored)) { $stored['attributes_mode'] = $stored['update_attributes'] ? 'sync' : 'none'; } self::$cache = array_merge(self::DEFAULTS, $stored); } return self::$cache; } public static function get(string $key): mixed { return self::all()[$key] ?? null; } public static function bool(string $key): bool { return (bool) self::get($key); } public static function int(string $key): int { return (int) self::get($key); } public static function str(string $key): string { return trim((string) self::get($key)); } public static function flush(): void { self::$cache = null; } /** * Очистка данных из формы настроек. */ public static function sanitize(mixed $input): array { $input = is_array($input) ? $input : []; $old = self::all(); $out = []; foreach (['enabled', 'use_zip', 'match_by_sku', 'update_name', 'update_description', 'update_categories', 'update_images', 'update_sku', 'update_weight', 'update_price', 'update_stock', 'import_attributes', 'manage_stock', 'orders_enabled', 'order_import_statuses', 'debug', 'skip_unchanged'] as $key) { $out[$key] = !empty($input[$key]); } $out['login'] = sanitize_user((string) ($input['login'] ?? ''), true); // Пароль хранится только в виде хеша. Пустое поле = оставить прежний. $password = (string) ($input['password'] ?? ''); // (WP может вызвать sanitize дважды при первом сохранении — тогда хеш уже лежит в $input.) $out['password_hash'] = $password !== '' ? wp_hash_password($password) : (string) ($input['password_hash'] ?? $old['password_hash']); $ips = []; foreach (preg_split('/[\s,;]+/', (string) ($input['allowed_ips'] ?? ''), -1, PREG_SPLIT_NO_EMPTY) as $ip) { if (filter_var($ip, FILTER_VALIDATE_IP)) { $ips[] = $ip; } } $out['allowed_ips'] = implode("\n", array_unique($ips)); $out['time_limit'] = max(5, min(120, (int) ($input['time_limit'] ?? 20))); $out['file_limit_mb'] = max(1, min(512, (int) ($input['file_limit_mb'] ?? 32))); $out['new_status'] = self::choice($input, 'new_status', ['publish', 'draft', 'pending', 'private'], 'publish'); $out['deleted_action'] = self::choice($input, 'deleted_action', ['draft', 'trash', 'none'], 'draft'); $out['missing_action'] = self::choice($input, 'missing_action', self::MISSING_ACTIONS, 'none'); $out['attributes_mode'] = self::choice($input, 'attributes_mode', self::ATTRIBUTE_MODES, 'sync'); $out['response_charset'] = self::choice($input, 'response_charset', ['cp1251', 'utf-8'], 'cp1251'); $out['image_sizes'] = self::choice($input, 'image_sizes', ['all', 'woo'], 'all'); $out['price_type'] = sanitize_text_field((string) ($input['price_type'] ?? '')); $out['sale_price_type'] = sanitize_text_field((string) ($input['sale_price_type'] ?? '')); $out['order_currency'] = sanitize_text_field((string) ($input['order_currency'] ?? '')); $allowed = array_map(static fn(string $s): string => substr($s, 3), array_keys(wc_get_order_statuses())); $statuses = array_map('sanitize_key', (array) ($input['order_statuses'] ?? [])); $out['order_statuses'] = array_values(array_intersect($statuses, $allowed)); self::$cache = null; return $out; } /** * @param list $allowed */ private static function choice(array $input, string $key, array $allowed, string $default): string { $value = (string) ($input[$key] ?? ''); return in_array($value, $allowed, true) ? $value : $default; } }