Image Manager could not finish automatic folders for an upload. The upload is saved. Open and save its Media details to retry; existing folders and image files remain intact.

'; } } /** * Give one image its automatic folder when no person chose one. * * @param int $id The attachment. * @throws \RuntimeException Only inside this function, where it is caught; callers get no exception. */ public static function observe( int $id ): void { if ( self::$working || ! taxonomy_exists( Library::FOLDER ) ) { return; } self::$working = true; try { $post = get_post( $id ); if ( ! $post || $post->post_type !== 'attachment' || ! str_starts_with( (string) $post->post_mime_type, 'image/' ) ) { return; } $current = Library::term_ids( $id, Library::FOLDER ); $owned = array_map( 'intval', (array) get_post_meta( $id, self::OWNED, true ) ); // Explicit native or reviewed folder choices have priority over the fallback category. if ( array_diff( $current, $owned ) ) { return; } $parent = $post->post_parent ? get_post( $post->post_parent ) : null; $kind = $parent ? $parent->post_type : ''; $label = in_array( $kind, array( 'product', 'product_variation' ), true ) ? 'Products' : ( $kind === 'page' ? 'Pages' : ( $kind === 'post' ? 'Posts' : ( in_array( $kind, array( 'course', 'sfwd-courses', 'sfwd-lessons' ), true ) ? 'Courses' : 'Uploads' ) ) ); $paths = get_post_meta( $id, '_afsd_im_organization_paths', true ); $result = self::assign( $id, is_array( $paths ) && $paths ? $paths : array( array( 'Website images', $label ) ), false ); if ( is_wp_error( $result ) ) { throw new \RuntimeException( 'organization_failed' ); } delete_post_meta( $id, '_afsd_im_organization_retry' ); if ( (int) get_option( 'afsd_im_organization_notice' ) === $id ) { delete_option( 'afsd_im_organization_notice' ); } } catch ( \Throwable $e ) { $attempt = (int) get_post_meta( $id, '_afsd_im_organization_retry', true ); update_option( 'afsd_im_organization_notice', $id, false ); if ( $attempt < 3 && ! wp_next_scheduled( 'afsd_im_organize_attachment', array( $id ) ) ) { update_post_meta( $id, '_afsd_im_organization_retry', $attempt + 1 ); wp_schedule_single_event( time() + 60 * ( 2 ** $attempt ), 'afsd_im_organize_attachment', array( $id ) ); } } finally { self::$working = false; } } /** * Owning importer API. No model-supplied paths, uploads, metadata changes or public delivery. * * @param int $id The attachment. * @param array $paths One to eight folder paths, each one to four folder names from the top. * @param bool $authorize Whether to check the current user may upload files and edit the attachment (false for * importers running on their own). * @return array|\WP_Error The attachment, its folder IDs and paths, or the error. */ public static function assign( int $id, array $paths, bool $authorize = true ) { if ( $authorize && ( ! current_user_can( 'upload_files' ) || ! current_user_can( 'edit_post', $id ) ) ) { return new \WP_Error( 'afsd_im_organization_forbidden', __( 'You cannot organize this attachment.', 'affstackdev-image-manager' ) ); } $post = get_post( $id ); if ( ! $post || $post->post_type !== 'attachment' || ! taxonomy_exists( Library::FOLDER ) || ! $paths || count( $paths ) > 8 ) { return new \WP_Error( 'afsd_im_organization_input', __( 'Choose an existing attachment and one to eight folder paths.', 'affstackdev-image-manager' ) ); } foreach ( $paths as $path ) { if ( ! is_array( $path ) || ! $path || count( $path ) > 4 ) { return new \WP_Error( 'afsd_im_organization_input', __( 'Invalid folder path.', 'affstackdev-image-manager' ) ); } foreach ( $path as $label ) { if ( ! is_string( $label ) || trim( $label ) === '' || strlen( $label ) > 120 || sanitize_text_field( $label ) !== $label ) { return new \WP_Error( 'afsd_im_organization_input', __( 'Invalid folder label.', 'affstackdev-image-manager' ) ); } } } $locked = Reviewed_Store::enter(); try { Reviewed_Store::guard(); $ids = array(); foreach ( $paths as $path ) { $parent = 0; foreach ( $path as $label ) { $slug = 'auto-' . substr( hash( 'sha256', $parent . '|' . $label ), 0, 24 ); $term = get_term_by( 'slug', $slug, Library::FOLDER ); if ( ! $term ) { Reviewed_Store::guard(); $made = wp_insert_term( $label, Library::FOLDER, array( 'slug' => $slug, 'parent' => $parent, ) ); if ( is_wp_error( $made ) ) { $term = get_term_by( 'slug', $slug, Library::FOLDER ); if ( ! $term ) { return $made; }$parent = (int) $term->term_id; } else { $parent = (int) $made['term_id']; } } else { $parent = (int) $term->term_id; } } $ids[] = $parent; } $ids = array_values( array_unique( $ids ) ); $current = Library::term_ids( $id, Library::FOLDER ); $owned = array_map( 'intval', (array) get_post_meta( $id, self::OWNED, true ) ); $manual = array_values( array_diff( $current, $owned ) ); Reviewed_Store::guard(); $set = wp_set_object_terms( $id, array_values( array_unique( array_merge( $manual, $ids ) ) ), Library::FOLDER, false ); if ( is_wp_error( $set ) ) { return $set; } update_post_meta( $id, self::OWNED, $ids ); if ( $authorize ) { update_post_meta( $id, '_afsd_im_organization_paths', $paths ); } Library::clear_terms(); return array( 'attachment_id' => $id, 'folders' => $ids, 'paths' => $paths, ); } finally { Reviewed_Store::leave( $locked ); } } }