$pictures узлы <Картинка> * @return bool были ли изменения */ public function apply(WC_Product $product, array $pictures): bool { $this->complete = true; $ids = []; foreach ($pictures as $picture) { $file = $this->file(trim((string) $picture)); if ($file === null) { continue; // 1С не прислала файл (выгрузка изменений) — это нормально } $id = $this->attach($file, $product->get_id(), $product->get_name()); if ($id > 0) { $ids[] = $id; } else { $this->complete = false; } } // Файлов нет — текущие картинки не трогаем. if (!$ids) { return false; } $main = array_shift($ids); $gallery = array_values(array_unique(array_diff($ids, [$main]))); if ($product->get_image_id() === $main && $product->get_gallery_image_ids() === $gallery) { return false; } $product->set_image_id($main); $product->set_gallery_image_ids($gallery); return true; } /** * Все присланные картинки удалось загрузить (иначе товар обработается заново в следующий обмен). */ public function complete(): bool { return $this->complete; } private function file(string $relative): ?string { if ($relative === '') { return null; } try { $file = Storage::path($relative); } catch (ExchangeException) { return null; // недопустимый путь из XML — молча пропускаем } return is_file($file) ? $file : null; } private function attach(string $file, int $productId, string $title): int { $md5 = md5_file($file); if ($md5 === false) { return 0; } $existing = Repo::attachmentByMeta(self::HASH_META, $md5); if ($existing > 0) { return $existing; } // Картинка, загруженная прежним плагином, — используем её и запоминаем по своему хешу. $sha1 = sha1_file($file); $legacy = $sha1 !== false ? Repo::attachmentByMeta(self::LEGACY_HASH_META, $sha1) : 0; if ($legacy > 0) { update_post_meta($legacy, self::HASH_META, $md5); return $legacy; } require_once ABSPATH . 'wp-admin/includes/file.php'; require_once ABSPATH . 'wp-admin/includes/media.php'; require_once ABSPATH . 'wp-admin/includes/image.php'; $limitSizes = Settings::str('image_sizes') === 'woo'; if ($limitSizes) { add_filter('intermediate_image_sizes_advanced', [self::class, 'onlyWooSizes'], 99); } // media_handle_sideload перемещает файл и сам проверяет его тип — отдаём копию. $tmp = wp_tempnam(basename($file)); $id = ($tmp && copy($file, $tmp)) ? media_handle_sideload(['name' => basename($file), 'tmp_name' => $tmp], $productId, $title) : new \WP_Error('copy', 'не удалось скопировать файл'); if ($limitSizes) { remove_filter('intermediate_image_sizes_advanced', [self::class, 'onlyWooSizes'], 99); } if (is_wp_error($id)) { if ($tmp) { wp_delete_file($tmp); } Log::warning('Картинка ' . basename($file) . ' не загружена: ' . $id->get_error_message()); return 0; } update_post_meta($id, self::HASH_META, $md5); return (int) $id; } /** * @param array $sizes * @return array */ public static function onlyWooSizes(array $sizes): array { return array_intersect_key($sizes, array_flip(self::WOO_SIZES)); } }