get_id(); $name = trim( wp_strip_all_tags( $product->get_name( 'edit' ) ) ); if ( 'auto-draft' === get_post_status( $product_id ) || '' === $name ) { throw new Action_Failed( __( 'Give the product a name and save it, then click the aiModelka button in the product again.', 'aimodelka' ) ); } if ( ! Product_Lock::acquire( $product_id, Meta::PREPARE_LOCK, self::LOCK_TTL ) ) { throw new Action_Failed( __( 'Photos for this product are already being prepared. Wait a moment and try again.', 'aimodelka' ), true ); } try { wc_set_time_limit( self::TIME_LIMIT ); // Состояние автоматической загрузки, которое вёл плагин версии 1.0, больше ничему // не служит — у товара его не остаётся. delete_post_meta( $product_id, Meta::LEGACY_UPLOAD_STATE ); $session = $this->find_or_create_session( $product_id, $name, $kind ); $session_id = (string) $session['id']; try { $pass = $this->client->create_window_pass( $session_id, $product_id, Settings::image_size(), Settings::file_format(), Settings::aspect_ratio(), $admin_origin ); } catch ( Api_Exception $exception ) { throw Action_Failed::from_api( $exception ); } $window_url = is_string( $pass['windowUrl'] ?? null ) ? $pass['windowUrl'] : ''; if ( Origins::of( $window_url ) !== Config::site_origin() ) { // Окно должно открываться на том сайте, от которого страница товара примет // сообщения. Иначе ни фото товара, ни «Сохранить в товар» до магазина не дойдут. Logger::error( 'Window address is not on the aiModelka site', array( 'product_id' => $product_id, 'window_origin' => Origins::of( $window_url ), 'site_origin' => Config::site_origin(), ) ); throw new Action_Failed( sprintf( /* translators: 1: site address the window was given, 2: aiModelka site address this plugin expects. */ __( 'aiModelka gave a window address on %1$s, but this plugin expects %2$s. If you are testing with another aiModelka server, set AIMODELKA_SITE_URL in wp-config.php to that site.', 'aimodelka' ), (string) Origins::of( $window_url ), Config::site_origin() ) ); } Logger::info( 'Window prepared', array( 'product_id' => $product_id, 'photo_session_id' => $session_id, 'kind' => $kind, 'admin_origin' => $admin_origin, ) ); return array( 'windowUrl' => $window_url, 'windowOrigin' => Config::site_origin(), 'photoSessionId' => $session_id, ); } finally { Product_Lock::release( $product_id, Meta::PREPARE_LOCK ); } } /** * Фотосессия товара этого типа: из меты, а если её нет или она удалена — новая. * * @param int $product_id Id товара. * @param string $name Название товара. * @param string $kind Тип фотосессии. * @return array Фотосессия (`PhotoSession`). * @throws Action_Failed Отказ API. */ private function find_or_create_session( int $product_id, string $name, string $kind ): array { $stored_id = (string) get_post_meta( $product_id, Photo_Kinds::session_meta_key( $kind ), true ); if ( '' !== $stored_id ) { try { $session = $this->client->get_photo_session( $stored_id ); Logger::info( 'Photo session found', array( 'product_id' => $product_id, 'photo_session_id' => $stored_id, ) ); return $session; } catch ( Api_Exception $exception ) { if ( Error_Kind::NotFound !== $exception->kind ) { throw Action_Failed::from_api( $exception ); } // Фотосессию удалили в кабинете или её убрала уборка брошенных — мёртвая ссылка // в мете не должна становиться ошибкой: молча заводим новую. Logger::warning( 'Photo session is gone, a new one will be created', array( 'product_id' => $product_id, 'photo_session_id' => $stored_id, ) ); } } try { $session = $this->client->create_photo_session( $product_id, mb_substr( $name, 0, self::MAX_NAME_LENGTH ), home_url(), $kind ); } catch ( Api_Exception $exception ) { throw Action_Failed::from_api( $exception ); } if ( ! is_string( $session['id'] ?? null ) || '' === $session['id'] ) { throw new Action_Failed( __( 'aiModelka could not complete the request. Try again in a few minutes.', 'aimodelka' ), true ); } update_post_meta( $product_id, Photo_Kinds::session_meta_key( $kind ), $session['id'] ); // Записи «фото товара → фото вещи» этого типа относятся к прежней фотосессии: в новой этих // фото нет. Записи других типов не трогаем — их фотосессии живы. delete_post_meta( $product_id, Photo_Kinds::source_photos_meta_key( $kind ) ); Logger::info( 'Photo session created', array( 'product_id' => $product_id, 'photo_session_id' => $session['id'], 'kind' => $kind, ) ); return $session; } }