= self::VERSION) { return; } // Переименование данных идёт первым: следующие шаги работают уже с новыми именами. if ($current < 2) { self::renameLegacyData(); } if ($current < 1) { self::migrateAttributesSetting(); } update_option(self::OPTION, self::VERSION, true); delete_option(self::LEGACY_PREFIX . 'db_version'); Settings::flush(); Log::warning(sprintf('Данные плагина обновлены: версия %d → %d', $current, self::VERSION)); } /** * 1.0–1.3 → 1.4: префикс wc1cx_ → gersync_ (настройки, служебные поля товаров, категорий, картинок, заказов). */ private static function renameLegacyData(): void { global $wpdb; foreach (self::LEGACY_OPTIONS as $name) { $old = get_option(self::LEGACY_PREFIX . $name, null); if ($old !== null && get_option('gersync_' . $name, null) === null) { update_option('gersync_' . $name, $old, false); } delete_option(self::LEGACY_PREFIX . $name); } // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- разовая миграция $hpos = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($wpdb->prefix . 'wc_orders_meta'))) !== null; // Имена таблиц — только свойства $wpdb, без переменных; значения — через prepare(). // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- разовая миграция foreach (self::LEGACY_META as $key) { $new = '_gersync_' . $key; $old = '_' . self::LEGACY_PREFIX . $key; $wpdb->query($wpdb->prepare("UPDATE {$wpdb->postmeta} SET meta_key = %s WHERE meta_key = %s", $new, $old)); $wpdb->query($wpdb->prepare("UPDATE {$wpdb->termmeta} SET meta_key = %s WHERE meta_key = %s", $new, $old)); if ($hpos) { $wpdb->query($wpdb->prepare("UPDATE {$wpdb->prefix}wc_orders_meta SET meta_key = %s WHERE meta_key = %s", $new, $old)); } } // phpcs:enable wp_cache_flush(); // Старая временная папка обмена (только временные файлы). self::removeLegacyTempDir(); // Фоновые задачи старых версий. if (function_exists('as_unschedule_all_actions')) { as_unschedule_all_actions(self::LEGACY_PREFIX . 'process_missing'); as_unschedule_all_actions(self::LEGACY_PREFIX . 'media_cleanup'); } } private static function removeLegacyTempDir(): void { $key = (string) get_option('gersync_dir_key', ''); if (!preg_match('/^[a-f0-9]{24}$/', $key)) { return; } $dir = trailingslashit(wp_upload_dir(null, false)['basedir']) . 'wc1c-exchange-' . $key; if (!is_dir($dir)) { return; } $items = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::CHILD_FIRST ); foreach ($items as $item) { if ($item->isDir() && !$item->isLink()) { rmdir($item->getPathname()); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir -- пустая папка (обход снизу вверх) } else { wp_delete_file($item->getPathname()); } } rmdir($dir); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir -- своя старая временная папка } /** * 1.0–1.2 → 1.3: галочка update_attributes заменена режимом attributes_mode. */ private static function migrateAttributesSetting(): void { $stored = get_option(Settings::OPTION, null); if (is_array($stored) && !isset($stored['attributes_mode']) && array_key_exists('update_attributes', $stored)) { $stored['attributes_mode'] = $stored['update_attributes'] ? 'sync' : 'none'; unset($stored['update_attributes']); update_option(Settings::OPTION, $stored); } } public static function backupSettings(): void { $settings = get_option(Settings::OPTION); if (is_array($settings) && $settings) { update_option(self::BACKUP, $settings, false); } } /** * Настройки пропали — возвращаем из резервной копии. */ public static function restoreSettings(): void { if (get_option(Settings::OPTION, null) !== null) { if (get_option(self::BACKUP, null) === null) { self::backupSettings(); } return; } $backup = get_option(self::BACKUP); if (is_array($backup) && $backup) { update_option(Settings::OPTION, $backup); Settings::flush(); Log::warning('Настройки обмена были удалены и восстановлены из резервной копии.'); } } }