diff --git a/src/Umbraco.Web.BackOffice/Services/IconService.cs b/src/Umbraco.Web.BackOffice/Services/IconService.cs
index 7f060dc756..c8b6eaaf1b 100644
--- a/src/Umbraco.Web.BackOffice/Services/IconService.cs
+++ b/src/Umbraco.Web.BackOffice/Services/IconService.cs
@@ -136,6 +136,9 @@ public class IconService : IIconService
}
}
+ // Get icons from the web root file provider (both physical and virtual)
+ icons.UnionWith(GetIconsFiles(_webHostEnvironment.WebRootFileProvider, Constants.SystemDirectories.AppPlugins));
+
IDirectoryContents? iconFolder =
_webHostEnvironment.WebRootFileProvider.GetDirectoryContents(_globalSettings.IconsPath);
@@ -148,6 +151,63 @@ public class IconService : IIconService
return icons;
}
+
+ ///
+ /// Finds all SVG icon files based on the specified and .
+ /// The method will find both physical and virtual (eg. from a Razor Class Library) icons.
+ ///
+ /// The file provider to be used.
+ /// The sub path to start from - should probably always be .
+ /// A collection of representing the found SVG icon files.
+ private static IEnumerable GetIconsFiles(IFileProvider fileProvider, string path)
+ {
+ // Iterate through all plugin folders, this is necessary because on Linux we'll get casing issues when
+ // we directly try to access {path}/{pluginDirectory.Name}/{Constants.SystemDirectories.PluginIcons}
+ foreach (IFileInfo pluginDirectory in fileProvider.GetDirectoryContents(path))
+ {
+ // Ideally there shouldn't be any files, but we'd better check to be sure
+ if (!pluginDirectory.IsDirectory)
+ {
+ continue;
+ }
+
+ // Iterate through the sub directories of each plugin folder
+ foreach (IFileInfo subDir1 in fileProvider.GetDirectoryContents($"{path}/{pluginDirectory.Name}"))
+ {
+ // Skip files again
+ if (!subDir1.IsDirectory)
+ {
+ continue;
+ }
+
+ // Iterate through second level sub directories
+ foreach (IFileInfo subDir2 in fileProvider.GetDirectoryContents($"{path}/{pluginDirectory.Name}/{subDir1.Name}"))
+ {
+ // Skip files again
+ if (!subDir2.IsDirectory)
+ {
+ continue;
+ }
+
+ // Does the directory match the plugin icons folder? (case insensitive for legacy support)
+ if (!$"/{subDir1.Name}/{subDir2.Name}".InvariantEquals(Constants.SystemDirectories.PluginIcons))
+ {
+ continue;
+ }
+
+ // Iterate though the files of the second level sub directory. This should be where the SVG files are located :D
+ foreach (IFileInfo file in fileProvider.GetDirectoryContents($"{path}/{pluginDirectory.Name}/{subDir1.Name}/{subDir2.Name}"))
+ {
+ if (file.Name.InvariantEndsWith(".svg"))
+ {
+ yield return new FileInfo(file.PhysicalPath);
+ }
+ }
+ }
+ }
+ }
+ }
+
private IReadOnlyDictionary? GetIconDictionary() => _cache.GetCacheItem(
$"{typeof(IconService).FullName}.{nameof(GetIconDictionary)}",
() => GetAllIconsFiles()