<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet href="/firehose/news?altTemplate=FirehoseXslt" type="text/xsl" media="screen" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:umb="http://www.umbraco.com" umb:media-type="news">
    <channel>
        <atom:link href="https://umb.fyi/firehose/news" rel="self" type="application/rss+xml" />
        <title>UMB.FYI Firehose - News</title>
        <link>https://umb.fyi/firehose/news</link>
        <description>Aggregated news from the Umbraco community</description>
        <pubDate>Tue, 24 Oct 2023 14:27:33 Z</pubDate>
        <lastBuildDate>Tue, 07 Jul 2026 19:19:55 Z</lastBuildDate>
        <language>en</language>
        <generator>Umbraco</generator>
                <item>
                    <guid>https://skrift.io/issues/#129</guid>
                    <title>Skrift Issue #129</title>
                    <link>https://skrift.io/issues/#129</link>
                    <description><![CDATA[Featuring guest posts by Bogdan Kosarevskyi on &quot;The tip of the observability iceberg: depth is not measured in meters, but in levels of observation&quot; and Hubert Galuszka on &quot;Virtual Members: Passwordless Umbraco Auth Without the Identity-Provider Bill&quot;]]></description>
                    <pubDate>Tue, 07 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                        <category>skrift</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/thtaai</guid>
                    <title>ThtaAi</title>
                    <link>https://marketplace.umbraco.com/package/thtaai</link>
                    <description><![CDATA[AI-powered content generation for the Umbraco backoffice. Uses a local LLM (or other LLM API) to generate page content, block content, and full pages from natural-language prompts, with editorial review before anything publishes.]]></description>
                    <pubDate>Tue, 07 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/security-advisory-july-7-2026-security-patches-are-now-available/</guid>
                    <title>Security Advisory, July 7, 2026: Security Patches are now available</title>
                    <link>https://umbraco.com/blog/security-advisory-july-7-2026-security-patches-are-now-available/</link>
                    <description><![CDATA[Summary: A vulnerability classified as high has been found and fixed in Umbraco 13, 17, and 18.]]></description>
                    <pubDate>Tue, 07 Jul 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://github.com/abjerner/Limbo.Umbraco.TextBox/releases/tag/v17.0.0-alpha001</guid>
                    <title>Limbo.Umbraco.TextBox 17.0.0-alpha001</title>
                    <link>https://github.com/abjerner/Limbo.Umbraco.TextBox/releases/tag/v17.0.0-alpha001</link>
                    <description><![CDATA[Limbo Textbox&#xA0;(or&#xA0;Limbo.Umbraco.TextBox) is a package that adds new textbox and textarea property editors for Umbraco 10&#x2B;. While having similar functionality to the build in property editors, this package adds a few extra features.]]></description>
                    <pubDate>Mon, 06 Jul 2026 11:46:55 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://owainjones.dev/blog/new-giscus-powered-comments-and-h5yr-widget/</guid>
                    <title>New Giscus powered comments and H5YR widget!</title>
                    <link>https://owainjones.dev/blog/new-giscus-powered-comments-and-h5yr-widget/</link>
                    <description><![CDATA[I&amp;#x27;ve added a giscus powered comments, and the awesome H5YR widget, to my blog posts!]]></description>
                    <pubDate>Sat, 04 Jul 2026 19:18:36 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://shazwazza.com/post/letting-ai-agents-loose-on-examine/</guid>
                    <title>Letting AI agents loose on Examine</title>
                    <link>https://shazwazza.com/post/letting-ai-agents-loose-on-examine/</link>
                    <description><![CDATA[&lt;p&gt;I&#x27;ve been maintaining &lt;a href=&quot;https://github.com/Shazwazza/Examine&quot;&gt;Examine&lt;/a&gt; for a very long time now. It&#x27;s the search and indexing library that sits underneath every Umbraco site, and like any project that&#x27;s been around long enough, it has plenty of hot paths that could be faster, a steady trickle of issues that need triaging, and a backlog of &quot;I&#x27;ll get to that eventually&quot; performance work that, well&#x2026; I never actually get to.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;So a couple of months ago I thought I&#x27;d try an experiment - what if I stopped doing all of that myself and instead let a bunch of AI agents do it for me, on a schedule, while I got on with everything else? This post is about how that went, and honestly it went a fair bit better than I expected. We&#x27;ve shipped a few releases off the back of it and some of the hot-path improvements are genuinely a bit ridiculous.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;So what are these &quot;agentic workflows&quot;?&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The thing I installed is &lt;a href=&quot;https://github.com/githubnext/agentics&quot;&gt;GitHub Next&#x27;s Agentic Workflows&lt;/a&gt; - a set of markdown-defined workflows that run in GitHub Actions and drive an AI agent to do actual maintenance work on your repo. They&#x27;re not chat bots. They run on a schedule, they have persistent memory, they open real pull requests, and they leave the &quot;should this ship?&quot; decision to me.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;I ended up with a few of them running on Examine:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Perf Improver&lt;/strong&gt; - runs daily, hunts for performance bottlenecks, writes benchmarks to actually prove the improvement, and opens a draft PR with the before/after numbers.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Efficiency Improver&lt;/strong&gt; - its scrappier sibling, focused on the smaller allocation-and-LINQ-state-machine wins that add up over time.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Daily Issue Triage&lt;/strong&gt; - goes through untriaged issues, sets types, applies labels, spots duplicates, and leaves a tidy triage report for me.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Agentic Maintenance&lt;/strong&gt; - keeps the whole setup ticking along.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;Each one is just a markdown file in &lt;code&gt;.github/workflows/&lt;/code&gt; with a description, a schedule, some &lt;code&gt;safe-outputs&lt;/code&gt; limits (things like &quot;you may open at most 4 PRs per run, and they must be drafts&quot;) and a big prompt describing how to behave. That&#x27;s it. The nice part is that the guardrails are declarative, so the agent can&#x27;t merge its own PRs, it can&#x27;t touch protected files, and it can only comment so many times per run. All of that is baked in.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;How it actually works day to day&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The bit that makes this more than a gimmick is the persistent memory. Every run, the Perf Improver reads its own notes - which build/test/benchmark commands it validated, what&#x27;s on its optimisation backlog, what it worked on last time, and which suggestions I&#x27;ve already ticked off. Then it does a couple of tasks in a round-robin fashion so it&#x27;s not endlessly poking at the same corner of the codebase.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;It also keeps a single rolling &quot;Monthly Activity&quot; issue open with a checklist of what needs my attention. So my side of it is pretty simple: the agent opens a draft PR with measured before/after numbers, I read it and run CI, and if I&#x27;m happy with it I merge. If I&#x27;m not, I close it and it learns for next time. That&#x27;s the whole loop. I&#x27;m the reviewer, the agent is the workhorse doing the grind I never had time for.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;So what did they actually get done?&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Over roughly the last two months, here&#x27;s what these workflows actually got up to on Examine:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;124&lt;/strong&gt; successful Perf Improver runs and &lt;strong&gt;9&lt;/strong&gt; successful Efficiency Improver runs&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;20&lt;/strong&gt; successful Daily Issue Triage runs quietly keeping the issue tracker tidy&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;24&lt;/strong&gt; performance/efficiency PRs reviewed and merged (13 from Perf Improver, 11 from Efficiency Improver) between late May and the end of June&lt;/li&gt;&#xA;&lt;li&gt;Another &lt;strong&gt;13&lt;/strong&gt; bug-fix PRs from the Copilot coding agent (more on those below)&lt;/li&gt;&#xA;&lt;li&gt;And the bit that actually matters - &lt;strong&gt;three releases shipped&lt;/strong&gt; off this work: &lt;strong&gt;v3.8.0&lt;/strong&gt;, &lt;strong&gt;v3.9.0&lt;/strong&gt; and the &lt;strong&gt;v4.0.0-beta.7&lt;/strong&gt; pre-release&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;That last point is really the whole thing. This isn&#x27;t a pile of speculative branches rotting in a fork somewhere. This is code that went through my review, passed CI, and is now sitting in NuGet packages that real Umbraco sites are running.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;Show me the numbers&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Right, this is the part I actually get excited about. One of my favourite things about the Perf Improver is that it isn&#x27;t allowed to just claim an improvement - it&#x27;s flat out forbidden from doing that. Every change has to come with a benchmark. So along the way it built out a proper &lt;a href=&quot;https://benchmarkdotnet.org/&quot;&gt;BenchmarkDotNet&lt;/a&gt; suite that compares the current source against the published NuGet packages (3.0.1 through 3.3.0), which means I can show you real, reproducible deltas instead of hand waving.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;The full-text search hot path&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;&lt;code&gt;ManagedQuery&lt;/code&gt; is &lt;em&gt;the&lt;/em&gt; primary full-text search entry point in Examine - it&#x27;s what runs on basically every search. The agent noticed it had no dedicated benchmark, wrote one, and then we stacked up a series of small, individually measured changes: a volatile factory cache in &lt;code&gt;SearchContext.GetFieldValueType&lt;/code&gt;, an early return in the extract-terms check, and killing off some redundant &lt;code&gt;ConcurrentDictionary&lt;/code&gt; lookups in &lt;code&gt;AddDocument&lt;/code&gt;.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Here&#x27;s the current source vs the most recent 3.3.0 release, on a 1,000-document index:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;| Method | Version | Mean | Allocated |&#xA;|---|---|---:|---:|&#xA;| ManagedQueryAllFields | 3.3.0 | 11.42 ms | 1,323 KB |&#xA;| ManagedQueryAllFields | &lt;strong&gt;Source&lt;/strong&gt; | &lt;strong&gt;2.17 ms&lt;/strong&gt; | &lt;strong&gt;371 KB&lt;/strong&gt; |&lt;/p&gt;&#xA;&#xA;&lt;p&gt;That&#x27;s about &lt;strong&gt;5.3x faster&lt;/strong&gt; and roughly &lt;strong&gt;3.6x less memory allocated&lt;/strong&gt; on the single most travelled code path in the whole library. On the busiest thing Examine does. I&#x27;ll happily take that.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;Building queries&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;&lt;code&gt;GroupedAnd&lt;/code&gt; / &lt;code&gt;GroupedOr&lt;/code&gt; / &lt;code&gt;GroupedNot&lt;/code&gt; are the workhorses of the query builder. A little &lt;code&gt;string[]&lt;/code&gt; fast-path (skipping a defensive &lt;code&gt;.ToArray()&lt;/code&gt; copy when the caller already handed us a &lt;code&gt;string[]&lt;/code&gt;) plus some allocation trimming got us this:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;| Method | Version | Mean | Allocated |&#xA;|---|---|---:|---:|&#xA;| CreateQueryOnly | 3.3.0 | 3,995 ns | 8.34 KB |&#xA;| CreateQueryOnly | &lt;strong&gt;Source&lt;/strong&gt; | &lt;strong&gt;319 ns&lt;/strong&gt; | &lt;strong&gt;2.20 KB&lt;/strong&gt; |&#xA;| GroupedAndStringArray | 3.3.0 | 21,377 ns | 21.10 KB |&#xA;| GroupedAndStringArray | &lt;strong&gt;Source&lt;/strong&gt; | &lt;strong&gt;16,659 ns&lt;/strong&gt; | &lt;strong&gt;14.34 KB&lt;/strong&gt; |&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The &lt;code&gt;CreateQuery()&lt;/code&gt; baseline dropping from 8.34 KB down to 2.2 KB is a lovely little win, and the grouped clauses are about 25% faster with a third of the allocation shaved off.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;Constructing a ValueSet&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Every single document you index goes through a &lt;code&gt;ValueSet&lt;/code&gt; constructor. The old path allocated an intermediate dictionary and a generator state machine per field, which is exactly the kind of thing you don&#x27;t notice until you&#x27;re bulk indexing a big site. The agent got rid of both:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;| Method | Version | Mean | Allocated |&#xA;|---|---|---:|---:|&#xA;| FromDictionary5Fields | 3.3.0 | 1,183 ns | 2,200 B |&#xA;| FromDictionary5Fields | &lt;strong&gt;Source&lt;/strong&gt; | &lt;strong&gt;226 ns&lt;/strong&gt; | &lt;strong&gt;592 B&lt;/strong&gt; |&#xA;| FromDictionary20Fields | 3.3.0 | 4,007 ns | 6,544 B |&#xA;| FromDictionary20Fields | &lt;strong&gt;Source&lt;/strong&gt; | &lt;strong&gt;654 ns&lt;/strong&gt; | &lt;strong&gt;1,520 B&lt;/strong&gt; |&lt;/p&gt;&#xA;&#xA;&lt;p&gt;That&#x27;s roughly &lt;strong&gt;5-6x faster&lt;/strong&gt; and about &lt;strong&gt;4x less allocated&lt;/strong&gt; on indexing, and when you&#x27;re rebuilding the index on a large Umbraco site that adds up fast.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The really nice touch is that these benchmark result tables now live in &lt;code&gt;&amp;lt;remarks&amp;gt;&lt;/code&gt; doc-comments right next to the benchmark code, so the numbers are versioned in the repo alongside the thing they measure. The agent did that bit too.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;It&#x27;s not just perf, it fixes bugs as well&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Alongside the scheduled perf work, I leaned on the Copilot coding agent for the gnarlier stuff - the kind of bug that needs actual investigation. A big one was the &lt;code&gt;SyncedFileSystemDirectoryFactory&lt;/code&gt; (the default directory factory for Umbraco) getting into a permanent index outage when a temp index file was transiently locked, along with taxonomy replication getting out of sync. Those are exactly the sort of intermittent, hard-to-reproduce issues that can eat a whole weekend. The agent investigated, reproduced it, and proposed fixes that made the searcher lazily resettable and hardened the replication, and those shipped in the v3.x and v4 beta releases.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;Was it actually worth it?&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Honestly, yes. And I want to be straight about it, because there&#x27;s a lot of AI hype flying around at the moment and most of it deserves a healthy dose of scepticism.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The bit that sold me wasn&#x27;t that the agents are magic, because they&#x27;re not. It&#x27;s the measurement. Everything comes to me as a small, focused, draft PR with the numbers attached, so I can look at it, sanity check it, and decide in a couple of minutes. When the agent isn&#x27;t sure about something the prompt tells it to do nothing rather than post noise, and for the most part it actually behaves. The stuff that isn&#x27;t good enough I just close, and it moves on.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;It&#x27;s not zero effort - I still read every change and I&#x27;ve closed plenty that weren&#x27;t worth it. But the ratio is fantastic. I&#x27;m getting a steady stream of well-measured, single-purpose performance PRs on a library I care about, on paths I&#x27;d genuinely never have found the time to optimise by hand, and I&#x27;ve shipped real releases because of it. For a project that I maintain around everything else, that&#x27;s a pretty great deal.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;If you maintain a repo with a backlog you never get to, especially performance work that needs benchmarks to justify it, I&#x27;d genuinely recommend giving &lt;a href=&quot;https://github.com/githubnext/agentics&quot;&gt;GitHub Next&#x27;s agentics&lt;/a&gt; a go.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;You can see all of it out in the open on the &lt;a href=&quot;https://github.com/Shazwazza/Examine&quot;&gt;Examine repo&lt;/a&gt; - the &lt;code&gt;[perf-improver]&lt;/code&gt; and &lt;code&gt;[efficiency-improver]&lt;/code&gt; PRs, the benchmark suite, and the releases they fed into. And there&#x27;s a nice bonus here for me too: &lt;a href=&quot;https://examinex.online/&quot;&gt;ExamineX&lt;/a&gt;, my managed, cloud-hosted Examine search offering, runs on this exact same internal plumbing. So all of this work the agents have been doing to tighten up Examine&#x27;s query and indexing hot paths feeds straight through into ExamineX as well - the underlying engine gets faster and leaner, and every ExamineX site gets those wins for free without changing a thing. If you&#x27;d rather have that search running as a managed service instead of hosting Lucene indexes on your own servers, that&#x27;s what ExamineX is there for. &#x1F642;&lt;/p&gt;]]></description>
                    <pubDate>Fri, 03 Jul 2026 17:45:20 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://medium.com/@ravimotha/umbraco-london-july-meetup-the-write-up-b4ce49a37390?source=rss------umbraco-5</guid>
                    <title>Umbraco London July Meetup .. the write- up</title>
                    <link>https://medium.com/@ravimotha/umbraco-london-july-meetup-the-write-up-b4ce49a37390?source=rss------umbraco-5</link>
                    <description><![CDATA[&lt;div class=&quot;medium-feed-item&quot;&gt;&lt;p class=&quot;medium-feed-image&quot;&gt;&lt;a href=&quot;https://medium.com/@ravimotha/umbraco-london-july-meetup-the-write-up-b4ce49a37390?source=rss------umbraco-5&quot;&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/2600/1*TzZ8HkxpsC1nIL1zJpZFjA@2x.jpeg&quot; width=&quot;4624&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;medium-feed-snippet&quot;&gt;Umbraco london is trying something silly a short unprogrammed stream of useless brain fog.&lt;/p&gt;&lt;p class=&quot;medium-feed-link&quot;&gt;&lt;a href=&quot;https://medium.com/@ravimotha/umbraco-london-july-meetup-the-write-up-b4ce49a37390?source=rss------umbraco-5&quot;&gt;Continue reading on Medium &#xBB;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;]]></description>
                    <pubDate>Fri, 03 Jul 2026 09:18:14 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/uprofile-july-2026-georgina-bidder/</guid>
                    <title>uProfile July 2026 - Georgina Bidder</title>
                    <link>https://umbraco.com/blog/uprofile-july-2026-georgina-bidder/</link>
                    <description><![CDATA[Meet Georgina: From the deep end to the Codegarden stage: Meet Core Collaborator Georgina Bidder!]]></description>
                    <pubDate>Fri, 03 Jul 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://mattbrailsford.dev/creating-a-safe-space-for-editors-to-be-wrong</guid>
                    <title>Creating A Safe Space for Editors to Be Wrong</title>
                    <link>https://mattbrailsford.dev/creating-a-safe-space-for-editors-to-be-wrong</link>
                    <description><![CDATA[I spend most of my time these days working on Umbraco AI, bringing AI into the hands of content editors. So I think a lot about what actually makes...]]></description>
                    <pubDate>Fri, 03 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/phases.umbraco.contentsearch</guid>
                    <title>Phases.Umbraco.ContentSearch</title>
                    <link>https://marketplace.umbraco.com/package/phases.umbraco.contentsearch</link>
                    <description><![CDATA[Advanced content search for the Umbraco backoffice. Editors can search content by document type and property, view results in a sortable grid, export to CSV or Excel, and save searches for later.]]></description>
                    <pubDate>Fri, 03 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=X8im857dhUs</guid>
                    <title>UMBRAAD 2026 | Accessibility Manual Testing: Why Lived Experience Matters - Thiago Carmo</title>
                    <link>https://www.youtube.com/watch?v=X8im857dhUs</link>
                    <description><![CDATA[Accessibility Manual Testing: Why Lived Experience Matters by Thiago Carmo&#xA;&#xA;UMBRAAD is a free virtual Umbraco community event packed with practical talks, live demos, and expert Q&amp;A sessions on building a more inclusive web.&#xA;&#xA;Read more on https://umbraad.com]]></description>
                    <pubDate>Thu, 02 Jul 2026 07:48:53 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=AsKGl8N20ek</guid>
                    <title>UMBRAAD 2026 | Accessibility Debt in Digital Products - Shivansh Mathur</title>
                    <link>https://www.youtube.com/watch?v=AsKGl8N20ek</link>
                    <description><![CDATA[Accessibility Debt in Digital Products: What AI Fixes and What It Doesn&#x27;t by Shivansh Mathur&#xA;&#xA;UMBRAAD is a free virtual Umbraco community event packed with practical talks, live demos, and expert Q&amp;A sessions on building a more inclusive web.&#xA;&#xA;Read more on https://umbraad.com]]></description>
                    <pubDate>Thu, 02 Jul 2026 07:28:49 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=on7fwoS32Hs</guid>
                    <title>UMBRAAD 2026 | Write Once, Reach Everyone: Accessible Writing - Corey Vilhauer</title>
                    <link>https://www.youtube.com/watch?v=on7fwoS32Hs</link>
                    <description><![CDATA[Write Once, Reach Everyone: Accessible Writing and GEO Want the Same Solution by Corey Vilhauer&#xA;&#xA;UMBRAAD is a free virtual Umbraco community event packed with practical talks, live demos, and expert Q&amp;A sessions on building a more inclusive web.&#xA;&#xA;Read more on https://umbraad.com]]></description>
                    <pubDate>Thu, 02 Jul 2026 07:24:46 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=FwgBVdGi3mw</guid>
                    <title>UMBRAAD 2026 | Why Automated Accessibility Tools Are Not Enough - Shadrack William Kyei</title>
                    <link>https://www.youtube.com/watch?v=FwgBVdGi3mw</link>
                    <description><![CDATA[Why Automated Accessibility Tools Are Not Enough by Shadrack William Kyei&#xA;&#xA;UMBRAAD is a free virtual Umbraco community event packed with practical talks, live demos, and expert Q&amp;A sessions on building a more inclusive web.&#xA;&#xA;Read more on https://umbraad.com]]></description>
                    <pubDate>Thu, 02 Jul 2026 07:19:35 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=Oa6Y7u3qITo</guid>
                    <title>UMBRAAD 2026 | What No One Tells You About Working in Accessibility - Danny Lancaster</title>
                    <link>https://www.youtube.com/watch?v=Oa6Y7u3qITo</link>
                    <description><![CDATA[What No One Tells You About Working in Accessibility by Danny Lancaster&#xA;&#xA;UMBRAAD is a free virtual Umbraco community event packed with practical talks, live demos, and expert Q&amp;A sessions on building a more inclusive web.&#xA;&#xA;Read more on https://umbraad.com]]></description>
                    <pubDate>Thu, 02 Jul 2026 07:16:46 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=1tUY7i2mKI4</guid>
                    <title>UMBRAAD 2026 | Shift Left on Accessibility: Beyond the Audit - Ramona Domen</title>
                    <link>https://www.youtube.com/watch?v=1tUY7i2mKI4</link>
                    <description><![CDATA[Shift Left on Accessibility: Beyond the Audit by Ramona Domen&#xA;&#xA;UMBRAAD is a free virtual Umbraco community event packed with practical talks, live demos, and expert Q&amp;A sessions on building a more inclusive web.&#xA;&#xA;Read more on https://umbraad.com]]></description>
                    <pubDate>Thu, 02 Jul 2026 07:13:10 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=spFK0VODBiI</guid>
                    <title>UMBRAAD 2026 | Designing for cognition - Ellie Barrett</title>
                    <link>https://www.youtube.com/watch?v=spFK0VODBiI</link>
                    <description><![CDATA[Designing for cognition by Ellie Barrett&#xA;&#xA;UMBRAAD is a free virtual Umbraco community event packed with practical talks, live demos, and expert Q&amp;A sessions on building a more inclusive web.&#xA;&#xA;Read more on https://umbraad.com]]></description>
                    <pubDate>Thu, 02 Jul 2026 07:05:11 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=dStALum-g_k</guid>
                    <title>UMBRAAD 2026 | Automating Accessibility Audits - Jordan Smith</title>
                    <link>https://www.youtube.com/watch?v=dStALum-g_k</link>
                    <description><![CDATA[Automating Accessibility Audits: Building a Full-Pipeline A11Y Scanning &amp; Reporting Tool by Jordan Smith.&#xA;&#xA;UMBRAAD is a free virtual Umbraco community event packed with practical talks, live demos, and expert Q&amp;A sessions on building a more inclusive web.&#xA;&#xA;Read more on https://umbraad.com]]></description>
                    <pubDate>Thu, 02 Jul 2026 07:00:43 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=IRYNePlevSo</guid>
                    <title>UMBRAAD 2026 | Accessibility starts before the software - Carl Sargunar</title>
                    <link>https://www.youtube.com/watch?v=IRYNePlevSo</link>
                    <description><![CDATA[Accessibility starts before the software: hardware, cloud tooling, LLMs and diminishing returns by Carl Sargunar.&#xA;&#xA;UMBRAAD is a free virtual Umbraco community event packed with practical talks, live demos, and expert Q&amp;A sessions on building a more inclusive web.&#xA;&#xA;Read more on https://umbraad.com]]></description>
                    <pubDate>Thu, 02 Jul 2026 06:44:05 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/the-agent-ready-cms-enable-the-ecosystem-umbraco-s-mcp-as-a-platform-and-software-factory/</guid>
                    <title>The Agent-Ready CMS: Enable the ecosystem</title>
                    <link>https://umbraco.com/blog/the-agent-ready-cms-enable-the-ecosystem-umbraco-s-mcp-as-a-platform-and-software-factory/</link>
                    <description><![CDATA[Learn how Umbraco&#x2019;s MCP platform and software factory empower partners and clients to build agentic AI tools for a truly agent-ready CMS ecosystem.]]></description>
                    <pubDate>Thu, 02 Jul 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.imagesharp.trimcache</guid>
                    <title>Umbraco.Community.ImageSharp.TrimCache</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.imagesharp.trimcache</link>
                    <description><![CDATA[Scheduled, age-based trimming of the ImageSharp.Web image cache for Umbraco. Supports both the Azure Blob cache and the local physical cache, keeping the cache from growing unbounded (for example exceeding Umbraco Cloud media-storage limits). Old variants are removed in the background and regenerated on the next request. Supports Umbraco 13, 17 and 18.]]></description>
                    <pubDate>Thu, 02 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/ideo.umbraco.mediamanager</guid>
                    <title>Ideo.Umbraco.MediaManager</title>
                    <link>https://marketplace.umbraco.com/package/ideo.umbraco.mediamanager</link>
                    <description><![CDATA[Safe, async media cleanup for Umbraco v17: find and remove orphaned media nodes and orphaned physical files, guarded by a deep reference scan, with dry-run preview and Recycle Bin safety.]]></description>
                    <pubDate>Thu, 02 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://dev.to/mpisaacs/codegarden-2026-a-little-late-because-it-gave-me-something-to-build-2em6</guid>
                    <title>Codegarden 2026 - a little late, because it gave me something to build</title>
                    <link>https://dev.to/mpisaacs/codegarden-2026-a-little-late-because-it-gave-me-something-to-build-2em6</link>
                    <description><![CDATA[&lt;p&gt;A few weeks ago I was in Copenhagen for my first Codegarden, and one quiet thought has stuck with me since. It didn&#x27;t come from a keynote. It came from the bit the keynote leaves out.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;I&#x27;ve worked with Umbraco for years, but I&#x27;d never been to Codegarden, and I turned up without much of a fixed idea of what the two days would be. I kept that open on purpose. I wanted to take it in rather than measure it against something I&#x27;d decided in advance. What struck me most was that the value came from two places at once. The sessions were a fantastic source of inspiration; everything from keynotes to guest speakers all seemed to resonate in some way or another. The conversations in between the sessions - drifting around the event space and finding common ground with anyone and everyone - proved just as valuable. I came home more energised than I&#x27;ve been in a while, with a notebook full of half-formed ideas and a better feel for the community I&#x27;m part of.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;But the thing I kept turning over afterwards was that bit the keynote leaves out. That&#x27;s what I want to write about.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The easy half and the hard half&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Every major Umbraco release gets the same treatment. A polished keynote, a clean demo, a feature that looks effortless on stage. There&#x27;s plenty in 18, and which part matters most depends on what you&#x27;re building. For me it&#x27;s Elements: a new Library section where you manage reusable content and reference it through a new element picker. Create once, use everywhere. It&#x27;s a genuinely good direction. Reusable content has lived awkwardly in the content tree for years, and Library finally gives it a proper home.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;What the demos don&#x27;t show you is the part I&#x27;ve been playing around with for the past few weeks. Taking a real Umbraco 17 site, with content pickers threaded through block lists, block grids, rich text blocks and base document properties, and getting all of it to point at the new Library without an editor ever noticing anything moved underneath them.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The feature is the easy half. The migration is the half that decides whether anyone actually uses it.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Why migration is where adoption lives&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;A new way of modelling content only matters if existing sites can get to it. New projects will use Library because it&#x27;s there and it&#x27;s the obvious choice. The much bigger pile of work is the sites already in production, built the old way, where reusable content was faked with content pickers pointing at hidden nodes because that was the best tool on offer at the time.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Upgrade conversations with clients are increasingly turning into &quot;end of life is on the way, you need to upgrade!&quot; but Umbraco have given us some genuinely useful new features that can turn those conversations from scaring clients away from security woes to improving their content management and supercharging their marketing activities.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;There&#x27;s a timing thing here. The migration path has to exist when the feature does, not three months later when the upgrade conversation has gone cold. A site that wants Library is at its most willing in the window right after release, while the appetite is fresh and the project is being planned anyway. Miss that window and you&#x27;re asking someone to reopen a decision they&#x27;ve already made, which almost never happens.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;That&#x27;s the question I bring to every shiny thing on a keynote slide. Not &quot;is this exciting&quot;, but &quot;what&#x27;s the real path from a live production site to it, and how much of that path can be made painless&quot;. The exciting idea is the easy part. The route onto it is the work.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  What the package actually does&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;This is the problem the Library Migrator package is built to solve, and the job is less glamorous than it sounds. It moves documents from Content into Library, so the things that were always meant to be reusable end up where they belong. It swaps every content picker on the relevant types for an element picker pointed at Library, so editors keep the same workflow and have nothing new to learn. And it rewrites the stored values, which is the part that earns its keep: every value held in an old content picker is updated to reference the new elements, across block lists, block grids, rich text blocks and base document properties. One reference left behind is a broken link an editor finds at the worst possible moment.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;None of that shows up in a demo, using a brand new, tailored project designed to show the feature off at its best. Yet content is the centrepiece of all CMS solutions and the value in existing content is always at the forefront of our clients&#x27; minds. Whether it&#x27;s a same-platform upgrade or a complete rebuild, the question of migration always gets raised.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The Library Migrator is out now. If you&#x27;re looking at an Umbraco 17 site and wondering how on earth it&#x27;s going to reach 18&#x27;s (or 21 if you&#x27;re LTS-conscious) Library, that&#x27;s exactly what it&#x27;s for.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://marketplace.umbraco.com/package/growcreate.librarymigrator&quot; rel=&quot;noopener noreferrer&quot;&gt;Library Migrator on Umbraco Marketplace&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://github.com/GrowCreate/Growcreate.LibraryMigrator&quot; rel=&quot;noopener noreferrer&quot;&gt;Library Migrator repository&lt;/a&gt;&lt;/p&gt;]]></description>
                    <pubDate>Wed, 01 Jul 2026 15:53:03 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/growcreate.librarymigrator</guid>
                    <title>Growcreate.LibraryMigrator</title>
                    <link>https://marketplace.umbraco.com/package/growcreate.librarymigrator</link>
                    <description><![CDATA[A backoffice package for Umbraco 18&#x2B; that migrates content saved as Element Types to the new Library (reusable elements) feature introduced in Umbraco 18.]]></description>
                    <pubDate>Wed, 01 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://kjac.dev/posts/postgresql-provider-for-umbraco-search/</guid>
                    <title>PostgreSQL provider for Umbraco Search</title>
                    <link>https://kjac.dev/posts/postgresql-provider-for-umbraco-search/</link>
                    <description><![CDATA[Introducing a PostgreSQL powered search provider for Umbraco Search.]]></description>
                    <pubDate>Wed, 01 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/july/using-umbracoautomate-to-populate-content-from-an-api/</guid>
                    <title>Using Umbraco.Automate to populate content from an API</title>
                    <link>https://owain.codes/blog/2026/july/using-umbracoautomate-to-populate-content-from-an-api/</link>
                    <description><![CDATA[Learn how to automatically populate Umbraco content from an external API using Umbraco.Automate, with a hands-on Pok&#xE9;API example and video demo.]]></description>
                    <pubDate>Wed, 01 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/casko.xmlsitemapsforumbraco</guid>
                    <title>Casko.XmlSitemapsForUmbraco</title>
                    <link>https://marketplace.umbraco.com/package/casko.xmlsitemapsforumbraco</link>
                    <description><![CDATA[Xml Sitemaps package for Umbraco CMS.]]></description>
                    <pubDate>Wed, 01 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/utpro.feature.simpleformbuilder</guid>
                    <title>uTPro.Feature.SimpleFormBuilder</title>
                    <link>https://marketplace.umbraco.com/package/utpro.feature.simpleformbuilder</link>
                    <description><![CDATA[Lightweight form builder for Umbraco 16, 17 and 18 backoffice. Create, manage, and render dynamic forms with 19&#x2B; field types, groups/columns layout, client-side validation, sensitive data encryption, multi-language support, custom field extensibility, entry storage, and public submit/render APIs. Render any form with a single ViewComponent call.]]></description>
                    <pubDate>Wed, 01 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>http://www.zpqrtbnk.net/posts/u17/</guid>
                    <title>U17</title>
                    <link>http://www.zpqrtbnk.net/posts/u17/</link>
                    <description><![CDATA[&lt;p&gt;This site has started as an Umbraco v4.x site, and has been regularly upgraded since then, never completely rebuilt. It has been running Umbraco 13 for about 3 years now, and it is about time to upgrade to Umbraco 17.&lt;/p&gt;&#xA;&lt;h4&gt;Packages&lt;/h4&gt;&#xA;&lt;p&gt;This is the easy part. The solution contains two projects: a Core project, and a UI project. Open each &lt;code&gt;.csproj&lt;/code&gt; file, bump &lt;code&gt;TargetFramework&lt;/code&gt; from &lt;code&gt;net8.0&lt;/code&gt; to &lt;code&gt;net10.0&lt;/code&gt;, bump Umbraco package references from &lt;code&gt;13.0.2&lt;/code&gt; to &lt;code&gt;17.4.0&lt;/code&gt;, bump a few other packages as per NuGet&#x27;s suggestions.&lt;/p&gt;&#xA;&lt;p&gt;The excellent &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/get-started/upgrading-and-migrating/version-specific&quot;&gt;Breaking Changes&lt;/a&gt; documentation tells us to remove &lt;code&gt;RazorCompileOnBuild&lt;/code&gt; and &lt;code&gt;RazorCompileOnPublish&lt;/code&gt; so, let us do it. It also tells us to clean our &lt;code&gt;Program&lt;/code&gt; class a little. Remove a &lt;code&gt;.AddDeliveryApi()&lt;/code&gt; call, remove a &lt;code&gt;.UserInstallerEndpoints()&lt;/code&gt; calls, that is it.&lt;/p&gt;&#xA;&lt;p&gt;At this point, rebuilding fails.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;ModelsBuilderSettings.ModelsMode&lt;/code&gt; used to be an &lt;code&gt;enum&lt;/code&gt;, looks like it is now a &lt;code&gt;string&lt;/code&gt;. Quite simple to fix. Everything that queried the &lt;code&gt;IPublishedContentCache&lt;/code&gt; does not compile anymore, porting to &lt;code&gt;IPublishedContentQuery&lt;/code&gt; is trivial. There is no &lt;code&gt;IContentService.SaveAndPublish()&lt;/code&gt; anymore, apparently, and one needs to &lt;code&gt;Save()&lt;/code&gt; then &lt;code&gt;Publish()&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;All in all, nothing dramatic.&lt;/p&gt;&#xA;&lt;p&gt;Some of my custom Markdown property editor and converter will not compile, I am going to comment them out for the time being.&lt;/p&gt;&#xA;&lt;p&gt;And... it builds.&lt;/p&gt;&#xA;&lt;h4&gt;Database&lt;/h4&gt;&#xA;&lt;p&gt;Trying to boot the site fails... with a &lt;code&gt;BootFailedException&lt;/code&gt;. A migration seems to want to delete a non-existing constraint named &lt;code&gt;DF_umbracoUser_createDate&lt;/code&gt;. A quick Internet search shows that this happened to others as well, so something must have gone wrong with migrations at some point. Not going to troubleshoot, creating the missing constraints before upgrading is quicker:&lt;/p&gt;&#xA;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt; ALTER TABLE umbracoUser ADD CONSTRAINT DF_umbracoUser_createDate DEFAULT GETUTCDATE() FOR createDate;&#xA; ALTER TABLE umbracoUser ADD CONSTRAINT DF_umbracoUser_updateDate  DEFAULT GETUTCDATE() FOR updateDate;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And presto... the site upgrades, boots, and I can log into the back-office.&lt;/p&gt;&#xA;&lt;h4&gt;Data Types&lt;/h4&gt;&#xA;&lt;p&gt;A range of data types are gone or have changed. And of course my custom data types are CompletelyBroken&#x2122; which is not a surprise, since the back-office UI has been entirely rebuilt.&lt;/p&gt;&#xA;&lt;p&gt;First, native data types. Basically, go into the &lt;em&gt;Data Types&lt;/em&gt; back-office section, and re-assign those that have issues to the proper property type. Rather simple. Weird enough, a content list datatype is throwing in the back-office, because of its &lt;code&gt;orderBy&lt;/code&gt; value. Something a migration did not catch? Manually re-saving the datatype fixes it.&lt;/p&gt;&#xA;&lt;p&gt;And then, I actually use two custom data types:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;ZpqrtBnk.ImgFocus&lt;/code&gt; is an image focus data type which is an alternative to crops. It allows the user to define a rectangle that represents the &amp;quot;zone of interest&amp;quot; of an image. That zone is defined on the media itself. Next, whenever we need to render the media, we can automatically figure out the best crop based upon this zone.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;ZpqrtBnk.Markdown&lt;/code&gt; is a custom Markdown data type that uses the back-office widget pretty much unchanged, but implements some rendering helpers for links or images.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;As far as Markdown is concerned, I was using a property editor in order to support additional custom syntax. Turns out a property editor is not needed anymore, a plain &lt;code&gt;IMarkdownToHtmlConverter&lt;/code&gt; implementation is all that is needed. So, the property editor is gone, and it is way nicer this way.&lt;/p&gt;&#xA;&lt;p&gt;On the other hand the image focus editor needs to be completely rebuilt.&lt;/p&gt;&#xA;&lt;h4&gt;My First Property Editor&lt;/h4&gt;&#xA;&lt;p&gt;There is some nice &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/extend-your-project/tutorials/creating-a-property-editor&quot;&gt;documentation&lt;/a&gt; about property editors in v17, so let us follow it.&lt;/p&gt;&#xA;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;mkdir PropertyEditors&#xA;cd PropertyEditors&#xA;npm create vite@latest ZpqrtBnk.ImgFocus&#xA;# with Lit&#xA;# with TypeScript&#xA;# without Vite RollDown (but I was not proposed it)&#xA;cd ZpqrtBnk.ImgFocus&#xA;npm i &amp;amp;&amp;amp; npm install -D @umbraco-cms/backoffice@17.4.0&#xA;rm -rf public/* src/*&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then,&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Update &lt;code&gt;vite.config.ts&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Create &lt;code&gt;src/zpqrtbnk-imgfocus.element.ts&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Create &lt;code&gt;public/umbraco-package.json&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Is all it takes. OK, it takes a bit of time to figure out how to put everything together but hey, this is my very first time with the new UI. The end result is &lt;em&gt;quite&lt;/em&gt; polished. As in, it makes way more sense than the convoluted Angular version.&lt;/p&gt;&#xA;&lt;p&gt;In the end,&lt;/p&gt;&#xA;&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code&gt;npm run build&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Drops files in my site&#x27;s &lt;code&gt;App_Plugins&lt;/code&gt; and we are done. As in, it just works. I have to say the experience is quite pleasant.&lt;/p&gt;&#xA;&lt;h4&gt;Models&lt;/h4&gt;&#xA;&lt;p&gt;We are not entirely done with backend work. A few more things have changed, including the CLR type of objects returned by various data types.&lt;/p&gt;&#xA;&lt;p&gt;The new &lt;code&gt;MediaPicker3&lt;/code&gt; for instance does not return a plain &lt;code&gt;IPublishedContent&lt;/code&gt;, but a &lt;code&gt;MediaWithCrops&lt;/code&gt;. I do not care about crops. And I had a media converter ensuring that the property value type would be reported as &lt;code&gt;Image&lt;/code&gt; in case the picker can only pick one single image. So... that converter needs a bit of update to report the proper type, and to unwrap &lt;code&gt;MediaWithCrops&lt;/code&gt; to &lt;code&gt;Image&lt;/code&gt; wherever appropriate.&lt;/p&gt;&#xA;&lt;p&gt;And then, with the various changes applied to property types, I though I would rebuild my models. Turns out they were built using the &lt;code&gt;Our.ModelsBuilder&lt;/code&gt; edition of the Models Builder, not the built-in one, because I am using some extra features.&lt;/p&gt;&#xA;&lt;h4&gt;Front-End Time&lt;/h4&gt;&#xA;&lt;p&gt;At this point, I have a running back-office, clean data types (though missing my Markdown converter, but that will be fixed later), everything is nice, time to test the front-end.&lt;/p&gt;&#xA;&lt;p&gt;And... it does not work.&lt;/p&gt;]]></description>
                    <pubDate>Tue, 30 Jun 2026 18:17:02 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=_tNVDlw2T18</guid>
                    <title>Umbraco Automate demo, Umbraco Codegarden 2026</title>
                    <link>https://www.youtube.com/watch?v=_tNVDlw2T18</link>
                    <description><![CDATA[Discover the capabilities of Umbraco Automate, a native workflow automation tool integrated directly into the Umbraco back office. This session provides a comprehensive look at how you can create, manage, and execute complex automation chains triggered by backend events like content modifications or media uploads.&#xA;&#xA;Learn how the architecture coordinates triggers and actions, allowing you to build intricate logic chains across the entire Umbraco ecosystem. The presentation details native integrations with Umbraco Engage, Forms, Commerce, Deploy, and AI Agents, demonstrating how workflows can operate autonomously when ecosystem events occur.&#xA;&#xA;Who This Video Is For&#xA;This video is designed for Umbraco developers, system architects, and content administrators looking to streamline backend operations. Understanding these automation workflows will help teams eliminate repetitive tasks, integrate external systems seamlessly, and safely embed AI utilities into their daily content management processes.&#xA;&#xA;Chapters&#xA;00:00 - Introduction to Umbraco Automate&#xA;&#xA;00:38 - Understanding Triggers, Actions, and Logic Chains&#xA;&#xA;00:54 - Ecosystem Integration: Forms, Commerce, Deploy, and AI&#xA;&#xA;01:18 - Demo: Content Saved Trigger &amp; Slack Notification Setup&#xA;&#xA;02:34 - Demo: Connecting AI Agents and Webhooks&#xA;&#xA;03:48 - Demo: Automated Media Transcription on Upload&#xA;&#xA;05:26 - Implementing a Human-in-the-Loop Approval Step&#xA;&#xA;06:30 - Community Packages and Early Access Extensions&#xA;&#xA;07:34 - Open Source Availability and Wrap-up&#xA;&#xA;Key Takeaways&#xA;Native Workflow Engine: Build and manage complex automation chains directly within the Umbraco back office without relying on external third-party integration platforms.&#xA;&#xA;AI &amp; Webhook Extensibility: Send data to AI agents for automated summaries or transcriptions, and route outputs to external endpoints via standard HTTP webhooks.&#xA;&#xA;Human-in-the-Loop Guardrails: Insert manual approval gates into automated processes to pause execution until an administrator reviews and verifies the data.&#xA;&#xA;Ecosystem &amp; Community Ready: Supports core Umbraco products alongside popular community packages like Translation Manager for automated translations and Newsletter Studio for transactional mailing lists.&#xA;&#xA;Free and Open Source: Umbraco Automate is fully open source and available for immediate deployment.&#xA;&#xA;Important Links&#xA;Umbraco Automate Project Page: [Insert Link]&#xA;&#xA;Launch Announcement &amp; Documentation: [Insert Link]&#xA;&#xA;Community Extension Guide: [Insert Link]&#xA;&#xA;Featured Session - AI and Umbraco by Matt: [Insert Link]]]></description>
                    <pubDate>Tue, 30 Jun 2026 08:41:04 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/knowit.umbraco.aitranslate</guid>
                    <title>Knowit.Umbraco.AiTranslate</title>
                    <link>https://marketplace.umbraco.com/package/knowit.umbraco.aitranslate</link>
                    <description><![CDATA[A guided AI translation dashboard for Umbraco. Pick a language pair (or create a new language), choose pages or the whole site, and translate content into other languages using your Umbraco.AI profile. Media references are carried over, link titles are translated, and everything is saved as drafts for review. Requires the Umbraco.AI package.]]></description>
                    <pubDate>Tue, 30 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umcontenttranslator</guid>
                    <title>umContentTranslator</title>
                    <link>https://marketplace.umbraco.com/package/umcontenttranslator</link>
                    <description><![CDATA[Umbraco backoffice package for translating content nodes using OSKI Content Translator.]]></description>
                    <pubDate>Tue, 30 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/going-from-umbraco-13-to-17/</guid>
                    <title>Going from Umbraco 13 to 17</title>
                    <link>https://umbraco.com/blog/going-from-umbraco-13-to-17/</link>
                    <description><![CDATA[Upgrading from Umbraco 13 to 17 LTS? Discover the two main migration paths and learn how Umbraco Cloud can smooth your transition before the 2026 EOL date for Umbraco 13.]]></description>
                    <pubDate>Tue, 30 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/oc.automate.linkedin</guid>
                    <title>OC.Automate.LinkedIn</title>
                    <link>https://marketplace.umbraco.com/package/oc.automate.linkedin</link>
                    <description><![CDATA[LinkedIn integration for Umbraco Automate. Post content to LinkedIn as part of your automation workflows.]]></description>
                    <pubDate>Tue, 30 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/phases.umbraco.community.templatehistory</guid>
                    <title>Phases.Umbraco.Community.TemplateHistory</title>
                    <link>https://marketplace.umbraco.com/package/phases.umbraco.community.templatehistory</link>
                    <description><![CDATA[Track version history for Umbraco templates, stylesheets, scripts, and partial views. Compare diffs side-by-side or unified, restore previous versions, and browse recent changes from a dedicated History workspace tab and Settings dashboard.]]></description>
                    <pubDate>Tue, 30 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://dev.to/luukpeters/advanced-permissions-meets-umbraco-18-26g0</guid>
                    <title>Advanced Permissions meets Umbraco 18!</title>
                    <link>https://dev.to/luukpeters/advanced-permissions-meets-umbraco-18-26g0</link>
                    <description><![CDATA[&lt;p&gt;A few days ago, the final version of &lt;a href=&quot;https://umbraco.com/blog/umbraco-18-release/&quot; rel=&quot;noopener noreferrer&quot;&gt;Umbraco 18 was released&lt;/a&gt;! So it was time to update my Advanced Permissions package to support Umbraco 18.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This was not just a simple case of updating a few namespaces and dependencies and calling it done. The main new feature in Umbraco 18 was a perfect candidate for Advanced Permissions support, so that is exactly what I added!&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  What is new in Umbraco 18&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The Umbraco 18 release is (and I quote) &quot;a short and sweet release&quot;. The main attraction is the new Library section and the first version of reusable Elements.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffkf4v757xyftp3s0ci5m.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffkf4v757xyftp3s0ci5m.png&quot; alt=&quot;The new Library section in Umbraco 18&quot; width=&quot;771&quot; height=&quot;366&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Reusable Elements in the Library section are essentially Content nodes without rendering and routing. Other than that, they behave a lot like Content: you can create, delete, move them, and so on. That made them the perfect candidate for support in v18 of the Advanced Permissions package.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Besides Library support, the package also has a few other improvements and additions. Let&#x27;s talk about them!&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Library support!&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The first obvious new feature is the Permissions Editor for the Library. Just like with Content, you can set permissions for a User Group using the same inheritance and scoping system as the Content Permissions Editor.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8nndmdxhifxli40asm5w.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8nndmdxhifxli40asm5w.png&quot; alt=&quot;The Library Permissions Editor&quot; width=&quot;800&quot; height=&quot;313&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;You&#x27;ll notice that not every permission is applicable in every case, so N/A is displayed when a permission does not apply.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;And just like with Content, the Library also has an Access Viewer where you can see the effective permissions for a User Group or an individual User.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzbiitpigy6g93hfw3092.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzbiitpigy6g93hfw3092.png&quot; alt=&quot;The Library Access Viewer&quot; width=&quot;800&quot; height=&quot;287&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;I also added a Library Element Type Permissions Editor. Just like the Document Type Permissions Editor, you can set the insert options for Element Types for a specific User Group.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft64dxrjo4kahxha0w8j7.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft64dxrjo4kahxha0w8j7.png&quot; alt=&quot;The Library Element Type Permissions Editor&quot; width=&quot;800&quot; height=&quot;265&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;With this Permissions Editor, you can control whether a User Group can create instances of an Element Type. This acts as a filter on the &quot;create&quot; list in the Library. And when a User has multiple User Groups, the well-established resolver will determine the effective permissions.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Currently, because of a limitation in Umbraco, it is not yet possible to scope these permissions to a specific part of the Library tree like the Document Type Permissions Editor does.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;And of course, the Element Type Permissions Editor also has an associated Access Viewer.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Febygmk78o91jrk6chea0.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Febygmk78o91jrk6chea0.png&quot; alt=&quot;Library Elements Access Viewer&quot; width=&quot;800&quot; height=&quot;270&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Redesign&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Because of all these new Permissions Editors and Access Viewers, the menu became harder to read at a glance. So the main menu has been redesigned around the scope of the editor and viewer.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1g4dv1ag1ofbm6hh95uw.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1g4dv1ag1ofbm6hh95uw.png&quot; alt=&quot;The reworked menu of Advanced Permissions&quot; width=&quot;800&quot; height=&quot;390&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;All editors and viewers in the menu are now called Permissions Editor and Access Viewer respectively. Their purpose is determined by the menu header they are under: Content, Document Type, Library, or Library Element Type.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;In the screenshot, you&#x27;ll also notice a slight redesign of the workspaces for the editors and viewers. They now look more Umbraco native and display a one-line description of what the editor or viewer is for. And when you have not selected anything yet, it will now display a much nicer view. This will also be ported back to the Umbraco 17 version.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  To help or not to help&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;In the top-right corner of each editor or viewer, you&#x27;ll also notice a &quot;learn more&quot; button. This button gives access to more detailed documentation. It describes what the editor or viewer is for, and it links to more generic documentation explaining the concepts.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Consider this a first version. It is already much better than nothing, but I think it can still be improved over time. This will also be ported back to the Umbraco 17 version.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Localization support!&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;And lastly, apart from the expanded documentation, Advanced Permissions now has localization for all languages that the Backoffice supports. Obviously, these translations are automatically generated because I am not fluent in 28 languages, so if you find an error, please let me know!&lt;/p&gt;&#xA;&#xA;&lt;p&gt;All in all, I think this is a very nice and complete release. I&#x27;m happy that Advanced Permissions can support new Umbraco features as soon as they come out.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;You can find Advanced Permissions for Umbraco here:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;NuGet:&lt;br&gt;&#xA;&lt;a href=&quot;https://www.nuget.org/packages/Umbraco.Community.AdvancedPermissions/&quot; rel=&quot;noopener noreferrer&quot;&gt;https://www.nuget.org/packages/Umbraco.Community.AdvancedPermissions/&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The Umbraco Marketplace:&lt;br&gt;&#xA;&lt;a href=&quot;https://marketplace.umbraco.com/package/umbraco.community.advancedpermissions&quot; rel=&quot;noopener noreferrer&quot;&gt;https://marketplace.umbraco.com/package/umbraco.community.advancedpermissions&lt;/a&gt;&lt;/p&gt;]]></description>
                    <pubDate>Sun, 28 Jun 2026 19:49:52 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/june/ocautomatelinkedin-now-available/</guid>
                    <title>OC.Automate update</title>
                    <link>https://owain.codes/blog/2026/june/ocautomatelinkedin-now-available/</link>
                    <description><![CDATA[OC.Automate.LinkedIn is out of beta and OC.Automate.Bluesky and OC.Automate.Mastodon are all working on Umbraco 18]]></description>
                    <pubDate>Sun, 28 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://github.com/umbraco/Announcements/issues/36</guid>
                    <title>[Breaking change]: Umbraco Search replaces existing search in Umbraco 19</title>
                    <link>https://github.com/umbraco/Announcements/issues/36</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 26 Jun 2026 11:38:19 Z</pubDate>
                        <category>hq</category>
                        <category>announcement</category>
                </item>
                <item>
                    <guid>https://community.umbraco.com/blog/2026/06/what-were-most-excited-about-on-the-new-community-site-part-1-of-2/</guid>
                    <title>What we&#x27;re most excited about on the new Community site - part 1 of 2</title>
                    <link>https://community.umbraco.com/blog/2026/06/what-were-most-excited-about-on-the-new-community-site-part-1-of-2/</link>
                    <description><![CDATA[What we&#x27;re most excited about on the new Community site - part 1 of 2 | Umbraco Community]]></description>
                    <pubDate>Fri, 26 Jun 2026 11:16:40 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=mEa90pJb0Bw</guid>
                    <title>umbraCoffee - Codegarden 2026 Wrapped &#x1F32F;</title>
                    <link>https://www.youtube.com/watch?v=mEa90pJb0Bw</link>
                    <description><![CDATA[Welcome to your monthly dose of #umbraCoffee&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;! Your hosts - Marcin and Callum - together with their guest(s) will drive through all of the community news and happenings in the Umbraco world. So... grab a cuppa, join us LIVE and enjoy!&#xA;&#xA;See ya?!&#xA;&#xA;---&#xA;&#x2615; Wanna buy us a coffee/pizza/donuts?&#xA;https://www.buymeacoffee.com/umbracoffee&#xA;---&#xA;&#xA;Topics:&#xA;//ToDo:]]></description>
                    <pubDate>Fri, 26 Jun 2026 09:00:07 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/june/umbraco-automate/</guid>
                    <title>Umbraco Automate</title>
                    <link>https://owain.codes/blog/2026/june/umbraco-automate/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 26 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.entityactions.forcedelete</guid>
                    <title>Umbraco.Community.EntityActions.ForceDelete</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.entityactions.forcedelete</link>
                    <description><![CDATA[A Umbraco community package that adds an entity action to force delete documents.]]></description>
                    <pubDate>Fri, 26 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.schemeweaver.ai</guid>
                    <title>Umbraco.Community.SchemeWeaver.AI</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.schemeweaver.ai</link>
                    <description><![CDATA[AI-powered schema mapping for SchemeWeaver using Umbraco.AI]]></description>
                    <pubDate>Fri, 26 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/june/umbraco-automate-workflows/</guid>
                    <title>Umbraco Automate Workflows</title>
                    <link>https://owain.codes/blog/2026/june/umbraco-automate-workflows/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 26 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.proworks.com/blog/archive/building-with-claude-and-umbraco-setting-up-mcp-and-creating-content-with-ai/</guid>
                    <title>Building with Claude and Umbraco: Setting Up MCP and Creating Content with AI</title>
                    <link>https://www.proworks.com/blog/archive/building-with-claude-and-umbraco-setting-up-mcp-and-creating-content-with-ai/</link>
                    <description><![CDATA[&lt;p&gt;I&#x27;ll be honest, when Jason first mentioned setting up an MCP server to connect Claude to our Umbraco dev environment, I assumed it was going to be a difficult dev-heavy project that would take the day at least, and be a bit past my coding comprehension ability as a Front End Developer. I even made a new local branch assuming I was going to have to write and commit code.&lt;/p&gt;&#xA;&lt;p&gt;Nope! It wasn&#x27;t like that at all. And I&#x27;m still a little surprised about it. It was just setting up a config file in Claude and setting up API users in Umbraco.&lt;/p&gt;&#xA;&lt;p&gt;If you&#x27;re an Umbraco developer who&#x27;s been curious about AI-assisted content workflows but figured the setup overhead wasn&#x27;t worth it, this post is for you. I&#x27;m going to walk through exactly what I did, what tripped me up (spoiler: one small thing), and what became possible on the other side of it.&lt;/p&gt;&#xA;&lt;hr /&gt;&#xA;&lt;h2&gt;Part 1: What Is the Umbraco MCP Server, Anyway?&lt;/h2&gt;&#xA;&lt;p&gt;MCP stands for Model Context Protocol. It&#x27;s an open standard that lets AI assistants like Claude connect directly to external tools and services, not just chat about them, but actually interact with them.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;a href=&quot;https://docs.umbraco.com/umbraco-in-ai/mcp/cms-developer-mcp&quot;&gt;Umbraco MCP server&lt;/a&gt; is an implementation of that standard for Umbraco. Once it&#x27;s set up and connected, Claude can read and write content in your Umbraco instance through the Management API. We&#x27;re talking creating pages, updating properties, working with block components, the same things you&#x27;d do in the back office, but driven by Claude. It&#x27;s actually pretty amazing to see it work.&lt;/p&gt;&#xA;&lt;hr /&gt;&#xA;&lt;h2&gt;Part 2: Setting Up the MCP Server&lt;/h2&gt;&#xA;&lt;p&gt;Before anything else, a quick note on prerequisites. You&#x27;ll need an Umbraco site to connect to (we&#x27;re using our dev environment), and Claude Desktop or Cowork installed on your machine. That&#x27;s really it on the &amp;quot;before you start&amp;quot; front, which was the first pleasant surprise.&lt;/p&gt;&#xA;&lt;p&gt;The MCP server itself is configured through a JSON config file in Claude. Go to your &lt;strong&gt;Claude settings&lt;/strong&gt;, then &lt;strong&gt;Developer&lt;/strong&gt;, and click the &lt;strong&gt;&amp;quot;Edit Config&amp;quot;&lt;/strong&gt; button to bring up the &lt;em&gt;&lt;strong&gt;claude_desktop_config.json&lt;/strong&gt;&lt;/em&gt; file in your favorite editor.&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Close Claude completely (including killing it in the taskbar) while working on the config file. If Claude is running, it will overwrite your changes when it closes.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Make sure you&#x27;re on the latest version of Node before you start.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Drop this into your config file, change the name as you like, change the BASE_URL to your site, and we&#x27;ll cover the CLIENT_ID and SECRET in the next steps.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&amp;quot;mcpServers&amp;quot;: {&#xA;  &amp;quot;YOUR-umbraco-dev-mcp-server&amp;quot;: {&#xA;    &amp;quot;command&amp;quot;: &amp;quot;npx&amp;quot;,&#xA;    &amp;quot;args&amp;quot;: [&#xA;      &amp;quot;@umbraco-cms/mcp-dev@latest&amp;quot;&#xA;    ],&#xA;    &amp;quot;env&amp;quot;: {&#xA;      &amp;quot;UMBRACO_CLIENT_ID&amp;quot;: &amp;quot;umbraco-back-office-api-user&amp;quot;,&#xA;      &amp;quot;UMBRACO_CLIENT_SECRET&amp;quot;: &amp;quot;12345-GUID-OR-PASSWORD-6789&amp;quot;,&#xA;      &amp;quot;UMBRACO_BASE_URL&amp;quot;: &amp;quot;https://your-site.io&amp;quot;,&#xA;      &amp;quot;UMBRACO_INCLUDE_TOOL_COLLECTIONS&amp;quot;: &amp;quot;document,media,document-type,data-type&amp;quot;&#xA;    }&#xA;  }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;hr /&gt;&#xA;&lt;h2&gt;Part 3: Creating an API User in the Umbraco Back Office&lt;/h2&gt;&#xA;&lt;p&gt;This is the part I was most nervous about. &amp;quot;API user&amp;quot; sounds like something that involves a terminal and a lot of Googling. It does not. It&#x27;s just a few clicks in the Umbraco back office and I was genuinely a little embarrassed by how straightforward it was.&lt;/p&gt;&#xA;&lt;p&gt;Head into your Umbraco back office and navigate to the Users section. We&#x27;re going to create both a new User Group and a new API user. First, the User Group. Create one and call it MCP-User-Developer and give it as much control as a developer would. If you ever wanted another group called MCP-User-Editor with less control, you can do that too. For now, add Content, Media and Settings sections and turn on everything you&#x27;d like it to have access to.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&quot;https://dev-proworks-v13-site.useast01.umbraco.io/media/5sbd1xfk/group-1.png&quot; alt=&quot;creating a user group&quot; /&gt;&lt;/p&gt;&#xA;&lt;p&gt;Next, go to Users and create a new API User. Name it something like &amp;quot;something-mcp-developer&amp;quot; and make it a member of the MCP-User-Developer group we just made. Add an email address for its username and check on access to start nodes (or give it full access).&lt;/p&gt;&#xA;&lt;p&gt;Now the key step: click the Client Credentials button to add the key we&#x27;ll need in the Claude config file. The ID will have a prefix of &amp;quot;umbraco-back-office&amp;quot; and then you name it whatever you want. In my example I went with &amp;quot;api-user&amp;quot;, so the full ID becomes &amp;quot;umbraco-back-office-api-user&amp;quot;. For the Secret, generate a GUID or secure password however you like.&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Once you click Create, the password won&#x27;t be visible again. Save it somewhere before moving on!&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;&lt;img src=&quot;https://dev-proworks-v13-site.useast01.umbraco.io/media/oshpbxuf/credentials.png&quot; alt=&quot;credentials&quot; /&gt;&lt;/p&gt;&#xA;&lt;p&gt;Now we have all the info for the config file. Go back and add &amp;quot;umbraco-back-office-api-user&amp;quot; to the &lt;code&gt;UMBRACO_CLIENT_ID&lt;/code&gt; and your password to the &lt;code&gt;UMBRACO_CLIENT_SECRET&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;hr /&gt;&#xA;&lt;h2&gt;Part 4: Connecting Claude to Your Umbraco Site&lt;/h2&gt;&#xA;&lt;p&gt;At this point you&#x27;ve got the config file set up and your API user created. The last step is getting Claude to actually recognize the connection. Save your claude_desktop_config.json file and restart Claude. Go to Settings, then Developer again, and you should see your MCP server listed there and running.&lt;/p&gt;&#xA;&lt;p&gt;I was stuck here for a bit because I was not on the latest version of Node, and also because I had the UMBRACO_CLIENT_ID wrong. Woops! So make sure your config has all the correct info. But if everything checks out you should see a &amp;quot;running&amp;quot; label next to your server, and you&#x27;re now connected!&lt;/p&gt;&#xA;&lt;p&gt;A quick way to confirm everything is working is to just ask Claude something simple about your site. Something like &amp;quot;list the pages under the home node&amp;quot; or &amp;quot;what document types are available?&amp;quot; If Claude comes back with real data from your Umbraco instance, you&#x27;re in business. As soon as it gave me the ID of the home node of our dev site, I knew things were about to get real.&lt;/p&gt;&#xA;&lt;hr /&gt;&#xA;&lt;h2&gt;Part 5: Creating Content with Claude&lt;/h2&gt;&#xA;&lt;p&gt;This is the fun part.&lt;/p&gt;&#xA;&lt;p&gt;Once Claude is connected to your Umbraco instance, you can start asking it to do real content work. Not just drafting copy in the chat window, but actually creating and populating pages inside Umbraco. I started simple, asking Claude to create a Basic Page under the home node with a title and some body text. It did it. First try. I went and checked the back office and there it was, sitting as a draft, ready to review.&lt;/p&gt;&#xA;&lt;p&gt;From there I started pushing it further. Our Basic Page document type has a bunch of block components available, things like Feature Boxes, Statistics, Testimonials, FAQ sections, Numbered Steps, and a Two-Column Comparison block. I described what I wanted the page to be about and asked Claude to use as many relevant components as made sense for the content. The results were genuinely impressive, well-structured pages with appropriate blocks chosen for the content, not just a wall of rich text.&lt;/p&gt;&#xA;&lt;p&gt;A few tips from what I&#x27;ve learned so far:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Give Claude context about your document types.&lt;/strong&gt; The more it knows about your block components and what fields they have, the better the output.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Keep pages as drafts first.&lt;/strong&gt; Claude creates content as drafts by default, which is exactly what you want. Review before publishing.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Be specific about tone and content.&lt;/strong&gt; Claude will make reasonable choices on its own, but the more direction you give it, the closer the first draft will be to what you actually want.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Watch out for placeholder content.&lt;/strong&gt; Claude may generate fictional quotes or statistics as placeholders. Always review before anything goes live.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;One small thing to be aware of: on our setup, pages created via the MCP server sometimes needed the template set manually in the back office before they&#x27;d render on the front end. It&#x27;s a quick fix, just one more thing to check on your first run through.&lt;/p&gt;&#xA;&lt;hr /&gt;&#xA;&lt;h2&gt;Part 6: Real-World Use Cases&lt;/h2&gt;&#xA;&lt;p&gt;So what&#x27;s this actually good for in practice? After spending some time with it, here are the use cases that have stood out most.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Spinning up draft pages quickly.&lt;/strong&gt; If you&#x27;ve got a list of pages that need to exist, Claude can create and populate them fast. What might take an editor an afternoon of copying, pasting and formatting can happen in minutes. The drafts still need a human review pass, but you&#x27;re starting from something solid rather than a blank page.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Consistent page structure across a site.&lt;/strong&gt; When Claude is working from the same document type and block components every time, the output is naturally consistent. Every page gets a hero, a logical block order, appropriate use of the available components. It&#x27;s a lot harder to end up with that one orphaned page that&#x27;s formatted completely differently from everything else.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Exploring content strategy.&lt;/strong&gt; This one surprised me. Being able to say &amp;quot;create a page making the case for upgrading Umbraco and use whichever block components make sense&amp;quot; and get back a fully structured draft is genuinely useful for figuring out what you actually want to say. It&#x27;s a fast way to go from a topic to a first draft you can react to.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Auditing and rewriting existing content.&lt;/strong&gt; Claude can read your existing pages too, which means you can ask it to review copy, flag inconsistencies, or suggest rewrites across multiple pages without touching the back office yourself.&lt;/p&gt;&#xA;&lt;p&gt;Like I said, I knew things were about to get real.&lt;/p&gt;&#xA;&lt;p&gt;We&#x27;re still figuring out the best workflows ourselves at ProWorks, but it&#x27;s already changing how we think about content production. I&#x27;m excited to see where it goes from here.&lt;/p&gt;&#xA;&lt;p&gt;If you have questions or want to share what you&#x27;ve built with it, feel free to reach out.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;Alan Ballard, Front End Developer, ProWorks&lt;/em&gt;&lt;/p&gt;]]></description>
                    <pubDate>Thu, 25 Jun 2026 16:00:16 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=WtatxMNRW8Y</guid>
                    <title>Umbraco MCP as a Platform Intoduction</title>
                    <link>https://www.youtube.com/watch?v=WtatxMNRW8Y</link>
                    <description><![CDATA[Phil Whittaker and Bolette Kern introduce the &quot;Umbraco in AI&quot; framework, showcasing how the Umbraco Management API exposes content, media, document types, and search configurations to modern AI models. This session highlights how to bridge the CMS with artificial intelligence using the Model Context Protocol (MCP) and dedicated command-line tools.&#xA;&#xA;Learn how to move beyond local environments using Hosted MCP servers with secure OAuth authentication, connect terminal environments directly via the new CLI tool, and use the Base MCP SDK to make custom Umbraco packages agent-ready. The talk also explores advanced architectural patterns like MCP chaining and an automated five-phase Software Factory.&#xA;&#xA;This video is for Umbraco package authors, digital agencies, and platform developers looking for a structured path to implement AI agents. By leveraging these official tools, development teams can eliminate manual integration plumbing and focus entirely on building custom logic, strategy, and creative experiences for clients.&#xA;&#xA;Key Takeaways:&#xA;- Management API Core: Serves as the central translation engine, transforming structured CMS capabilities into discoverable data points that LLMs can read, reason about, and automate.&#xA;&#xA;- Multi-Channel Architecture: Support for Local MCP (on-machine agents), Hosted MCP (cloud remote agent access via secure user authentication), and a developer-centric CLI tool.&#xA;&#xA;- Marketplace Readiness: The official Base MCP SDK enables package authors to instantly convert existing OpenAPI schemas into functional MCP servers with minimal overhead.&#xA;&#xA;- The Five-Phase Software Factory: A command-line toolkit that handles boilerplate scaffolding, project configuration, API schema discovery, tool generation, and automated integration/evaluation testing.&#xA;&#xA;- Advanced MCP Chaining: Eliminates redundant manual configurations through structural orchestration patterns like proxying, delegation, and composite multi-step tools.&#xA;&#xA;Timeline Chapters: &#xA;00:00 - Introduction to the Umbraco in AI Strategy&#xA;00:59 - Interactive Integration Diagram Overview&#xA;01:07 - The Central Role of the Umbraco Management API&#xA;01:29 - Stage 1: The Local Developer MCP Foundation&#xA;02:10 - Stage 2: Hosted MCP and Custom ChatGPT App Setup Demo&#xA;03:24 - Native Connections via the CLI Tool and Claude Code Integration&#xA;05:08 - Unpacking the Differences: Local MCP vs. Hosted MCP vs. CLI&#xA;06:49 - Stage 3: Making Umbraco Packages Agent-Ready with the Base SDK&#xA;07:43 - Stage 4: Scaffolding a Server Using the Five-Phase Software Factory&#xA;09:57 - Stage 5: Advanced MCP Chaining (Proxying, Delegation, and Composite Tools)&#xA;11:07 - Composing Shared Capabilities Across Custom MCP Servers&#xA;11:51 - Stage 6: The New Umbraco in AI Documentation Section&#xA;12:12 - Summary: Lowering Barriers and Reducing Friction for Digital Agencies&#xA;&#xA;Resources and Links:&#xA;Official Umbraco in AI Documentation: https://docs.umbraco.com/umbraco-in-ai&#xA;&#xA;Model Context Protocol (MCP) Core Concepts: https://docs.umbraco.com/umbraco-in-ai/concepts/model-context-protocol&#xA;&#xA;Base MCP Package Guide &amp; Repository Info: https://docs.umbraco.com/umbraco-in-ai/mcp/base-mcp&#xA;&#xA;Developer MCP Server Configurations: https://docs.umbraco.com/umbraco-in-ai/mcp/cms-developer-mcp&#xA;&#xA;Umbraco AI strategy: www.umbraco.com/ai &#xA;&#xA;Umbraco Official CMS Resources: www.umbraco.com]]></description>
                    <pubDate>Thu, 25 Jun 2026 10:11:03 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=PmSAsJMs_lw</guid>
                    <title>Unboxing Umbraco 18</title>
                    <link>https://www.youtube.com/watch?v=PmSAsJMs_lw</link>
                    <description><![CDATA[Join us for a developer&#x27;s perspective on Umbraco 18, the new Standard-Term Support release of the CMS.&#xA;&#xA;We discuss the new Elements feature, typed OpenAPI schemas for the Delivery API, and the move from Swashbuckle to Microsoft.AspNetCore.OpenApi.&#xA;&#xA;We also look at features you may have missed in recent Umbraco 17 minors, and explain the plan for Umbraco 17 - the current Long-Term Support release.&#xA;&#xA;Chapters: &#xA;00:00 Introduction&#xA;00:51 Releases review&#xA;02:50 A look at Elements&#xA;14:06 Typed OpenAPI schemas for the Delivery API&#xA;18:29 Moving from Swashbuckle to Microsoft.AspNetCore.OpenApi&#xA;21:10 The new login screen!&#xA;23:30 Umbraco 17 minors review&#xA;23:51 Umbraco 17.4 changes for AI&#xA;27:36 Upgrade considerations&#xA;29:21 Finding more information&#xA;&#xA;&#xA;Related resources: &#xA;Dive into the Umbraco 18 final release blog post: [URL]&#xA;&#xA;Visit our Umbraco 18 product page: https://umbraco.com/products/umbraco-cms/umbraco-18/&#xA;&#xA;Ready to learn more? Explore the Umbraco 18 documentation: https://docs.umbraco.com/umbraco-cms&#xA;&#xA;Specific documentation links:&#xA;Version-specific upgrade instructions: https://docs.umbraco.com/umbraco-cms/18.latest/get-started/upgrading-and-migrating/version-specific&#xA;&#xA;Umbraco 18 Release Candidate blog post: https://umbraco.com/blog/umbraco-18-release-candidate/&#xA;&#xA;Laura&#x27;s blog post on migrating away from Swashbuckle: https://dev.to/lauraneto/umbraco-18-and-openapi-a-heads-up-for-extension-developers-1k7&#xA;&#xA;Filip&#x27;s product update from Codegarden: https://umbraco.com/blog/umbraco-product-updatecodegarden-keynote-highlights-q2-2026/&#xA;&#xA;Andy Butland&#x27;s CMS Roadmap talk from Codegarden: https://www.youtube.com/watch?v=HO0BsEebTys]]></description>
                    <pubDate>Thu, 25 Jun 2026 10:10:54 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://codeshare.co.uk/blog/clean-starter-kit-v8-released/</guid>
                    <title>Clean Starter Kit v8 Released</title>
                    <link>https://codeshare.co.uk/blog/clean-starter-kit-v8-released/</link>
                    <description><![CDATA[Clean Starter Kit v8 released for Umbraco 18. Explore the new element library features, block list labels workaround, and runtime migration solution for categories.]]></description>
                    <pubDate>Thu, 25 Jun 2026 08:07:26 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.memberlogin</guid>
                    <title>Umbraco.Community.MemberLogin</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.memberlogin</link>
                    <description><![CDATA[Sign in to the front-end as a member from the Umbraco backoffice, with optional culture and redirect page, opening in a new tab.]]></description>
                    <pubDate>Thu, 25 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/krebil.umbracoazuresearch</guid>
                    <title>Krebil.UmbracoAzureSearch</title>
                    <link>https://marketplace.umbraco.com/package/krebil.umbracoazuresearch</link>
                    <description><![CDATA[Plug Azure AI Search into Umbraco Search as a fully-featured provider: filtering, faceting, sorting, culture/segment variants, and protected content out of the box.]]></description>
                    <pubDate>Thu, 25 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/umbraco-18-release/</guid>
                    <title>Umbraco 18 Release</title>
                    <link>https://umbraco.com/blog/umbraco-18-release/</link>
                    <description><![CDATA[The latest Major Release of Umbraco is here: Umbraco 18. Including Phase One of Elements for reusable content management, and typed OpenAPI schemas for the Delivery API. Upgrade today]]></description>
                    <pubDate>Thu, 25 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=4hKRsNnKzkY</guid>
                    <title>Phil Whittaker, Umbraco in AI</title>
                    <link>https://www.youtube.com/watch?v=4hKRsNnKzkY</link>
                    <description><![CDATA[AI agents are becoming part of how we build and manage digital experiences. In this session, we explore how Umbraco works in an AI-first world - from a base MCP server and chained MCP architecture to Agent Skills for the backoffice, implementation, and content modelling. Learn how we&#x2019;re reducing friction so LLMs and agents can interact with Umbraco using shared best practices.]]></description>
                    <pubDate>Wed, 24 Jun 2026 11:15:38 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.johanreitsma.com/blogs/validating-an-umbraco-13-to-17-upgrade-with-a-sitemap-audit/</guid>
                    <title>Validating an Umbraco 13 to 17 Upgrade with a Sitemap Audit</title>
                    <link>https://www.johanreitsma.com/blogs/validating-an-umbraco-13-to-17-upgrade-with-a-sitemap-audit/</link>
                    <description><![CDATA[How I used a small .NET console tool to crawl a sitemap, compare Umbraco 13 and 17 environments, and quickly find broken pages after an upgrade....]]></description>
                    <pubDate>Wed, 24 Jun 2026 10:54:04 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/lait.umbraco.content.draganddrop</guid>
                    <title>Lait.Umbraco.Content.DragAndDrop</title>
                    <link>https://marketplace.umbraco.com/package/lait.umbraco.content.draganddrop</link>
                    <description><![CDATA[Drag-and-drop and keyboard reordering for the Umbraco backoffice Content tree, plus the ability to drag an item out of a collection (list view) and drop it anywhere in the content tree. Three-zone drop targets, cross-parent moves, a move-in-progress spinner and WCAG-compliant keyboard grab &amp; place.]]></description>
                    <pubDate>Wed, 24 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/sa.automate.weatherapi</guid>
                    <title>SA.Automate.WeatherApi</title>
                    <link>https://marketplace.umbraco.com/package/sa.automate.weatherapi</link>
                    <description><![CDATA[WeatherAPI.com connection types and actions for Umbraco Automate. Get the current weather for a location as part of an automation workflow.]]></description>
                    <pubDate>Wed, 24 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=wx7Qiyi2Y90</guid>
                    <title>Kenn Jakobsen, It&#x27;s Elemental; reuse your content!</title>
                    <link>https://www.youtube.com/watch?v=wx7Qiyi2Y90</link>
                    <description><![CDATA[Reusable content has arguably been one of the most requested features in Umbraco since forever.&#xA;&#xA;Umbraco 18 is just around the corner, and along with it comes Elements - a brand new way of managing content items that can be shared freely between pages. It&#x27;s a fully-fledged content editing experience, built for content reuse.&#xA;&#xA;What&#x27;s more, Elements promise a seamless integration with block editors such as Block List and Block Grid, making it an even more appealing choice for editors.&#xA;&#xA;In this session I&#x27;ll give you the grand tour of Elements. Expect lots of demos and sneak peaks of what&#x27;s to come.]]></description>
                    <pubDate>Tue, 23 Jun 2026 12:44:00 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=gtGw-mY3c2U</guid>
                    <title>Matt Brailsford, AI in Umbraco</title>
                    <link>https://www.youtube.com/watch?v=gtGw-mY3c2U</link>
                    <description><![CDATA[The core principle of Umbraco AI is to be a basis for custom AI integrations. Whilst the Prompt and Agent add-ons provide out of the box functionality, the real power of Umbraco AI is in its extension points.&#xA;&#xA;In this session we&#x27;ll take a look at the various way in which you can extend Umbraco AI and build your own custom AI solution on top of it.]]></description>
                    <pubDate>Tue, 23 Jun 2026 09:19:15 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=Vd1SLvO1pcE</guid>
                    <title>Bolette Kern, Umbraco CMS in the Age of AI</title>
                    <link>https://www.youtube.com/watch?v=Vd1SLvO1pcE</link>
                    <description><![CDATA[AI in Umbraco. Umbraco in AI. And the question underneath both: how do you work with a CMS platform for a future no one can predict?&#xA;&#xA;In this talk, I&#x27;ll present and demo the latest on both AI tracks, explore the changing role of content management, and why it&#x27;s even more important now, and take a look at the next editor-facing features coming to the CMS.]]></description>
                    <pubDate>Tue, 23 Jun 2026 08:19:07 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://dev.to/bernadet/extending-tiptap-in-umbraco-a-real-world-list-example-1hd1</guid>
                    <title>Extending Tiptap in Umbraco &#x2013; a real world list example</title>
                    <link>https://dev.to/bernadet/extending-tiptap-in-umbraco-a-real-world-list-example-1hd1</link>
                    <description><![CDATA[&lt;p&gt;If you&#x27;ve spent any time migrating editors or building rich-text features, you&#x27;ll know Tiptap looks great on paper but sometimes feels a little... minimal compared to what TinyMCE shipped out of the box. At ilionx we&#x27;ve been moving a few large sites to Umbraco 17 and bumped into the same feedback: list style options. Nothing dramatic, just the ability to pick Roman numerals, different bullet shapes, that sort of thing, but enough to make editors ask for the old behavior back.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;So we wrote a small TypeScript extension that adds back list-style variants. It gets built to App_Plugins with Vite, plugs into the UmbTiptapExtensionApiBase and wires up extra toolbar menu items. The actual extension is tiny, it just adds a listStyleType attribute to the list nodes and renders it as inline CSS, but the surrounding bits (icons, toolbar menus, wiring) make the UX feel polished.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Tiptap has solid docs on extending and creating extensions, and Umbraco documents how to register a Tiptap extension, but stitching everything together took a little trial and error. Below is the extension configuration we used. It looks like a lot for a simple feature, but a fair chunk of the files are just icons and small glue code.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmpscmls4o6334edu9dwi.jpg&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmpscmls4o6334edu9dwi.jpg&quot; alt=&quot; &quot; width=&quot;558&quot; height=&quot;581&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Let&#x2019;s start with the actual extension definitions in &lt;code&gt;Umbraco-package.json&lt;/code&gt;, where we define 4 extensions:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;&quot;extensions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;icons&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;alias&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;My.Icons.TiptapListStyle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/App_Plugins/My.TiptapListStyle/list-style-icons.js&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;tiptapExtension&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;alias&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;My.Tiptap.ListStyle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;api&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/App_Plugins/My.TiptapListStyle/list-style.tiptap-api.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;meta&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;icon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;icon-ordered-list&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;List style type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;group&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;#tiptap_extGroup_formatting&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;tiptapToolbarExtension&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;kind&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;menu&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;alias&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;My.Tiptap.Toolbar.OrderedList&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;overwrites&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Umb.Tiptap.Toolbar.OrderedList&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;api&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/App_Plugins/ My.TiptapListStyle/ordered-list-menu.tiptap-toolbar-api.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;forExtensions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;My.Tiptap.ListStyle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot; My.Tiptap.OrderedList&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Numbered list&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;appearance&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;icon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;icon-ordered-list&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Numbered list: i, ii, iii&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;lower-roman&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;appearance&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;icon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;icon-list-style-lower-roman&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;definitions&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;here&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &#xA;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;tiptapToolbarExtension&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;kind&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;menu&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;alias&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot; My.Tiptap.Toolbar.BulletList&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;overwrites&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Umb.Tiptap.Toolbar.BulletList&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;api&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/App_Plugins/My.TiptapListStyle/bullet-list-menu.tiptap-toolbar-api.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;forExtensions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;My.Tiptap.ListStyle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Umb.Tiptap.BulletList&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;items&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Bullet list&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;appearance&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;icon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;icon-bulleted-list&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Bullet list: circle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;circle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;appearance&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;icon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;icon-list-style-bullet-circle&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;definitions&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;here&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Here&#x2019;s what we register:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;an icon set (a bunch of tiny SVGs showing what each list style looks like)&lt;/li&gt;&#xA;&lt;li&gt;one Tiptap extension which carries the list-style attribute&lt;/li&gt;&#xA;&lt;li&gt;two toolbar extensions that replace the ordered/bulleted list buttons with menus that expose the variants.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The icon set&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The icons are trivial: I asked an AI to generate SVGs for different list markers and put each one in a tiny TypeScript file that exports the SVG string.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/** Ordered list with lower-roman markers (i, ii, iii). */&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; stroke-width=&quot;1.75&quot;&amp;gt;&amp;lt;text x=&quot;1&quot; y=&quot;7.5&quot; font-size=&quot;4.5&quot; fill=&quot;currentColor&quot; stroke=&quot;none&quot; font-family=&quot;serif&quot; font-style=&quot;italic&quot;&amp;gt;i.&amp;lt;/text&amp;gt;&amp;lt;path d=&quot;M9 6h12&quot;/&amp;gt;&amp;lt;text x=&quot;1&quot; y=&quot;13.5&quot; font-size=&quot;4.5&quot; fill=&quot;currentColor&quot; stroke=&quot;none&quot; font-family=&quot;serif&quot; font-style=&quot;italic&quot;&amp;gt;ii.&amp;lt;/text&amp;gt;&amp;lt;path d=&quot;M9 12h12&quot;/&amp;gt;&amp;lt;text x=&quot;1&quot; y=&quot;19.5&quot; font-size=&quot;4.5&quot; fill=&quot;currentColor&quot; stroke=&quot;none&quot; font-family=&quot;serif&quot; font-style=&quot;italic&quot;&amp;gt;iii.&amp;lt;/text&amp;gt;&amp;lt;path d=&quot;M9 18h12&quot;/&amp;gt;&amp;lt;/svg&amp;gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;And a small registry file maps the icon names to those files:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;icon-list-style-lower-roman&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./icons/svg-ordered-list-lower-roman.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;//...&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;These images are purely to make the toolbar menus readable &#x2014; a little UX polish so editors instantly recognise the option they&#x2019;re picking.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwq4cx2w5cdb00ep1rkyq.jpg&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwq4cx2w5cdb00ep1rkyq.jpg&quot; alt=&quot; &quot; width=&quot;305&quot; height=&quot;270&quot;&gt;&lt;/a&gt; &lt;br&gt;&#xA;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy66bsar5ax2iu3fm0ig4.jpg&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy66bsar5ax2iu3fm0ig4.jpg&quot; alt=&quot; &quot; width=&quot;392&quot; height=&quot;313&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The Tiptap extension&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The extension itself is surprisingly compact. It adds a &lt;code&gt;listStyleType&lt;/code&gt; attribute to the built-in &lt;code&gt;orderedList&lt;/code&gt; and &lt;code&gt;bulletList&lt;/code&gt; nodes and serialises it as inline &lt;code&gt;list-style-type&lt;/code&gt; style so the HTML stays portable and renders the same in the backoffice and on the front end.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Extension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UmbTiptapExtensionApiBase&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@umbraco-cms/backoffice/tiptap&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;cm&quot;&gt;/**&#xA; * Extends the built-in orderedList and bulletList nodes with a `listStyleType`&#xA; * attribute that maps to the CSS `list-style-type` property.&#xA; *&#xA; * The attribute is serialised as an inline style so the stored HTML is portable&#xA; * and renders correctly both in the backoffice editor and on the front end.&#xA; */&lt;/span&gt;&#xA;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ListStyleExtension&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Extension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;listStyle&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;&#xA;  &lt;span class=&quot;nf&quot;&gt;addGlobalAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;na&quot;&gt;types&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;orderedList&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;bulletList&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&#xA;        &lt;span class=&quot;na&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;          &lt;span class=&quot;na&quot;&gt;listStyleType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;na&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;na&quot;&gt;parseHTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listStyleType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;na&quot;&gt;renderHTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;              &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;listStyleType&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;&#xA;              &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`list-style-type: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;listStyleType&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;          &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ListStyleTiptapExtensionApi&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UmbTiptapExtensionApiBase&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;  &lt;span class=&quot;nf&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ConstructorParameters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UmbTiptapExtensionApiBase&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getTiptapExtensions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ListStyleExtension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;That&#x2019;s it, the extension maps an attribute to CSS and makes sure works in both front- and backoffice. Nothing scary.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The toolbar extensions&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Because ordered and unordered lists are separate toolbar buttons, we overwrite each one with a menu that exposes the style variants. To avoid duplicating logic we put the toolbar behaviour into a single helper and import it from the two small extension files.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Each toolbar menu has to do a few things:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;create a list if the selection isn&#x2019;t in one&lt;/li&gt;&#xA;&lt;li&gt;switch between ordered and bullet lists&lt;/li&gt;&#xA;&lt;li&gt;toggle or set a specific list-style-type and reflect the active state in the menu UI.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;That last bit is where the logic concentrates, the UI needs to show which style is active and allow toggling back to the default behaviour.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The per-list-type extension files look like this:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createListStyleMenuToolbarApi&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./list-style-menu-toolbar-api.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;createListStyleMenuToolbarApi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;bulletList&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;And the shared toolbar helper contains the actual implementation and state logic:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Editor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@umbraco-cms/backoffice/tiptap&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UmbTiptapToolbarElementApiBase&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@umbraco-cms/backoffice/tiptap&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ListStyleMenuItem&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getStyleType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ListStyleMenuItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;applyListStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;  &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;orderedList&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;bulletList&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;nx&quot;&gt;styleType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;  &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isActive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentStyle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;listStyleType&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;newStyle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentStyle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;styleType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;styleType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;updateAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;listStyleType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;newStyle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;  &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;orderedList&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;toggleOrderedList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;updateAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;orderedList&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;listStyleType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;styleType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;toggleBulletList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;updateAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;bulletList&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;listStyleType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;styleType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;applyDefaultList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;orderedList&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;bulletList&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;  &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isActive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentStyle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;listStyleType&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;currentStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;      &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;updateAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;listStyleType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;orderedList&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;      &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;toggleOrderedList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;      &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;toggleBulletList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;  &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;orderedList&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;toggleOrderedList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;focus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;toggleBulletList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;cm&quot;&gt;/**&#xA; * Toolbar menu API for ordered/bullet list buttons with list-style-type variants.&#xA; */&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;createListStyleMenuToolbarApi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;orderedList&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;bulletList&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UmbTiptapToolbarElementApiBase&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;nx&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isActive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ListStyleMenuItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;      &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;styleType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getStyleType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;      &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;styleType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isActive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;      &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;styleType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentStyle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;listStyleType&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isActive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentStyle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isActive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;listStyleType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;styleType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;nx&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ListStyleMenuItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;      &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;styleType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getStyleType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;      &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;styleType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;styleType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;nf&quot;&gt;applyDefaultList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;      &lt;span class=&quot;nf&quot;&gt;applyListStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;listType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;styleType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  TODO / caveats&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;I&#x2019;m still getting comfortable with TypeScript, so this isn&#x27;t a 100%-polished extension. One known quirk: clicking a custom style button after setting a style will clear the style but not fully remove the list node the way the stock ordered/bullet button does. It&#x27;s a small UX edge-case and likely fixable by tweaking the toggle logic, but I haven&#x27;t had time for it yet.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;If you want to copy this approach, the important bits are:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;expose a &lt;code&gt;listStyleType&lt;/code&gt; attribute on the list nodes,&lt;/li&gt;&#xA;&lt;li&gt;serialize it in a way that works in both editor and front end (inline style is the simplest)&lt;/li&gt;&#xA;&lt;li&gt;replace the toolbar buttons with menus that set/update that attribute.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;Hopefully this saves you a few hours of experimentation. The overall idea is small, but the payoff for editors is surprisingly nice.&lt;/p&gt;]]></description>
                    <pubDate>Tue, 23 Jun 2026 07:37:36 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/sa.automate.ntfy</guid>
                    <title>SA.Automate.Ntfy</title>
                    <link>https://marketplace.umbraco.com/package/sa.automate.ntfy</link>
                    <description><![CDATA[ntfy connection types and actions for Umbraco Automate. Send notifications to ntfy as part of an automation workflow.]]></description>
                    <pubDate>Tue, 23 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/sa.automate.pushover</guid>
                    <title>SA.Automate.Pushover</title>
                    <link>https://marketplace.umbraco.com/package/sa.automate.pushover</link>
                    <description><![CDATA[Pushover connection type and action for Umbraco Automate. Send notifications to Pushover as part of an automation workflow.]]></description>
                    <pubDate>Tue, 23 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/knowit.umbraco.editorlock</guid>
                    <title>Knowit.Umbraco.EditorLock</title>
                    <link>https://marketplace.umbraco.com/package/knowit.umbraco.editorlock</link>
                    <description><![CDATA[Prevents two editors from changing the same content node at the same time. When a node is already open, a second editor gets a read-only view with a red border and can either Request access (the current editor is prompted to accept or decline) or Force access (an immediate takeover with confirmation). Locks auto-release when the holder disconnects or goes idle, so nodes never get stuck. Real-time over SignalR.]]></description>
                    <pubDate>Tue, 23 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/the-pragmatic-enterprise-balancing-ai-innovation-with-predictable-tco/</guid>
                    <title>The Pragmatic Enterprise: Balancing AI Innovation with Predictable TCO</title>
                    <link>https://umbraco.com/blog/the-pragmatic-enterprise-balancing-ai-innovation-with-predictable-tco/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Tue, 23 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://github.com/limbo-works/Limbo.Umbraco.Video/releases/tag/v17.0.0-alpha001</guid>
                    <title>Limbo.Umbraco.Video 17.0.0-alpha001</title>
                    <link>https://github.com/limbo-works/Limbo.Umbraco.Video/releases/tag/v17.0.0-alpha001</link>
                    <description><![CDATA[Package serving as a base for Limbo&#x27;s video picker packages.]]></description>
                    <pubDate>Mon, 22 Jun 2026 18:05:01 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=TRGFLqq711g</guid>
                    <title>Bjarke Berg, Running Umbraco in a Changing World</title>
                    <link>https://www.youtube.com/watch?v=TRGFLqq711g</link>
                    <description><![CDATA[The web has changed. The traffic each Umbraco site is being asked to handle today looks very different from what it did just two years ago &#x2014; and most of the growth isn&#x27;t humans. AI has collapsed the cost of automated traffic, bots and probes are part of daily life on the open internet, and defaults that were merely sensible in 2024 are mandatory in 2026.&#xA;&#xA;There&#x27;s plenty to talk about, and as ever, Codegarden is a great time to share where we are with you.&#xA;&#xA;This talk will cover what running Umbraco actually looks like in 2026 &#x2014; no matter where you host. We&#x27;ll walk through the highlights from the last twelve months on Umbraco Cloud, the things that have landed and the things about to. We&#x27;ll dig into the dimensions every serious Umbraco operator should be thinking about right now: security, performance and operations. And we&#x27;ll look at where the platform itself is heading next &#x2014; there&#x27;s a new chapter beginning, and we&#x27;ll spend real time on what it means for you.&#xA;&#xA;Attend this talk and you will leave with a clear picture of what has changed about running Umbraco &#x2014; and one concrete thing to check on every site you operate tomorrow morning. You&#x27;ll be just as excited as we are about what&#x27;s coming next on Umbraco Cloud, and familiar with the roadmap for what the future holds in the upcoming releases.]]></description>
                    <pubDate>Mon, 22 Jun 2026 11:23:06 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=ThgXALBfU-g</guid>
                    <title>Umbraco Keynote, Mats Persson, Emma Bustow &amp; Filip Bech-Larsen</title>
                    <link>https://www.youtube.com/watch?v=ThgXALBfU-g</link>
                    <description><![CDATA[Creating and updating your website should be the least of your worries. With Umbraco, you get a content management system known and loved for its flexibility and great editing experience.&#xA;&#xA;Umbraco is easy to get started with install, set up, and host it yourself or let us take care of it all for you on Umbraco Cloud. https://try.umbraco.com&#xA;&#xA;Learn more about Umbraco on our website https://umbraco.com&#xA;Discover our Umbraco Community: https://community.umbraco.com/&#xA;Find the Umbraco source code on Github: https://github.com/umbraco/Umbraco-CMS&#xA;Visit the Umbraco Documentation: https://docs.umbraco.com]]></description>
                    <pubDate>Mon, 22 Jun 2026 10:51:13 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=LWtYvcAalac</guid>
                    <title>Arnold Visser, Build. Scale. Grow. From Running Projects to Growing Portfolios with Umbraco Cloud.</title>
                    <link>https://www.youtube.com/watch?v=LWtYvcAalac</link>
                    <description><![CDATA[Creating and updating your website should be the least of your worries. With Umbraco, you get a content management system known and loved for its flexibility and great editing experience.&#xA;&#xA;Umbraco is easy to get started with install, set up, and host it yourself or let us take care of it all for you on Umbraco Cloud. https://try.umbraco.com&#xA;&#xA;Learn more about Umbraco on our website https://umbraco.com&#xA;Discover our Umbraco Community: https://community.umbraco.com/&#xA;Find the Umbraco source code on Github: https://github.com/umbraco/Umbraco-CMS&#xA;Visit the Umbraco Documentation: https://docs.umbraco.com]]></description>
                    <pubDate>Mon, 22 Jun 2026 10:28:07 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=HO0BsEebTys</guid>
                    <title>Andy Butland, Our Roadmap, Your CMS  Umbraco 17 Released and What We&#x27;re Building Next</title>
                    <link>https://www.youtube.com/watch?v=HO0BsEebTys</link>
                    <description><![CDATA[Creating and updating your website should be the least of your worries. With Umbraco, you get a content management system known and loved for its flexibility and great editing experience.&#xA;&#xA;Umbraco is easy to get started with install, set up, and host it yourself or let us take care of it all for you on Umbraco Cloud. https://try.umbraco.com&#xA;&#xA;Learn more about Umbraco on our website https://umbraco.com&#xA;Discover our Umbraco Community: https://community.umbraco.com/&#xA;Find the Umbraco source code on Github: https://github.com/umbraco/Umbraco-CMS&#xA;Visit the Umbraco Documentation: https://docs.umbraco.com]]></description>
                    <pubDate>Mon, 22 Jun 2026 08:57:50 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@CorneHoskam/116792346368820033</guid>
                    <title>&quot;We Need to Go Deeper: Extending Umbraco&#x27;s Extensions&quot; Codegarden workshop now available as an escape room</title>
                    <link>https://umbracocommunity.social/@CorneHoskam/116792346368820033</link>
                    <description><![CDATA[&#x1F527; We turned our Codegarden workshop into an escape room.Ronald Barendse, Nathan Woulfe and I ran &quot;We Need to Go Deeper: Extending Umbraco&#x27;s Extensions&quot;, four hours of coding quests across Engage, Workflow and Deploy, each one unlocking a fragment of a bigger puzzle.And here&#x27;s the thing... you can play it too! The whole workshop is public, so clone the repo and work through the quests at your own pace. &#x1F447;https://cornehoskam.com/posts/extending-umbracos-extensions-a-codegarden-workshop-you-can-try-yourself/#umbraco #codegarden #dotnet #extensions]]></description>
                    <pubDate>Mon, 22 Jun 2026 07:48:45 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://umbuntu.uk/blog/codegarden-2026-ubuntu</guid>
                    <title>Codegarden 2026: Ubuntu</title>
                    <link>https://umbuntu.uk/blog/codegarden-2026-ubuntu</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 22 Jun 2026 06:44:08 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/june/its-coffee-time/</guid>
                    <title>It&#x27;s Coffee Time!</title>
                    <link>https://owain.codes/blog/2026/june/its-coffee-time/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 22 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://cornehoskam.com/posts/extending-umbracos-extensions-a-codegarden-workshop-you-can-try-yourself/</guid>
                    <title>Extending Umbraco&#x27;s Extensions: A Codegarden Workshop You Can Try Yourself</title>
                    <link>https://cornehoskam.com/posts/extending-umbracos-extensions-a-codegarden-workshop-you-can-try-yourself/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 22 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/uprofile-june-2026-ben-szymanski/</guid>
                    <title>uProfile June 2026 - Ben Szymanski</title>
                    <link>https://umbraco.com/blog/uprofile-june-2026-ben-szymanski/</link>
                    <description><![CDATA[From restoring vintage Macs to catching waves and building backoffice magic - meet 2026 Umbraco MVP Ben Szymanski.]]></description>
                    <pubDate>Mon, 22 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owaincodes.uksouth01.umbraco.io/blog/2026/june/its-coffee-time/</guid>
                    <title>It&#x27;s Coffee Time!</title>
                    <link>https://owaincodes.uksouth01.umbraco.io/blog/2026/june/its-coffee-time/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 22 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/kontainer.umbraco</guid>
                    <title>kontainer.umbraco</title>
                    <link>https://marketplace.umbraco.com/package/kontainer.umbraco</link>
                    <description><![CDATA[Adds a media picker to pick media items from a Kontainer repository]]></description>
                    <pubDate>Mon, 22 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/june/its-coffee-time/</guid>
                    <title>It&#x27;s Coffee Time!</title>
                    <link>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/june/its-coffee-time/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 22 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/lait.umbraco.analytics.plausible</guid>
                    <title>Lait.Umbraco.Analytics.Plausible</title>
                    <link>https://marketplace.umbraco.com/package/lait.umbraco.analytics.plausible</link>
                    <description><![CDATA[Surfaces Plausible Analytics tracking data inside the Umbraco backoffice: a Content dashboard and a per-page block on each document&#x27;s Info tab.]]></description>
                    <pubDate>Sat, 20 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/lait.umbraco.ui.scrolltofield</guid>
                    <title>Lait.Umbraco.UI.ScrollToField</title>
                    <link>https://marketplace.umbraco.com/package/lait.umbraco.ui.scrolltofield</link>
                    <description><![CDATA[A table of contents navigation helper for the Umbraco backoffice. Adds a dockable outline panel to the document editor that lists the page&#x27;s tabs, property groups and Block List / Block Grid items &#x2014; so editors keep their overview and can jump straight to any section on long content pages. Click an entry to scroll it into view and highlight it.]]></description>
                    <pubDate>Sat, 20 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/frontendsupport.partialtextstring</guid>
                    <title>FrontendSupport.PartialTextString</title>
                    <link>https://marketplace.umbraco.com/package/frontendsupport.partialtextstring</link>
                    <description><![CDATA[Basically a TextString, but you can specify prefix and/or postfix strings to show, which can make it much easier to understand exactly what&#x27;s supposed to go into the field.]]></description>
                    <pubDate>Sat, 20 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://markmcdonald.dev/writing/what-codegarden-inspired-me-to-build-next/</guid>
                    <title>What Codegarden Inspired Me to Build Next</title>
                    <link>https://markmcdonald.dev/writing/what-codegarden-inspired-me-to-build-next/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 19 Jun 2026 13:39:21 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://mastodon.social/@greystate/116774972921955847</guid>
                    <title>Spin up Umbraco websites quickly with Umbeasy</title>
                    <link>https://mastodon.social/@greystate/116774972921955847</link>
                    <description><![CDATA[Need to spin up an #Umbraco website for a quick test of something?Try the friction-free #Umbreasy &#x26A1;&#x1F3C3;&#x200D;&#x2642;&#xFE0F;&#x200D;&#x27A1;&#xFE0F;It&#x27;s in beta right now: https://umbreasy.com]]></description>
                    <pubDate>Fri, 19 Jun 2026 04:51:47 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/esatto.umbraco.backoffice.redirects</guid>
                    <title>Esatto.Umbraco.Backoffice.Redirects</title>
                    <link>https://marketplace.umbraco.com/package/esatto.umbraco.backoffice.redirects</link>
                    <description><![CDATA[Dead-URL &#x2192; new-URL redirects for Umbraco 17. Provides a SQL-backed Redirects table, a Settings-section dashboard for editors to manage 301 rules, and an IContentFinder that resolves redirects at request time. A single flat list of redirects: exact case-insensitive matching with query-string preservation, draft rows, and idempotent migrations.]]></description>
                    <pubDate>Fri, 19 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.nathanielnunes.com/blog/umbraco-mvp-codegarden-2026/</guid>
                    <title>Copenhagen, Codegarden, and My First Year as an Umbraco MVP</title>
                    <link>https://www.nathanielnunes.com/blog/umbraco-mvp-codegarden-2026/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Thu, 18 Jun 2026 17:53:16 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=FKpbT4LQHd0</guid>
                    <title>Codegarden Aftermovie 2026</title>
                    <link>https://www.youtube.com/watch?v=FKpbT4LQHd0</link>
                    <description><![CDATA[&#x1F430; The Rabbit faced traffic jams, train delays, and several moments of &#x201C;you&#x2019;ve got to be kidding me&#x201D; on the way to Codegarden.&#xA;&#xA;Then: Codegarden.&#xA;&#xA;&#x1F37F; Hit play to see how quickly travel stress turned into community vibes, new friendships, and a reminder that Codegarden isn&#x2019;t just an event.&#xA;&#xA;It&#x2019;s a family reunion that keeps growing &#x1FAF6;&#xA;&#xA;And before your grandma out-plans you and claims that prime summer weekend for her 90th birthday, lock your calendar for 2027: &#x1F475;&#x1F94A;&#xA;&#xA;&#x1F4CD; &#xD8;ksnehallen, Copenhagen &#x1F3F0;&#xA;&#x1F4C5; June 9&#x2013;10, 2027 &#x1F986;&#x1F1E9;&#x1F1F0;]]></description>
                    <pubDate>Thu, 18 Jun 2026 10:39:22 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/june/codegarden-2026/</guid>
                    <title>Codegarden 2026 recap</title>
                    <link>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/june/codegarden-2026/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Thu, 18 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owaincodes.uksouth01.umbraco.io/blog/2026/june/codegarden-2026/</guid>
                    <title>Codegarden 2026 recap</title>
                    <link>https://owaincodes.uksouth01.umbraco.io/blog/2026/june/codegarden-2026/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Thu, 18 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/lait.umbraco.search.typesense</guid>
                    <title>Lait.Umbraco.Search.Typesense</title>
                    <link>https://marketplace.umbraco.com/package/lait.umbraco.search.typesense</link>
                    <description><![CDATA[An extension for Umbraco CMS providing a custom search engine integration with Typesense.]]></description>
                    <pubDate>Thu, 18 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/oc.automate.bluesky</guid>
                    <title>OC.Automate.Bluesky</title>
                    <link>https://marketplace.umbraco.com/package/oc.automate.bluesky</link>
                    <description><![CDATA[Bluesky connection type and action for Umbraco Automate. Post to Bluesky as part of an automation workflow.]]></description>
                    <pubDate>Thu, 18 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/june/codegarden-2026/</guid>
                    <title>Codegarden 2026 recap</title>
                    <link>https://owain.codes/blog/2026/june/codegarden-2026/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Thu, 18 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://medium.com/@ravimotha/codegarden-26-a-review-aa35c60e3b08?source=rss------umbraco-5</guid>
                    <title>Codegarden 26 : a review</title>
                    <link>https://medium.com/@ravimotha/codegarden-26-a-review-aa35c60e3b08?source=rss------umbraco-5</link>
                    <description><![CDATA[&lt;div class=&quot;medium-feed-item&quot;&gt;&lt;p class=&quot;medium-feed-image&quot;&gt;&lt;a href=&quot;https://medium.com/@ravimotha/codegarden-26-a-review-aa35c60e3b08?source=rss------umbraco-5&quot;&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/2160/1*toX2D2qIoJiKh7DBjvlAoQ@2x.jpeg&quot; width=&quot;2160&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;medium-feed-snippet&quot;&gt;Photo by Lukas Rychvalsky on Unsplash&lt;/p&gt;&lt;p class=&quot;medium-feed-link&quot;&gt;&lt;a href=&quot;https://medium.com/@ravimotha/codegarden-26-a-review-aa35c60e3b08?source=rss------umbraco-5&quot;&gt;Continue reading on Medium &#xBB;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;]]></description>
                    <pubDate>Wed, 17 Jun 2026 17:42:48 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.jeroenbreuer.nl/blog/my-codegarden-2026-highlights/</guid>
                    <title>My Codegarden 2026 Highlights</title>
                    <link>https://www.jeroenbreuer.nl/blog/my-codegarden-2026-highlights/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 17 Jun 2026 12:51:39 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://jcdc.dev/blog/umbraco-package-automate-inspector</guid>
                    <title>Umbraco Package: Automate Inspector</title>
                    <link>https://jcdc.dev/blog/umbraco-package-automate-inspector</link>
                    <description><![CDATA[Explore everything Umbraco Automate has to offer with this new community package!]]></description>
                    <pubDate>Wed, 17 Jun 2026 07:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.youtubepicker</guid>
                    <title>Umbraco.Community.YouTubePicker</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.youtubepicker</link>
                    <description><![CDATA[Custom Umbraco datatype to enable editors to pick YouTube videos or playlists from a specific YouTube channel. You&#x27;ll need a Google account and signup for an API key before you can use it.]]></description>
                    <pubDate>Wed, 17 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://codeshare.co.uk/blog/my-codegarden-2026-experience/</guid>
                    <title>My Codegarden 2026 Experience</title>
                    <link>https://codeshare.co.uk/blog/my-codegarden-2026-experience/</link>
                    <description><![CDATA[My Codegarden 2026 experience: keynotes, talks, awards, and the moments that reminded me why this community matters. Nine years, still getting goosebumps.]]></description>
                    <pubDate>Tue, 16 Jun 2026 02:57:14 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/esatto.umbraco.backoffice.contenttreedraganddrop</guid>
                    <title>Esatto.Umbraco.Backoffice.ContentTreeDragAndDrop</title>
                    <link>https://marketplace.umbraco.com/package/esatto.umbraco.backoffice.contenttreedraganddrop</link>
                    <description><![CDATA[Native HTML5 drag-and-drop for the Umbraco 17 backoffice Content tree. Adds three-zone (above / into / below) drop targets per row with optimistic same-parent reorder and full cross-parent move support. Pure App_Plugins package &#x2014; no C# code.]]></description>
                    <pubDate>Tue, 16 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umcontentgenerator</guid>
                    <title>umContentGenerator</title>
                    <link>https://marketplace.umbraco.com/package/umcontentgenerator</link>
                    <description><![CDATA[AI-powered content generation for Umbraco: create fully-populated Block Grid and Block List pages &#x2014; text and images &#x2014; base on template page and short promt, powered by OpenAI.]]></description>
                    <pubDate>Tue, 16 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://aaronsadler.dev/blog/2026/june/16/codegarden-2026-i-went-to-copenhagen-for-a-week</guid>
                    <title>Codegarden 2026: I went to Copenhagen for a week</title>
                    <link>https://aaronsadler.dev/blog/2026/june/16/codegarden-2026-i-went-to-copenhagen-for-a-week</link>
                    <description><![CDATA[My week in Copenhagen for Codegarden 2026: the MVP Summit, the launch of Umbraco Automate, the sessions that stood out, and why I keep coming back. &lt;a href=&quot;https://aaronsadler.dev/blog/2026/june/16/codegarden-2026-i-went-to-copenhagen-for-a-week&quot;&gt;Continue reading&lt;/a&gt;]]></description>
                    <pubDate>Tue, 16 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://dev.to/luukpeters/tiptap-is-not-broken-your-expectations-are-5h8m</guid>
                    <title>TipTap is not broken. Your expectations are.</title>
                    <link>https://dev.to/luukpeters/tiptap-is-not-broken-your-expectations-are-5h8m</link>
                    <description><![CDATA[&lt;p&gt;Since the Umbraco 16 release, Umbraco ships only with the TipTap Rich Text Editor. This was unfortunately something that Umbraco was forced to do. TinyMce 7 has a license that is incompatible with the open source license of Umbraco and TinyMce 6 was going out of support. So an alternative had to be found.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Umbraco did a pretty good job at abstracting the rich text data. In Umbraco 15 both TinyMCE and TipTap were still present and exchangeable because of this abstraction. And arguably, the way you can set up your toolbars for the TipTap editor is superior to TinyMCE. But still, a new Rich Text Editor is a big change that presents real challenges.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;These challenges are most obvious when looking at the Umbraco forum&#x27;s &lt;a href=&quot;https://forum.umbraco.com/tag/tip-tap/78&quot; rel=&quot;noopener noreferrer&quot;&gt;tip-tap tag&lt;/a&gt;. Topics vary, but a few come up again and again:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Additional HTML tags getting added to the markup, like a &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag inside a &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;The inability to add certain tags to TipTap, like &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags&lt;/li&gt;&#xA;&lt;li&gt;The inability to add styling to an element, for instance to create a link that looks like a button&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;These are valid challenges, especially if you&#x27;re upgrading from an existing TinyMCE setup. But this is also a good moment to ask two questions:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Why&lt;/strong&gt; do I want the same behaviour?&lt;/li&gt;&#xA;&lt;li&gt;And was the old behaviour actually any good to begin with?&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  You don&#x27;t have to migrate everything at once&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Before getting into that, it&#x27;s worth knowing that TinyMCE is still available as a community package for Umbraco 16&#x2B;. If you&#x27;re in the middle of a project, dealing with a large codebase, or just not ready to rethink your Rich Text Editor setup right now, that&#x27;s a valid escape hatch. Swap in the package, keep things running, and give yourself time to migrate properly.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;But &quot;later&quot; should still be on the roadmap. The package is community maintained, not an official Umbraco product, so there are no guarantees around long-term support or compatibility with future Umbraco versions. Relying on it indefinitely carries the same risk as the situation Umbraco just came out of with TinyMCE 6.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;So use it if you need to. Just don&#x27;t treat it as a permanent solution.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The RTE is not a page builder&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;I&#x27;m not a big fan of giving editors too much freedom in a Rich Text Editor. Don&#x27;t get me wrong, RTEs are great and help editors a lot. But give too much rope and things go wrong fast. My preference is for RTEs to handle the basics: adding a link, making text bold or italic, maybe a table if the frontend deals with it gracefully on mobile.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;What I don&#x27;t like is image placement and scaling inside an RTE. Without proper processing this is a problem for performance and mobile layouts. I also don&#x27;t like HTML snippets or trying to add CSS classes to elements from within an editor. It&#x27;s error prone, and if something breaks, you need HTML knowledge to fix it. That&#x27;s not a realistic expectation for most editors.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;So when people ask how to replicate that kind of behaviour in TipTap, I&#x27;d rather ask why they need it at all.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Stop fighting the editor, start working with Umbraco&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Instead of trying to make TipTap behave like TinyMCE did, consider using the tools Umbraco already gives you.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Need a link that looks like a button? Use a block inside the Rich Text Editor. TipTap has solid block support, and Umbraco exposes this well. You get a structured piece of content with its own view, its own properties, fully typed, fully renderable. An editor picks a &quot;Button&quot; block, fills in the label and the link and that&#x27;s it. No CSS classes, no raw HTML, no risk of someone pasting &lt;code&gt;style=&quot;color:red&quot;&lt;/code&gt; into a script tag three months later.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Need a pull quote, a callout, a code snippet with syntax highlighting? Same answer. Model it as a block. Render it properly. Keep the RTE itself lean.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The argument I keep hearing is that recreating all of this takes more time than just making the old thing work again. That&#x27;s sometimes true in the short term. But you&#x27;re building something more maintainable, more predictable and more editor-friendly.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;There&#x27;s another reason to think twice before pouring effort into recreating editor-specific behaviour: Umbraco has already switched its default Rich Text Editor once. It could happen again. If your implementation leans heavily on workarounds and editor-specific quirks, you&#x27;re setting yourself up for the same migration pain all over again. If instead your RTE is kept lean and the complex bits live in blocks with their own models and views, a future editor switch becomes much less of an event. The RTE just renders text. Everything interesting is already abstracted away.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  What about the extra markup?&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; inside &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; is worth addressing separately, because it looks like a bug but it isn&#x27;t. TipTap is built on ProseMirror, which uses a strict document schema where every node needs to contain the right type of child node. For list items, that child is a block node and a paragraph is that block node. This is what makes editing reliable: without it, you can end up in situations where the cursor can&#x27;t be placed inside a list item at all, or where deleting an item breaks unexpectedly.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This behaviour is not unique to TipTap. Any editor built on ProseMirror does the same thing, and that includes quite a few well-known ones. TinyMCE handled lists differently, but that doesn&#x27;t make TinyMCE&#x27;s approach the correct one.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;If your frontend CSS breaks because of this, that&#x27;s a one-time fix, typically just adjusting margin or display rules on &lt;code&gt;li p&lt;/code&gt;. Once it&#x27;s done, you&#x27;re working with markup that is actually more structurally consistent than what TinyMCE produced.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Closing thought&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;A new editor is disruptive. But disruption is also a chance to reconsider decisions that were made years ago under different constraints, maybe with less knowledge of what Umbraco could do, or just because TinyMCE made it easy and easy felt like good enough.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;TipTap is not TinyMCE. It&#x27;s not trying to be. And once you stop expecting it to be, you might find it pushes you toward solutions that are cleaner, better structured and easier to hand off to an editor who has no idea what a DOM is.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Work with the grain of the tool, not against it.&lt;/p&gt;]]></description>
                    <pubDate>Mon, 15 Jun 2026 12:47:24 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://codeshare.co.uk/blog/how-i-hacked-the-sticker-printers-at-codegarden-2026/</guid>
                    <title>How I Hacked the Sticker Printers at Codegarden 2026</title>
                    <link>https://codeshare.co.uk/blog/how-i-hacked-the-sticker-printers-at-codegarden-2026/</link>
                    <description><![CDATA[Discover how constraints sparked innovation at Codegarden 2026. I bypassed printer limitations using only my phone and creative problem-solving techniques.]]></description>
                    <pubDate>Mon, 15 Jun 2026 10:29:21 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.nevitech.co.uk/blog/codegarden-2026-a-week-in-copenhagen-i-wont-forget/</guid>
                    <title>Codegarden 2026: A Week in Copenhagen I Won&#x27;t Forget</title>
                    <link>https://www.nevitech.co.uk/blog/codegarden-2026-a-week-in-copenhagen-i-wont-forget/</link>
                    <description><![CDATA[Just back from @umbraco.com Codegarden in Copenhagen, and what a week! &#x1F389;&#xA;&#xA;I was awarded Umbraco MVP 2026, did a demo in the keynote, and won the AI Package Award too. Still feels surreal. &#x1F3C6;&#xA;&#xA;Read more in the blog post.&#xA;&#xA;www.nevitech.co.uk/blog/codegar...&#xA;&#xA;#Umbraco #Codegarden&#xA;&#xA;]]></description>
                    <pubDate>Mon, 15 Jun 2026 10:19:36 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@owaincodes/116753175751677147</guid>
                    <title>New release for umbPublisher 1.5.1</title>
                    <link>https://umbracocommunity.social/@owaincodes/116753175751677147</link>
                    <description><![CDATA[New release for umbPublisher 1.5.1Tags that are set in #obsidian can now be mapped to #umbraco property editor. Available on https://community.obsidian.md/plugins/umbpublisher]]></description>
                    <pubDate>Mon, 15 Jun 2026 08:43:36 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://dev.to/d_inventor/i-attended-umbraco-codegarden-2026-5dak</guid>
                    <title>I attended Umbraco Codegarden 2026!</title>
                    <link>https://dev.to/d_inventor/i-attended-umbraco-codegarden-2026-5dak</link>
                    <description><![CDATA[&lt;p&gt;Codegarden was last week in Copenhagen! I was there this time and here are my thoughts about the event. Previous time I attended was in 2023, so I will draw some comparisons to that year. It was a great experience and I left feeling generally excited and inspired.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Organization&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Just like previous time, the event was very well-organized. At Codegarden, you&#x27;re always well taken care of with lunch and dinner, great instructions, a little kick-off at the start of every day and a lot of spatial diversity. You always know what to expect.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;I was very happy to see that the quiet area was easy to find and it was mentioned at the beginning of the event. The previous time I didn&#x27;t know that such a quiet area existed and I spoke out about that. It gave me comfort that I knew where to retreat to when I needed to. Additionally, there were many places to stand or sit outside and inside. The event was also a little shorter, which made it more manageable for me.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The location was absolutely ideal for the amount of people that attended. There were many attendees (about 700 they said, if I remember correctly), but at no point did the venue feel crowded. I could always easily get to where I wanted to go, there were no long queues and there was always enough seats for all the talks at every stage.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Talks&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;I&#x27;ll admit that, on the previous Codegarden, I had the wrong expectations for the talks. Talks are obviously aimed at specific target audiences and I don&#x27;t belong to all of them. Some talks aim to inform, while others aim to inspire. Stories are not tutorials. Also, sometimes a talk doesn&#x27;t teach you something new, but simply validates what you were already doing.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;So it was this time too. My focus is currently shifting slightly away from coding and more towards collaboration and I am looking for inspiration on how to deliver better software faster. I specifically wanted to attend &lt;em&gt;Debugging Teams: What High-Performing Developer Teams Do Differently&lt;/em&gt;, because it seemed relevant to me. Although I was hoping for a deep analysis in development process and teamwork strategies, I ended up learning about the importance of trust and of sharing the &quot;what&quot;, &quot;how&quot; and &quot;why&quot; of what we do. It surely gave me something to think about.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;I listened to &lt;em&gt;Building Resilient Umbraco Integrations&lt;/em&gt;. A more tutorial-style demonstration with insightful information about what you need to think about when integrating with external services. The presentation included concrete code examples that gave concrete solutions to the presented problems. I personally already knew all of it, but it was nice to see anyway, because it confirms that I&#x27;m already doing it right.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;A special mention goes to Semira Allen and Jason Wodicka with their talks &lt;em&gt;Drowning in Details: Turning TechTalk Into Everyday Language&lt;/em&gt; and &lt;em&gt;How (not) to mess up everything&lt;/em&gt;. Their talks were incredibly engaging and they were a joy to listen to. I had a good laugh and they were each inspiring in their own ways.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Some additional thoughts&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Copenhagen:&lt;/strong&gt; The fact that it was in Copenhagen was what made me consider it again. I am not big on traveling abroad and the trip to Odense and back was seriously daunting. Being able to get there with just the airplane made the whole trip so much better!&lt;br&gt;&#xA;&lt;strong&gt;AI:&lt;/strong&gt; I haven&#x27;t mentioned AI in this blog. That&#x27;s because I find the ethics of the application of AI at the moment very questionable. I am still working on forming a well-informed opinion. Umbraco and the community have showcased some very impressive work with AI.&lt;br&gt;&#xA;&lt;strong&gt;Umbraco awards:&lt;/strong&gt; In case you didn&#x27;t know it yet: we were nominated for an Umbraco award for &quot;Accessibility and Security&quot;! Even though we didn&#x27;t win the award, I believe that our submission was still the best. The winning solution had a more visible approach to accessibility, but we can show off a real certification of accessibility with end-user testimonies to back it up. The nomination is a nice validation of my team&#x27;s hard work.&lt;br&gt;&#xA;&lt;strong&gt;Umbraco in the bigger picture?&lt;/strong&gt; Right now I am learning from people like &lt;a href=&quot;https://www.youtube.com/@ModernSoftwareEngineeringYT&quot; rel=&quot;noopener noreferrer&quot;&gt;Dave Farley&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/@EmilyBache-tech-coach&quot; rel=&quot;noopener noreferrer&quot;&gt;Emily Bache&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/channel/UC3RKA4vunFAfrfxiJhPEplw&quot; rel=&quot;noopener noreferrer&quot;&gt;Derek Comartin&lt;/a&gt; about better software development practices. Some of it is more about architecture and some of it is about collaboration and process. I feel like these topics deserve more attention in the Umbraco community. I need a talk named &lt;em&gt;How I upgraded my mid-size web agency from feature branch and PR drag to real CI/CD&lt;/em&gt;. Maybe I get to give this talk myself one day, who knows.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Conclusion&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;It was a great event, and I&#x27;m very happy that I could be there. If it&#x27;s like this again next year, then I will be eager to attend. Thank you Umbraco for everything!&lt;/p&gt;]]></description>
                    <pubDate>Mon, 15 Jun 2026 07:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/june/ocautomatemastodon-released/</guid>
                    <title>OC.Automate.Mastodon released</title>
                    <link>https://owain.codes/blog/2026/june/ocautomatemastodon-released/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 15 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/esatto.umbraco.backoffice.sharedpreviewlink</guid>
                    <title>Esatto.Umbraco.Backoffice.SharedPreviewLink</title>
                    <link>https://marketplace.umbraco.com/package/esatto.umbraco.backoffice.sharedpreviewlink</link>
                    <description><![CDATA[Shareable preview links for Umbraco 17. Editors mint a tokenized URL via a workspace-action button; recipients open the URL externally and see the current draft (no backoffice login). Tokens are 7-day data-protected; recipient cookie scopes preview to the specific page for 5 minutes.]]></description>
                    <pubDate>Mon, 15 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://owaincodes.uksouth01.umbraco.io/blog/2026/june/ocautomatemastodon-released/</guid>
                    <title>OC.Automate.Mastodon released</title>
                    <link>https://owaincodes.uksouth01.umbraco.io/blog/2026/june/ocautomatemastodon-released/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 15 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/oc.automate.mastodon</guid>
                    <title>OC.Automate.Mastodon</title>
                    <link>https://marketplace.umbraco.com/package/oc.automate.mastodon</link>
                    <description><![CDATA[Mastodon connection type and action for Umbraco Automate. Post statuses to any Mastodon instance as part of an automation workflow.]]></description>
                    <pubDate>Mon, 15 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/june/ocautomatemastodon-released/</guid>
                    <title>OC.Automate.Mastodon released</title>
                    <link>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/june/ocautomatemastodon-released/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 15 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/across-the-himalayas-and-into-the-heart-of-umbraco/</guid>
                    <title>Across the Himalayas and Into the Heart of Umbraco</title>
                    <link>https://umbraco.com/blog/across-the-himalayas-and-into-the-heart-of-umbraco/</link>
                    <description><![CDATA[Meet Rashmita and Jasper, the founders of One Tech Nepal. Discover how they use their 100% Umbraco agency to fund IT education and libraries in remote Himalayan schools.]]></description>
                    <pubDate>Mon, 15 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://blog.aabech.no/archive/introducing-larsingerlogue-cv-5000/</guid>
                    <title>Introducing Larsingerlogue CV-5000</title>
                    <link>https://blog.aabech.no/archive/introducing-larsingerlogue-cv-5000/</link>
                    <description><![CDATA[&lt;h2&gt;Or how I gave Behringer FCV100 the reference power supply it deserves to use for CV-modulation with Korg Minilogue XD&lt;/h2&gt;&#xA;&lt;p&gt;&lt;em&gt;If you&#x27;re here to solve the problem and don&#x27;t care for a story, keep scrolling, you&#x27;ll get to schematics, breadboard pictures and an ingredient list.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;There&#x27;s also a &lt;a href=&quot;#video-montage&quot;&gt;short video montage&lt;/a&gt; for the even more impatient.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&quot;https://blog.aabech.no/media/1080/intro-image.png&quot; alt=&quot;A logo with the text Larsingerlogue CV-5000 and an FCV100 connected to a gray box&quot; /&gt;&lt;/p&gt;&#xA;&lt;p&gt;This is quite a different post than I usually make, if I&#x27;m allowed to call it usually anymore at all. In any case, I&#x27;ve been playing the keys in a band for a couple of years and have yearned for a proper synth to supplement my (6) master keyboards. Recently I acquired my first ever analogue synthesizer. It only took 40 years for the dream to come through. I found a 15% cheaper second hand &amp;quot;unused&amp;quot; Korg Minilogue XD. But I only had damper pedals to use with it. Half the fun of synthesizers for me is varying the low pass filter cutoff. It&#x27;s what gives that cool swiping, buzzing or muffled sound depending on how you &amp;quot;turn&amp;quot; it. For that I needed another type of pedal, and not just a regular one.&lt;/p&gt;&#xA;&lt;p&gt;The Minilogue has a ton of hand-controlled potentiometer knobs we can use for a multitude of parameters, amongst others the filter cutoff. However it does not have a regular 1/4&amp;quot; jack slot for expression pedals like keyboards usually have. It has a damper slot, but only for CC64 on/off (sustain on and off). What we want is a full, preferably analogue, range from 0 to 100%. Expression pedals are excellent for this since they&#x27;re basically pot meters you turn with your foot.&lt;/p&gt;&#xA;&lt;p&gt;What the Minilogue comes with are two 1/8&amp;quot; jack &amp;quot;CV in&amp;quot; ports. So I browsed the interwebz for &amp;quot;CV pedal&amp;quot; and found a bunch of alternatives. Since I&#x27;m eyeing a Behringer Poly D come fall I thought the Behringer FCV100 V2 pedal seemed a good deal. It&#x27;s advertised as a volume pedal with a CV option, including reversing polarity. So I ordered one and excitedly unpacked it while the band leader ran out to buy the last 1/8&amp;quot; to 1/8&amp;quot; cable and a 1/8&amp;quot; to 1/4&amp;quot; adapter. I&#x27;d dutifully inserted a 9V battery and optimistically hooked everything up...&lt;/p&gt;&#xA;&lt;p&gt;Nothing!&lt;/p&gt;&#xA;&lt;p&gt;I tried both CV inputs, both polarities, tons of options on the minilogue, but still nothing.&lt;br /&gt;&#xA;When I got home - I plugged a 1/8&amp;quot; into the &lt;em&gt;input&lt;/em&gt; port which according to the interwebs should &amp;quot;power it on&amp;quot;. Still nothing from the CV output. And yes, I &lt;em&gt;had&lt;/em&gt; measured the voltage on the 9V battery.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note: I have had no ambition doing electronics &amp;quot;right&amp;quot; with this project, nor writing a proper tutorial with a &amp;quot;right&amp;quot; way of doing it. This is a story about fiddling around and getting things to work. It is &lt;em&gt;not&lt;/em&gt; a tutorial in proper electronics, in fact almost the opposite. I have not bothered to look up facts or calculated things. This means people who know their way around electronics might find this article revolting. I&#x27;m sorry. It was a way for me to brush up on how things work and get something working quickly. DIY by fiddling around until it works. Again, sorry, but hopefully other learners might be inspired to both fiddle around &lt;em&gt;and&lt;/em&gt; learn to do the calculations. There&#x27;s even a gem of an insight in the end that only hit me while writing this post. &#x1F607;&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&lt;h2&gt;The research&lt;/h2&gt;&#xA;&lt;p&gt;According to the interwebz, someone claimed to have gotten CV output when they had plugged an unconnected 1/8&amp;quot; jack into input 2, but showed no proof or measurements. The next answer was someone who had done some due dilligence and measured the output. Apparently it only works with instruments that feed a reference voltage from its control voltage (CV) &lt;em&gt;input&lt;/em&gt; in order for the pedal to vary it.&lt;/p&gt;&#xA;&lt;p&gt;So I dug out my trusty old multimeter and started the process of dusting off the parts of my brain still remembering reading &lt;a href=&quot;https://www.goodreads.com/book/show/10796575-there-are-no-electrons&quot;&gt;&amp;quot;There are no Electrons: Electronics for Earthlings&amp;quot;&lt;/a&gt; ten plus years ago. I learned about what tip, ring and sleeve (TRS) for jack plugs are, and all the other variants. Measuring DC between the tip and sleeve of the unconnected side of the cable when pressing the pedal did absolutely nothing. Measuring resistance though showed a varying impedance of 0 through 50k&#x3A9;. If I flipped between TRS and RTS mode on the pedal it seemingly reversed the resistance on the ring, but the tip stayed fixed on 50k&#x3A9; in TRS mode. In any case, after some brain clearing with ChatGPT, I could conclude that the pedal in CV mode is &lt;em&gt;only&lt;/em&gt; a 50k&#x3A9; potmeter and does not provide any of the sweet power from the (now useless) 9V battery I had inserted.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;Note: I&#x27;ve left the pedal in RTS mode. In order to use both and reverse polarity there&#x27;s more research and a V2 to be built. See closer to the end for a short rant about the factory presets in Minilogue XD.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;I figured there has to be a way to provide that power even if the synth doesn&#x27;t. So after a little more chatting with ChatGPT I figured I could dig through all my old cables and adapters to find an USB cable and adapter we&#x27;re not using. I should be able to &amp;quot;inject&amp;quot; it&#x27;s 5V DC voltage into the jack cable instead of relying on the synth to provide it. I dug through all my treasure drawers and found an USB mini-B 4-pin (?) to USB A cable and cut off the mini-B plug to reveal the two VCC/GND cables and two data cables. I found a couple of horribly old AC USB adapters and measured the DC from both via the cable&#x27;s red (VCC) and black (GND) wires. One gave 3.3V and the other gave 5V. I happily threw the overdue 3.3V one in the &amp;quot;to recycling&amp;quot; bin and rubbed my hands together over the other. (Throwing out one old device should score me at least one plus in the wife&#x27;s accounting system.)&lt;/p&gt;&#xA;&lt;h2&gt;Specifications&lt;/h2&gt;&#xA;&lt;p&gt;Of course it&#x27;s prudent to actually check the specs of the hardware you&#x27;re trying to shove a current into. So I dug up the details in the manuals, which to be honest are both quite a tad more than averagely vague about how to connect control voltage hardware.&lt;/p&gt;&#xA;&lt;p&gt;The Minilogue XD manual has the following gem of a CV mention:&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;CV IN 1 and 2 jacks (3.5 mm monaural mini-phone jack; input voltage: &#x2013;5V to 5V in modulation mode, &#x2013;3V to 5V in CV/gate mode)&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;So I figured I&#x27;m safe proceeding with my 0-5V endeavour. We &lt;em&gt;are&lt;/em&gt; going to use it for modulation.&lt;/p&gt;&#xA;&lt;p&gt;The FCV100 manual has a similarly brief description of it&#x27;s &amp;quot;CV&amp;quot; output:&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;1/4&amp;quot; TS - unbalanced Tip: Supply volt. from unit/instr. to be controlled: Impedance: 50kOhm Ring: Slider pick-up (CV dependend on ped. position, impedance: 0-50kOhm)&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;There&#x27;s some more specs around 2V and output impedance, but as far as I&#x27;ve understood that&#x27;s all about the volume control feature of the pedal. I have a hard time interpreting whether that sentence says &amp;quot;bring your own power&amp;quot; or &amp;quot;we&#x27;ll use the battery you inserted&amp;quot;.&lt;/p&gt;&#xA;&lt;p&gt;Having this information and some support from the [un]trusty LLM though, I pressed on to simulating the imagined setup.&lt;/p&gt;&#xA;&lt;h2&gt;Tinkering&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&quot;https://www.tinkercad.com/&quot;&gt;Tinkercad&lt;/a&gt; is an awesome tool for budding DYIers wanting to learn or experiment with electronics. Especially if starting to experiment with arduinos or other consumer grade microcontrollers. I could safely experiment with placement of the resistors and different resistance values and until I got the desired voltage output on the simulator&#x27;s multimeter.&lt;/p&gt;&#xA;&lt;p&gt;In place of the pedal I added a regular pot meter. It has three pins which is basically a 1:1 representation of the tip, ring and sleeve on a jack plug. The middle pin is the &amp;quot;wiper&amp;quot;, which I&#x27;d measured on the pedal to output a varying resistance between the ring and sleeve on the opposite end of the jack cable.&lt;br /&gt;&#xA;Back and forth with GPT and the multimeter for a while made me understand that the CV input on the Minilogue likely has an internal 1M&#x3A9; or larger resistor, just like a multimeter has. That&#x27;s how it&#x27;s able to read the voltage loss between the sides and thereby also receive the varying &amp;quot;control voltage&amp;quot; input from the pedal.&lt;/p&gt;&#xA;&lt;p&gt;Tinkercad also sports a USB connector and all the resistors you can dream of. And that&#x27;s the whole recipe for this &amp;quot;CV adapter&amp;quot;. It took some time to remember my URIs (Ohm&#x27;s law) and how things affect the dance of the electrons (or little green men if you prefer). To be honest I still don&#x27;t really know, but fiddling and discussing with GPT got me to something that works with a fair understanding. Mr. GPT had suggested a 50 k&#x3A9; resistor between the pedal and synth, but the simulations led me to choose a 10 k&#x3A9;. Again, the learned and/or dilligent would bother to calculate why.&lt;/p&gt;&#xA;&lt;p&gt;The ingredients for the simulation ended up as follows:&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Name&lt;/th&gt;&#xA;&lt;th&gt;Value&lt;/th&gt;&#xA;&lt;th&gt;Description&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&lt;tr&gt;&#xA;&lt;td&gt;USB Standard A&lt;/td&gt;&#xA;&lt;td&gt;-&lt;/td&gt;&#xA;&lt;td&gt;USB connector. It gives 5V in the simulator as expected.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Resistor A&lt;/td&gt;&#xA;&lt;td&gt;150 &#x3A9; &lt;br&gt;(several&amp;nbsp;tries)&lt;/td&gt;&#xA;&lt;td&gt;A resistor to limit the circuit current slightly from the USB output. Just to be precaucious.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Resistor B&lt;/td&gt;&#xA;&lt;td&gt;10 k&#x3A9;&lt;/td&gt;&#xA;&lt;td&gt;A resistor to protect and limit the current going into the synth. (We&#x27;d rather not blow it up...)&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Fake CV in port&lt;/td&gt;&#xA;&lt;td&gt;1 M&#x3A9;&lt;/td&gt;&#xA;&lt;td&gt;A resistor representing the internal impedance of the synth&#x27;s CV sensor and the tip (VCC) and sleeve (GND) of the jack plug.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Multimeter&lt;/td&gt;&#xA;&lt;td&gt;-&lt;/td&gt;&#xA;&lt;td&gt;A multimeter in resistance mode measuring the loss over the &quot;fake CV in port&quot; resistor.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Fake pedal&lt;/td&gt;&#xA;&lt;td&gt;50 k&#x3A9;&lt;/td&gt;&#xA;&lt;td&gt;A potentiometer representing the pedal and the tip (VCC), ring (CV out), and sleeve (GND) of the jack plug.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&lt;/table&gt;&#xA;&lt;hr /&gt;&#xA;&lt;p&gt;Here&#x27;s the breadboard layout:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&quot;https://blog.aabech.no/media/1074/larsingerlogue-breadboard-tinkercad.png&quot; alt=&quot;A breadboard layout representing the pedal, extra parts and synth&quot; /&gt;&lt;/p&gt;&#xA;&lt;p&gt;I&#x27;m extremely discontent with how Tinkercad figured to lay out the schematic, but in any case I suppose it is correct. Why couldn&#x27;t the pot go straight to the 10k resistor? Oh well, here&#x27;s it is in all it&#x27;s jumbled glory:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&quot;https://blog.aabech.no/media/1077/larsingerlogue-schematic-tinkercad.png&quot; alt=&quot;An electronic shematic representing the pedal, extra parts and synth&quot; /&gt;&lt;/p&gt;&#xA;&lt;h2&gt;Prototyping and building in real life&lt;/h2&gt;&#xA;&lt;p&gt;Having the simulation show thumbs up I figured I should try it in real life and do some measurements before hooking anything up to my brand new synth. For some reason Tinkercad shows a tiny explosion on the USB connector when the simulation starts, but my adapter stood the test and I suspect there might be a bug with the implementation on Tinkercad. &#x1F607;&lt;/p&gt;&#xA;&lt;p&gt;I have both breadboards and a plethora of resistors lying around from my Arduino adventures last decade. Finding a breadboard and some resistors didn&#x27;t bide much problem. They&#x27;re all within arms length to my left. But this is where I started going back and forth between the breadboard and Tinkercad. Turns out real life didn&#x27;t give the same measurements as the simulation. Even if I used a PSU of 5.5V instead of a USB connector. My adapter gives 5.5V, remember?&lt;/p&gt;&#xA;&lt;p&gt;Here&#x27;s a little montage of all the crocodiles holding things together.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&quot;https://blog.aabech.no/media/1073/larsingerlogue-breadboard-prototype.png&quot; alt=&quot;Picture montage showing a breadboard, wires, crocodile clips and a multimeter&quot; /&gt;&lt;/p&gt;&#xA;&lt;p&gt;After a while I had the right resistors to see 0-5V on the multimeter having hooked up the pedal to my shortest mangled jack-cable. I excitedly hooked up some crocodiles to the other half-jack and the breadboard, wearily shoved the plug into my synth and tried the pedal. Sucess! The LCD-display on the synth showed 0 to ... 97%??? So even if the simulator and my multimeter showed I output 5V from the pedal when 100% down the Minilogue expects more. Anyone knowledgeable with electronics will likely know why, but I merely suspect that it somehow &amp;quot;feels&amp;quot; the max input from the source is 5.5V. So it was out with the jack, out with the GND crocodile and in and out with misc initial resistors until I saw 0-100% CV input on the synth. A 150 &#x3A9; resistor turned out to be the sweet spot.&lt;/p&gt;&#xA;&lt;p&gt;I now had proof I could build this &amp;quot;CV-adapter&amp;quot;, so it was time for V1.&lt;/p&gt;&#xA;&lt;h2&gt;Assembling V1&lt;/h2&gt;&#xA;&lt;p&gt;Again from my Arduino-days I found a few circuit boards in my drawers. The smallest ones were 24x18 holes (7x3cm) - a little big. But incidentally I could spot in the corner of my eye something resembling an Arduino-case.  The 7x3 board fits perfectly within, and it&#x27;s a slim one just 1.5cm tall. Perfect!&lt;/p&gt;&#xA;&lt;p&gt;On to the soldering. Not that I lacked any space, but it&#x27;s always nice not having to cross wires. Enter a slightly unorthodox tool, my favorite program in the whole world: Excel. Who needs technical drawing software when you have colorable cells? I first drew up the layout on the left, but inspecting the casing I&#x27;d found I figured I&#x27;d rather flip it around. So I ended up going for the layout on the right.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&quot;https://blog.aabech.no/media/1079/larsingerlogue_soldering_sketch.png&quot; alt=&quot;Excel sketches of the soldered circuit board&quot; /&gt;&lt;/p&gt;&#xA;&lt;p&gt;I&#x27;m extremely shaky, so soldering took its time. It&#x27;s somewhat of a Zen excercise I&#x27;ve never quite mastered. I also realized way too late (of course) that I&#x27;d been better off stretching a few more wires, but hey - it&#x27;s 10 years since last time I did anything like this.&lt;/p&gt;&#xA;&lt;p&gt;In any case, the first test with the multimeter and pedal showed a semi-constant 5.4V so I had to go back to the soldering board. A few connection tests with the trusty meter showed a lacking connection to ground from the pedal. Even with my new &amp;quot;computer glasses&amp;quot; &lt;em&gt;and&lt;/em&gt; a magnifyer on my little helper I couldn&#x27;t see that the amputated resistor leg I&#x27;d connected to ground wasn&#x27;t connected. But I could find the &lt;em&gt;spot&lt;/em&gt; where the connection ended, so I added kind of a highway of tin all the way. Success!&lt;/p&gt;&#xA;&lt;p&gt;Here&#x27;s how the circuitboard ended up.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&quot;https://blog.aabech.no/media/1078/larsingerlogue-soldered-circuit.png&quot; alt=&quot;Picture showing of a soldered circuit board&quot; /&gt;&lt;/p&gt;&#xA;&lt;p&gt;The final stretch was to have the board rest well within the box. I was lucky to find some double sided tape in the kitchen, and since one side of the board already rested slighly on the USB and jack cables I chuckled as I cut off another 2.5cm piece of the now 4cm long USB mini cord. It fit perfectly. Tape on the case, tape on the board, and a short piece of USB mini cord as a pillow.&lt;/p&gt;&#xA;&lt;p&gt;Here&#x27;s the final box.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&quot;https://blog.aabech.no/media/1076/larsingerlogue-final-box.png&quot; alt=&quot;Picture of a box connected to the FCV100&quot; /&gt;&lt;/p&gt;&#xA;&lt;h2&gt;Final fun&lt;/h2&gt;&#xA;&lt;p&gt;Of course my box needed a name and a logo. It didn&#x27;t take many brain-iterations until I landed on Larsingerlogue CV-5000. It&#x27;s &lt;em&gt;my&lt;/em&gt; [Behr]&lt;strong&gt;inger&lt;/strong&gt; [FCV100 to Mini]&lt;strong&gt;logue&lt;/strong&gt;[ XD] &lt;strong&gt;CV-5&lt;strong&gt;[V * 1]&lt;/strong&gt;000&lt;/strong&gt;[mA adapter]. I turned to my age old friend &amp;quot;Impact&amp;quot; and quickly found a fitting gradient in Photoshop.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&quot;https://blog.aabech.no/media/1075/larsingerlogue-cv-5000.png&quot; alt=&quot;Larsingerlogue CV-5000 logo in fat lettering with a retro colored gradient.&quot; /&gt;&lt;/p&gt;&#xA;&lt;h3&gt;Video montage&lt;/h3&gt;&#xA;&lt;p&gt;I&#x27;d also shot a couple of videos and pictures during the process, so I amused myself by throwing together a short video of the whole process. It features the first built in patch of Minilogue XD and it&#x27;s sample sequence with me &amp;quot;playing&amp;quot; the filter cutoff on the now functioning pedal, and the &amp;quot;riser&amp;quot; delay time and depth using my free hand. Farily cool. And then a quite off-beat attempt at the Stranger Things theme as an RL demo of the final product. Check it out.&lt;/p&gt;&#xA;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/nTTtX-T8_dE?si=M1ZUYMwnrk0mNLtL&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;&#xA;&lt;p&gt;I hope you&#x27;ve anjoyed following my little story of dipping my toes in electronics for music. There&#x27;s high potential for a V2 with better polarity support, and who knows what other ideas one might come up with for 100% &amp;quot;DIY&amp;quot; effects to shove into those CV inputs. There&#x27;s still one unused. &#x1F601;&lt;/p&gt;&#xA;&lt;h3&gt;Grief&lt;/h3&gt;&#xA;&lt;p&gt;My only grief, and that&#x27;s kind of connected to the single polarity of my adapter, is that &lt;em&gt;all&lt;/em&gt; of the built-in patches in the Minilogue XD are set to having CV 1 modulating the shape of VCO 1 from 0 to 100%, and CV 2 is set to filter cutoff from 0 to -100%. That means I open the filter by &amp;quot;closing&amp;quot; the pedal and close the filter by &amp;quot;opening&amp;quot; the pedal. Pedal to the floor means almost no audible sound.&lt;/p&gt;&#xA;&lt;h3&gt;Learning while blogging&lt;/h3&gt;&#xA;&lt;p&gt;In hindsight I think I just realized with writing this that 5V on the multimeter means (almost) &lt;em&gt;no&lt;/em&gt; power moves through the resistor, which is measured as 0V - while I&#x27;ve been reading 5V (loss) on the multimeter. That would explain the &amp;quot;weird&amp;quot; direction of the pot meter in the simulation that&#x27;d been bugging me. &#x1F923;&lt;/p&gt;&#xA;&lt;p&gt;But hey - adds to a fun story about learning and just jumping into the water.&lt;/p&gt;&#xA;&lt;p&gt;If you got this far I hope you had a chuckle, nodded or otherwise found this interesting.&lt;br /&gt;&#xA;Thanks a lot for reading, and have fun whatever endeavor led you to this post.&lt;/p&gt;]]></description>
                    <pubDate>Sun, 14 Jun 2026 21:24:09 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/esatto.umbraco.backoffice.dictionaryfiltervalues</guid>
                    <title>Esatto.Umbraco.Backoffice.DictionaryFilterValues</title>
                    <link>https://marketplace.umbraco.com/package/esatto.umbraco.backoffice.dictionaryfiltervalues</link>
                    <description><![CDATA[Extends the Umbraco 17 backoffice Dictionary section filter to also match translation VALUES, not just dictionary-item names. Useful for editors who remember a translated string but not the dictionary key. Adds one authenticated Management API endpoint and a backoffice entry point that re-points the built-in Dictionary collection&#x27;s data source at it &#x2014; no window.fetch patching, no anonymous endpoints.]]></description>
                    <pubDate>Sat, 13 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/esatto.umbraco.backoffice.customeditors</guid>
                    <title>Esatto.Umbraco.Backoffice.CustomEditors</title>
                    <link>https://marketplace.umbraco.com/package/esatto.umbraco.backoffice.customeditors</link>
                    <description><![CDATA[A library of reusable property editor UIs for the Umbraco backoffice. Ships an Encrypted Textbox editor (encrypts sensitive values at rest via ASP.NET Core Data Protection, masked on screen) and a Date Range editor (two inline calendars with start/end constraint, optional time and min/max bounds).]]></description>
                    <pubDate>Sat, 13 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=bmfrLgNfQ_g</guid>
                    <title>umbraCoffee - LIVE at #Codegarden 2026!</title>
                    <link>https://www.youtube.com/watch?v=bmfrLgNfQ_g</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Thu, 11 Jun 2026 10:52:11 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/im.umbraco.ai.local</guid>
                    <title>IM.Umbraco.AI.Local</title>
                    <link>https://marketplace.umbraco.com/package/im.umbraco.ai.local</link>
                    <description><![CDATA[Local LLM provider for Umbraco AI. Connects the Umbraco backoffice AI features (prompts, agents, Copilot, embeddings) to any OpenAI-compatible self-hosted server such as Ollama, LM Studio or vLLM &#x2014; no cloud account required.]]></description>
                    <pubDate>Thu, 11 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/ripplepreview</guid>
                    <title>RipplePreview</title>
                    <link>https://marketplace.umbraco.com/package/ripplepreview</link>
                    <description><![CDATA[See your actual pages while you edit them. Blocks render through your site&#x27;s own views, styles and scripts &#x2014; sections render whole with their children, carousels and animations run, and everything stays editable: hover to highlight a block inside the preview and click to open it.]]></description>
                    <pubDate>Thu, 11 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.aiagentmemory</guid>
                    <title>Umbraco.Community.AiAgentMemory</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.aiagentmemory</link>
                    <description><![CDATA[AI Agent Memory for Umbraco &#x2014; persistent memory &#x2B; learning layer for Umbraco&#x27;s AI agent stack. Editors give thumbs-up / thumbs-down feedback on agent runs via the AI Agent Feedback widget; the package indexes that feedback as searchable memory and injects it into subsequent runs so agents suppress false positives and reuse validated patterns. Composes on Umbraco.AI 1.8&#x2B; (vector store via Umbraco.AI.Search). Memory is off by default; per-agent opt-in via appsettings.json. Built for Umbraco v17&#x2B;.]]></description>
                    <pubDate>Thu, 11 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/the-umbraco-mvps-2026/</guid>
                    <title>The Umbraco MVPs 2026</title>
                    <link>https://umbraco.com/blog/the-umbraco-mvps-2026/</link>
                    <description><![CDATA[Meet our Umbraco MVPs for 2026. These are our Most Valuable People, people who have a passion for contributing to Umbraco and the Umbraco Community.]]></description>
                    <pubDate>Wed, 10 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/bt.redirectmanager</guid>
                    <title>BT.RedirectManager</title>
                    <link>https://marketplace.umbraco.com/package/bt.redirectmanager</link>
                    <description><![CDATA[Modern URL redirect manager for Umbraco 13 and 17. Manage 301, 302, 404, and 410 redirects from a clean backoffice dashboard with regex support, CSV import/export, and a built&#x2011;in test tool.]]></description>
                    <pubDate>Wed, 10 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/umbraco-awards-winners-2026/</guid>
                    <title>Umbraco Awards Winners 2026 &#x1F3C6;</title>
                    <link>https://umbraco.com/blog/umbraco-awards-winners-2026/</link>
                    <description><![CDATA[Umbraco Awards 2026 winners are announced! Discover the outstanding projects and celebrate the amazing work within the Umbraco ecosystem.]]></description>
                    <pubDate>Wed, 10 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/esatto.umbraco.backoffice.contenttreednd</guid>
                    <title>Esatto.Umbraco.Backoffice.ContentTreeDnd</title>
                    <link>https://marketplace.umbraco.com/package/esatto.umbraco.backoffice.contenttreednd</link>
                    <description><![CDATA[Native HTML5 drag-and-drop for the Umbraco 17 backoffice Content tree. Adds three-zone (above / into / below) drop targets per row with optimistic same-parent reorder and full cross-parent move support. Pure App_Plugins package &#x2014; no C# code.]]></description>
                    <pubDate>Wed, 10 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.deploy.automate</guid>
                    <title>Umbraco.Deploy.Automate</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.deploy.automate</link>
                    <description><![CDATA[Umbraco Deploy support for Umbraco Automate (artifacts, service connectors, triggers and actions).]]></description>
                    <pubDate>Wed, 10 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/umbraco-product-updatecodegarden-keynote-highlights-q2-2026/</guid>
                    <title>Umbraco Product Update/Codegarden Keynote Highlights, Q2 2026</title>
                    <link>https://umbraco.com/blog/umbraco-product-updatecodegarden-keynote-highlights-q2-2026/</link>
                    <description><![CDATA[Missed the Codegarden 2026 Keynote? Catch up on Umbraco&#x27;s Q2 product updates, including Umbraco Automate (new product!), CMS Elements, and Load Balancing for Cloud.]]></description>
                    <pubDate>Wed, 10 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.automate</guid>
                    <title>Umbraco.Automate</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.automate</link>
                    <description><![CDATA[Umbraco Automate]]></description>
                    <pubDate>Wed, 10 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/flowcourier.umbraco.cookieconsent</guid>
                    <title>Flowcourier.Umbraco.CookieConsent</title>
                    <link>https://marketplace.umbraco.com/package/flowcourier.umbraco.cookieconsent</link>
                    <description><![CDATA[A comprehensive cookie consent solution for Umbraco CMS with Google Consent Mode v2 support, customizable categories, and statistics tracking.]]></description>
                    <pubDate>Wed, 10 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.forms.automate</guid>
                    <title>Umbraco.Forms.Automate</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.forms.automate</link>
                    <description><![CDATA[Umbraco Forms triggers and actions for Umbraco Automate]]></description>
                    <pubDate>Wed, 10 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/crumpled.nostalgid</guid>
                    <title>Crumpled.Nostalgid</title>
                    <link>https://marketplace.umbraco.com/package/crumpled.nostalgid</link>
                    <description><![CDATA[...]]></description>
                    <pubDate>Wed, 10 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.search</guid>
                    <title>Umbraco.AI.Search</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.search</link>
                    <description><![CDATA[AI-powered vector search provider for Umbraco CMS]]></description>
                    <pubDate>Wed, 10 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.engage.automate</guid>
                    <title>Umbraco.Engage.Automate</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.engage.automate</link>
                    <description><![CDATA[Umbraco Engage triggers and actions for Umbraco Automate]]></description>
                    <pubDate>Wed, 10 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.workflow.automate</guid>
                    <title>Umbraco.Workflow.Automate</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.workflow.automate</link>
                    <description><![CDATA[Umbraco Workflow triggers for Umbraco Automate]]></description>
                    <pubDate>Wed, 10 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.commerce.automate</guid>
                    <title>Umbraco.Commerce.Automate</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.commerce.automate</link>
                    <description><![CDATA[Umbraco Commerce triggers and actions for Umbraco Automate]]></description>
                    <pubDate>Wed, 10 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.automate</guid>
                    <title>Umbraco.AI.Automate</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.automate</link>
                    <description><![CDATA[Umbraco Automate integration for Umbraco.AI.Agent]]></description>
                    <pubDate>Wed, 10 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://codeshare.co.uk/blog/how-to-add-giscus-comments-to-an-umbraco-site/</guid>
                    <title>How to add Giscus Comments to an Umbraco Site</title>
                    <link>https://codeshare.co.uk/blog/how-to-add-giscus-comments-to-an-umbraco-site/</link>
                    <description><![CDATA[Add Giscus comments to your Umbraco site with GitHub Discussions. Free, open-source comment system with no backend, privacy-friendly, and developer-native.]]></description>
                    <pubDate>Mon, 08 Jun 2026 01:18:50 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.cms.search.core</guid>
                    <title>Umbraco.Cms.Search.Core</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.cms.search.core</link>
                    <description><![CDATA[Umbraco Search provides an abstraction for search services in Umbraco, allowing for implementations using search providers such as Examine.]]></description>
                    <pubDate>Mon, 08 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.enkelmedia.se/blogg/2026/6/7/codegarden-talk-hybrid-cache-changes-everything?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=rss</guid>
                    <title>CodeGarden-talk: Hybrid Cache changes everything</title>
                    <link>https://www.enkelmedia.se/blogg/2026/6/7/codegarden-talk-hybrid-cache-changes-everything?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=rss</link>
                    <description><![CDATA[&lt;p&gt;I recently spent some time looking closer at the new &lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/performance/caching/hybrid&quot;&gt;HybridCache&lt;/a&gt; implementation in Umbraco to prepare for my presentation at &lt;a href=&quot;https://codegarden.umbraco.com/&quot;&gt;CodeGarden 2026&lt;/a&gt;, and the short version is this: it changes more than just the cache layer.&lt;/p&gt;&#xA;&lt;p&gt;Historically, Umbraco has been very good at keeping published content available in memory. That has made many common developer patterns feel cheap and convenient. Things like traversing content trees, using `.Children()`, `.Descendants()` and resolving references have often just worked without us thinking too much about the cost.&lt;/p&gt;&#xA;&lt;p&gt;With HybridCache, that mental model changes. The cache is still there, but not everything necessarily lives in memory all the time.&lt;/p&gt;&#xA;&lt;h2&gt;The big win is scalability&lt;/h2&gt;&#xA;&lt;p&gt;The reason for this change is very easy to understand when looking at large Umbraco installations.&lt;/p&gt;&#xA;&lt;p&gt;Keeping everything in memory can work beautifully for small and medium-sized sites, but it becomes painful when a site has hundreds of thousands of pages, many languages, or very large content structures. Startup time, memory usage and hosting constraints can become real problems.&lt;/p&gt;&#xA;&lt;p&gt;HybridCache helps by reducing the memory footprint and making startup faster. Instead of loading everything into memory, Umbraco can seed important content and load other content when needed. That is a big architectural improvement.&lt;/p&gt;&#xA;&lt;h2&gt;The cost did not disappear&lt;/h2&gt;&#xA;&lt;p&gt;The interesting part, at least for me as a developer, is that the cost did not vanish. It moved.&lt;/p&gt;&#xA;&lt;p&gt;Some operations that used to feel almost free can now become more expensive, especially on larger sites. Traversing a large tree, filtering over many children, or resolving many references may trigger more cache lookups or database access than before.&lt;/p&gt;&#xA;&lt;p&gt;That does not mean HybridCache is bad. Quite the opposite. But it does mean we need to be more intentional about how we build things like menus, listings, sitemaps and search-driven pages.&lt;/p&gt;&#xA;&lt;h2&gt;Use the right tool for the job&lt;/h2&gt;&#xA;&lt;p&gt;One of my main takeaways is that we should stop treating the published content cache as the answer to everything.&lt;/p&gt;&#xA;&lt;p&gt;For search and filtering, Examine is often a much better fit. For menus, footers and repeated structures, runtime cache or prebuilt DTOs can be a good option. For sitemaps, adding the right data to the index (e.g. URLs) can be much more scalable than traversing the whole content tree.&lt;/p&gt;&#xA;&lt;p&gt;So the practical message is simple: measure, observe, and choose the right approach based on what the page actually needs to do.&lt;/p&gt;&#xA;&lt;p&gt;HybridCache gives Umbraco a better foundation for large sites, but it also makes performance patterns more visible. And honestly, that is probably a good thing.&lt;/p&gt;&#xA;&lt;h2&gt;Download the slides&lt;/h2&gt;&#xA;&lt;p&gt;I&#x2019;ve shared the full slide deck from the presentation if you want to dig into the examples, benchmarks and diagrams in more detail.&lt;/p&gt;&#xA;&lt;p&gt;[Download the slides link common soon]&lt;/p&gt;]]></description>
                    <pubDate>Sun, 07 Jun 2026 05:31:32 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/knowit.umbraco.translationmanager</guid>
                    <title>Knowit.Umbraco.TranslationManager</title>
                    <link>https://marketplace.umbraco.com/package/knowit.umbraco.translationmanager</link>
                    <description><![CDATA[Backoffice dashboard for auditing Umbraco translation dictionary keys against actual code usage. Surfaces unused keys, missing translations, and language coverage gaps across Razor, React, Vue, or any custom pattern. Includes a setup wizard, multi-source scanning, and bulk dictionary management.]]></description>
                    <pubDate>Fri, 05 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/knowit.umbraco.svgpicker</guid>
                    <title>Knowit.Umbraco.SvgPicker</title>
                    <link>https://marketplace.umbraco.com/package/knowit.umbraco.svgpicker</link>
                    <description><![CDATA[Property editor for Umbraco 17 that adds a visual SVG icon picker to the backoffice. Editors browse and search symbols from any configured SVG spritesheet. Stores the symbol ID as a plain string and renders as svg/use in Razor via a built-in Html.SvgIcon() helper.]]></description>
                    <pubDate>Fri, 05 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://joe.gl/ombek/blog/codegarden-packing-list/</guid>
                    <title>Codegarden: What to bring (2026 edition!)</title>
                    <link>https://joe.gl/ombek/blog/codegarden-packing-list/</link>
                    <description><![CDATA[Wow, hasn&#x27;t time flown?! This weekend I&#x27;ll be boarding my plane to Denmark ahead of Codegarden 2026 so it&#x27;s about time we thought about packing our bags! But what to bring? If you&#x27;ve not been before, or if you&#x27;re forgetful like I am, I&#x27;ve written you a packing list...]]></description>
                    <pubDate>Thu, 04 Jun 2026 10:14:30 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.dynamicdave.nl/blog/why-2026-is-finally-the-year-i-m-going-to-codegarden/</guid>
                    <title>Why 2026 Is the Year to Finally Attend Codegarden</title>
                    <link>https://www.dynamicdave.nl/blog/why-2026-is-finally-the-year-i-m-going-to-codegarden/</link>
                    <description><![CDATA[Why 2026 Is the Year to Finally Attend Codegarden | DynamicDave]]></description>
                    <pubDate>Thu, 04 Jun 2026 07:55:39 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/security-advisory-june-4-2026-security-patch-for-umbracoai-is-now-available/</guid>
                    <title>Umbraco.AI Security Advisory, June 4, 2026</title>
                    <link>https://umbraco.com/blog/security-advisory-june-4-2026-security-patch-for-umbracoai-is-now-available/</link>
                    <description><![CDATA[Security patches are available for Umbraco.AI core package, versions 1.0.0 through 1.13.x versions fix a moderate vulnerability. Find the fix here]]></description>
                    <pubDate>Thu, 04 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://uskinned.net/blog/all-starter-kit-and-theme-add-ons-are-now-available-for-umbraco-17/</guid>
                    <title>All uSkinned Starter Kit and Themes Add-ons Out for Umbraco 17</title>
                    <link>https://uskinned.net/blog/all-starter-kit-and-theme-add-ons-are-now-available-for-umbraco-17/</link>
                    <description><![CDATA[All Starter Kit and Themes Add-ons Out for Umbraco 17&#xA;Every uSkinned Starter Kit and Theme add-on is now ready for Umbraco 17 and uSkinned Site Builder 7.]]></description>
                    <pubDate>Wed, 03 Jun 2026 09:42:08 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://www.jeroenbreuer.nl/blog/umbraco-openid-connect-example-with-lightweight-external-members/</guid>
                    <title>Umbraco OpenID Connect example with lightweight external members (Updated)</title>
                    <link>https://www.jeroenbreuer.nl/blog/umbraco-openid-connect-example-with-lightweight-external-members/</link>
                    <description><![CDATA[I updated the @umbraco OpenID Connect example to Umbraco 17.4.2 and added support for lightweight external members.Enabling it comes down to one flag: ExternalOnly = true. But there is one gotcha the docs don&#x27;t cover. Existing content-based members are not migrated automatically. If you want them to become lightweight external members, you need to delete them first and let Umbraco recreate them on the next login.Full details in the blog post below.https://www.jeroenbreuer.nl/blog/umbraco-openid-connect-example-with-lightweight-external-members/#Umbraco]]></description>
                    <pubDate>Wed, 03 Jun 2026 05:26:52 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.membertypes</guid>
                    <title>SplatDev.Umbraco.Plugins.MemberTypes</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.membertypes</link>
                    <description><![CDATA[Umbraco Member Type management plugin: create/edit custom member types with profile fields, custom properties and type templates. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.memberlogin</guid>
                    <title>SplatDev.Umbraco.Plugins.MemberLogin</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.memberlogin</link>
                    <description><![CDATA[Custom member login for Umbraco: login form, remember me, forgot password, lockout handling. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.socialmedia.share</guid>
                    <title>SplatDev.Umbraco.Plugins.SocialMedia.Share</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.socialmedia.share</link>
                    <description><![CDATA[Umbraco social sharing buttons plugin &#x2014; configurable platforms and share links. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0)]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.tweets</guid>
                    <title>SplatDev.Umbraco.Plugins.Tweets</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.tweets</link>
                    <description><![CDATA[Twitter/X feed display plugin for Umbraco 13 (net8.0) and Umbraco 17 (net10.0). Caches tweets locally and refreshes on a configurable schedule.]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.visitorcounter</guid>
                    <title>SplatDev.Umbraco.Plugins.VisitorCounter</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.visitorcounter</link>
                    <description><![CDATA[Umbraco visitor counter plugin: tracks unique and total site visitors, provides daily counts and a display widget. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.rdpmanager</guid>
                    <title>SplatDev.Umbraco.Plugins.RdpManager</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.rdpmanager</link>
                    <description><![CDATA[Umbraco Remote Desktop connection manager plugin &#x2014; store RDP configs and generate .rdp file downloads. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0)]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.countries</guid>
                    <title>SplatDev.Umbraco.Plugins.Countries</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.countries</link>
                    <description><![CDATA[Umbraco countries data plugin supporting Umbraco 13 (net8.0) and Umbraco 17 (net10.0)]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/blendinteractive.umbraco.securitydashboard</guid>
                    <title>BlendInteractive.Umbraco.SecurityDashboard</title>
                    <link>https://marketplace.umbraco.com/package/blendinteractive.umbraco.securitydashboard</link>
                    <description><![CDATA[The Umbraco Security Dashboard is a package that provides a dashboard within the Umbraco backoffice to help identify potential security vulnerabilities in installed packages. It scans installed packages against known vulnerabilities and can report vulnerabilities to a central location via webhook.]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.ispservices</guid>
                    <title>SplatDev.Umbraco.Plugins.IspServices</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.ispservices</link>
                    <description><![CDATA[Umbraco ISP/IP services utilities plugin supporting Umbraco 13 (net8.0) and Umbraco 17 (net10.0)]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.newsticker</guid>
                    <title>SplatDev.Umbraco.Plugins.NewsTicker</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.newsticker</link>
                    <description><![CDATA[Scrolling news ticker plugin for Umbraco 13 (net8.0) and Umbraco 17 (net10.0). Configurable items, speed, and direction stored in the database.]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.exceptionmanager</guid>
                    <title>SplatDev.Umbraco.Plugins.ExceptionManager</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.exceptionmanager</link>
                    <description><![CDATA[Umbraco exception handling middleware plugin supporting Umbraco 13 (net8.0) and Umbraco 17 (net10.0)]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.newsletters</guid>
                    <title>SplatDev.Umbraco.Plugins.Newsletters</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.newsletters</link>
                    <description><![CDATA[Newsletter subscriber management, campaigns, and send tracking for Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.rsvp</guid>
                    <title>SplatDev.Umbraco.Plugins.Rsvp</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.rsvp</link>
                    <description><![CDATA[Umbraco RSVP event registration plugin with attendee management, capacity limits, waitlisting, and cancellation support. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.examineextensions</guid>
                    <title>SplatDev.Umbraco.Plugins.ExamineExtensions</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.examineextensions</link>
                    <description><![CDATA[Examine search extensions for Umbraco &#x2014; additional query helpers, result transformers, and index utilities.]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.customlogin</guid>
                    <title>SplatDev.Umbraco.Plugins.CustomLogin</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.customlogin</link>
                    <description><![CDATA[Umbraco custom login page plugin with branding support, SSO integration hooks and 2FA readiness. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.seo</guid>
                    <title>SplatDev.Umbraco.Plugins.SEO</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.seo</link>
                    <description><![CDATA[Umbraco SEO plugin supporting Umbraco 13 (net8.0) and Umbraco 17 (net10.0)]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.slider</guid>
                    <title>SplatDev.Umbraco.Plugins.Slider</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.slider</link>
                    <description><![CDATA[Image slider plugin for Umbraco &#x2014; stores slide data with EF Core, renders via configurable view component.]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.surveys</guid>
                    <title>SplatDev.Umbraco.Plugins.Surveys</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.surveys</link>
                    <description><![CDATA[Umbraco survey builder plugin with questions, multiple choice, free text, rating, and results dashboard. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.wordsapi</guid>
                    <title>SplatDev.Umbraco.Plugins.WordsApi</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.wordsapi</link>
                    <description><![CDATA[Umbraco Words API plugin supporting Umbraco 13 (net8.0) and Umbraco 17 (net10.0)]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.markup</guid>
                    <title>SplatDev.Umbraco.Markup</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.markup</link>
                    <description><![CDATA[HTML/markup helpers and extensions for Umbraco 13 (net8.0) and Umbraco 17 (net10.0)]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.charlimit</guid>
                    <title>SplatDev.Umbraco.Plugins.CharLimit</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.charlimit</link>
                    <description><![CDATA[Character limit property editor for Umbraco &#x2014; enforces max length on text properties with live counter display.]]></description>
                    <pubDate>Wed, 03 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.passwordsettings</guid>
                    <title>SplatDev.Umbraco.Plugins.PasswordSettings</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.passwordsettings</link>
                    <description><![CDATA[Umbraco Password Settings plugin: complexity rules, expiration, history (prevent reuse), strength meter. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.restricted</guid>
                    <title>SplatDev.Umbraco.Plugins.Restricted</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.restricted</link>
                    <description><![CDATA[Umbraco Restricted Content plugin: member-only content gates, role-based access and paywall support using IPublicAccessService. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://owaincodes.uksouth01.umbraco.io/blog/2026/june/speed-up-slow-deployments-to-umbraco-cloud/</guid>
                    <title>Speed up slow deployments to Umbraco Cloud</title>
                    <link>https://owaincodes.uksouth01.umbraco.io/blog/2026/june/speed-up-slow-deployments-to-umbraco-cloud/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.emailnotifications</guid>
                    <title>SplatDev.Umbraco.Plugins.EmailNotifications</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.emailnotifications</link>
                    <description><![CDATA[Email template engine, Mailgun mail provider, newsletter campaigns, and member notifications for Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/uskinnedsitebuilder.starterkit.thefoundry</guid>
                    <title>uSkinnedSiteBuilder.StarterKit.TheFoundry</title>
                    <link>https://marketplace.umbraco.com/package/uskinnedsitebuilder.starterkit.thefoundry</link>
                    <description><![CDATA[The Foundry Starter Kit for uSkinned Site Builder for Umbraco CMS]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/june/speed-up-slow-deployments-to-umbraco-cloud/</guid>
                    <title>Speed up slow deployments to Umbraco Cloud</title>
                    <link>https://owain.codes/blog/2026/june/speed-up-slow-deployments-to-umbraco-cloud/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.payments.mercadopago</guid>
                    <title>SplatDev.Umbraco.Plugins.Payments.MercadoPago</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.payments.mercadopago</link>
                    <description><![CDATA[MercadoPago payment integration for Umbraco. Supports preference creation, payment status lookup, and webhook handling. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.d4sign</guid>
                    <title>SplatDev.Umbraco.Plugins.D4Sign</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.d4sign</link>
                    <description><![CDATA[D4Sign digital signature integration for Umbraco. Supports document upload, signer management, webhook processing, and a Lit 3 backoffice dashboard. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.livevideo</guid>
                    <title>SplatDev.Umbraco.Plugins.LiveVideo</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.livevideo</link>
                    <description><![CDATA[Live video embed for Umbraco &#x2014; YouTube Live, Twitch, and Vimeo live stream integration. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.videopreview</guid>
                    <title>SplatDev.Umbraco.Plugins.VideoPreview</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.videopreview</link>
                    <description><![CDATA[Video thumbnail preview for Umbraco &#x2014; auto-generate thumbnail URLs from YouTube, Vimeo, and Dailymotion video URLs. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.adminbar</guid>
                    <title>SplatDev.Umbraco.Plugins.AdminBar</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.adminbar</link>
                    <description><![CDATA[Fixed admin bar injected at the top of the page for logged-in backoffice users. Provides Edit Page, Preview and Publish shortcuts. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.newsletter</guid>
                    <title>SplatDev.Umbraco.Plugins.Newsletter</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.newsletter</link>
                    <description><![CDATA[Newsletter subscriber lists, campaigns, Mailgun bulk send, and stats tracking for Umbraco 17 (net10.0). Depends on SplatDev.Umbraco.Plugins.EmailTemplates for rendering.]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.payments.pagseguro</guid>
                    <title>SplatDev.Umbraco.Plugins.Payments.PagSeguro</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.payments.pagseguro</link>
                    <description><![CDATA[PagSeguro payment integration for Umbraco. Supports checkout session creation, transaction status lookup. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.gdrp</guid>
                    <title>SplatDev.Umbraco.Plugins.Gdrp</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.gdrp</link>
                    <description><![CDATA[GDPR compliance plugin for Umbraco &#x2014; cookie consent banner, data export, and right to erasure requests. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/june/speed-up-slow-deployments-to-umbraco-cloud/</guid>
                    <title>Speed up slow deployments to Umbraco Cloud</title>
                    <link>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/june/speed-up-slow-deployments-to-umbraco-cloud/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.enotassina</guid>
                    <title>SplatDev.Umbraco.Plugins.ENotAssina</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.enotassina</link>
                    <description><![CDATA[e-Not Assina electronic signature integration for Umbraco. Supports document creation, sequential signing, webhook processing, PDF download, and a Lit 3 backoffice dashboard. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.payments.bancointer</guid>
                    <title>SplatDev.Umbraco.Plugins.Payments.BancoInter</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.payments.bancointer</link>
                    <description><![CDATA[Banco Inter payment integration for Umbraco. Supports Pix (immediate and due charges), Boleto com Pix, Banking (outbound Pix, boleto payments, balance/statement), and webhook handling. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.dictionarymanager</guid>
                    <title>SplatDev.Umbraco.Plugins.DictionaryManager</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.dictionarymanager</link>
                    <description><![CDATA[Dictionary import/export/CRUD manager for Umbraco &#x2014; full rewrite of the Umbraco 8 plugin using ILocalizationService. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://skrift.io/issues/#128</guid>
                    <title>Skrift Issue #128</title>
                    <link>https://skrift.io/issues/#128</link>
                    <description><![CDATA[Featuring guest posts by Pasang Tamang on &quot;From Umbraco 8 to Umbraco 17 in One Leap: uSync, Cursor, and the Umbraco MCP&quot; and Aaron Sawyer on &quot;Using Local LLMs wth Umbraco MCP&quot;]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                        <category>skrift</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.hiddencontent</guid>
                    <title>SplatDev.Umbraco.Plugins.HiddenContent</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.hiddencontent</link>
                    <description><![CDATA[Umbraco Hidden Content plugin: hide nodes from navigation and sitemaps while keeping them accessible by URL via the umbracoNaviHide property. Supports Umbraco 13 (net8.0) and Umbraco 17 (net10.0).]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.mailer</guid>
                    <title>SplatDev.Umbraco.Plugins.Mailer</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.mailer</link>
                    <description><![CDATA[Umbraco mailer plugin supporting Umbraco 13 (net8.0) and Umbraco 17 (net10.0)]]></description>
                    <pubDate>Tue, 02 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://kjac.dev/posts/in-memory-umbraco-search/</guid>
                    <title>In-memory Umbraco Search</title>
                    <link>https://kjac.dev/posts/in-memory-umbraco-search/</link>
                    <description><![CDATA[How to run Umbraco Search purely in-memory.]]></description>
                    <pubDate>Mon, 01 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/june/fixing-the-sort-order-in-content-pickers-in-umbraco/</guid>
                    <title>Fixing the sort order in Content Pickers in Umbraco</title>
                    <link>https://owain.codes/blog/2026/june/fixing-the-sort-order-in-content-pickers-in-umbraco/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 01 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owaincodes.uksouth01.umbraco.io/blog/2026/june/fixing-the-sort-order-in-content-pickers-in-umbraco/</guid>
                    <title>Fixing the sort order in Content Pickers in Umbraco</title>
                    <link>https://owaincodes.uksouth01.umbraco.io/blog/2026/june/fixing-the-sort-order-in-content-pickers-in-umbraco/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 01 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/june/fixing-the-sort-order-in-content-pickers-in-umbraco/</guid>
                    <title>Fixing the sort order in Content Pickers in Umbraco</title>
                    <link>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/june/fixing-the-sort-order-in-content-pickers-in-umbraco/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 01 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/fastgooey.umbracoforms</guid>
                    <title>FastGooey.UmbracoForms</title>
                    <link>https://marketplace.umbraco.com/package/fastgooey.umbracoforms</link>
                    <description><![CDATA[Render Umbraco Forms into native iOS, macOS and Flutter viewing surfaces directly from your Umbraco projects.]]></description>
                    <pubDate>Mon, 01 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/more-visibility-more-control-whats-new-in-umbraco-cloud/</guid>
                    <title>More Visibility, More Control. What&#x27;s New in Umbraco Cloud</title>
                    <link>https://umbraco.com/blog/more-visibility-more-control-whats-new-in-umbraco-cloud/</link>
                    <description><![CDATA[Discover what&#x2019;s new and coming next in Umbraco Cloud. Explore new features like performance insights, security updates, and dedicated scaling for agencies.]]></description>
                    <pubDate>Mon, 01 Jun 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.ai.reframe</guid>
                    <title>Umbraco.Community.AI.Reframe</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.ai.reframe</link>
                    <description><![CDATA[Reframe image media to a new aspect ratio without leaving the Umbraco backoffice. A Reframe view on every Image media item lets editors retarget a picture either by Crop (instant, free, geometric) or by AI Outpaint (OpenAI gpt-image-2 invents the new edges so no content is lost). Preview before/after, then Accept to save the result as a new media item &#x2014; the original is never changed. Outpaint requires your own OpenAI API key and incurs OpenAI usage cost; Crop is free.]]></description>
                    <pubDate>Sat, 30 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://medium.com/@nomansiddiquins1/sso-in-umbraco-17-azure-ad-back-office-login-with-openid-connect-549a0e5f91e5?source=rss------umbraco-5</guid>
                    <title>SSO in Umbraco 17: Azure AD Back Office Login with OpenID Connect</title>
                    <link>https://medium.com/@nomansiddiquins1/sso-in-umbraco-17-azure-ad-back-office-login-with-openid-connect-549a0e5f91e5?source=rss------umbraco-5</link>
                    <description><![CDATA[&lt;div class=&quot;medium-feed-item&quot;&gt;&lt;p class=&quot;medium-feed-image&quot;&gt;&lt;a href=&quot;https://medium.com/@nomansiddiquins1/sso-in-umbraco-17-azure-ad-back-office-login-with-openid-connect-549a0e5f91e5?source=rss------umbraco-5&quot;&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/672/1*WGXVMKwKTrCDMQum52uvww.png&quot; width=&quot;672&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;medium-feed-snippet&quot;&gt;A step-by-step guide to wiring up Azure Active Directory as an external login provider for the Umbraco back office &amp;#x2014; with auto-linking&amp;#x2026;&lt;/p&gt;&lt;p class=&quot;medium-feed-link&quot;&gt;&lt;a href=&quot;https://medium.com/@nomansiddiquins1/sso-in-umbraco-17-azure-ad-back-office-login-with-openid-connect-549a0e5f91e5?source=rss------umbraco-5&quot;&gt;Continue reading on Medium &#xBB;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;]]></description>
                    <pubDate>Fri, 29 May 2026 18:47:06 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=cCqq76ItuB4</guid>
                    <title>umbraCoffee - Agents, Codegarden, Tees</title>
                    <link>https://www.youtube.com/watch?v=cCqq76ItuB4</link>
                    <description><![CDATA[Welcome to your monthly dose of #umbraCoffee&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;! Your hosts - Marcin and Callum - together with their guest(s) will drive through all of the community news and happenings in the Umbraco world. So... grab a cuppa, join us LIVE and enjoy!&#xA;&#xA;Today we&#x27;re joined by Adam Shallcross, CEO &amp; Founder of Cogworks &#x2013; and curator oft the Human Vibe Loop newsletter.&#xA;&#xA;See ya?!&#xA;&#xA;---&#xA;&#x2615; Wanna buy us a coffee/pizza/donuts?&#xA;https://www.buymeacoffee.com/umbracoffee&#xA;---&#xA;&#xA;Notes:&#xA;&#xA;// TODO]]></description>
                    <pubDate>Fri, 29 May 2026 09:02:18 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@lee/116654381716004252</guid>
                    <title>Contentment 7.0.0-alpha001 for Umbraco 18 RC out now</title>
                    <link>https://umbracocommunity.social/@lee/116654381716004252</link>
                    <description><![CDATA[#umbraco #Contentment 7.0.0-alpha001https://github.com/leekelleher/umbraco-contentment/releases/tag/7.0.0-alpha001TL;DR, want to try out Umbraco 18 with Contentment this weekend?Is it stable? Probably!Does it have bugs? Nah!How can you help? Test it out and feedback!]]></description>
                    <pubDate>Fri, 29 May 2026 06:23:49 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@owaincodes/116652325620551265</guid>
                    <title>Umbraco Forums #h5yr now display on HFYR.com</title>
                    <link>https://umbracocommunity.social/@owaincodes/116652325620551265</link>
                    <description><![CDATA[Pleased to announce that now, if you give a #h5yr on the Umbraco Forum, that post will be displayed on H5YR.com Thanks @sebastiaan for helping get this setup. #umbraco]]></description>
                    <pubDate>Thu, 28 May 2026 13:00:42 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@UmbHost/116651510454937905</guid>
                    <title>UmbHost launches automated Umbraco upgrades</title>
                    <link>https://umbracocommunity.social/@UmbHost/116651510454937905</link>
                    <description><![CDATA[Automated Umbraco upgrades, sorted. GitHub Dependabot handles the dependency PRs, GreenStack handles the deploy. Here&#x27;s how you can do it &#x1F447;https://umbhost.net/blog/2026/05/building-your-own-umbraco-cloud-style-auto-upgrades-with-github-dependabot#Umbraco #dotnet #DevOps #GreenStack]]></description>
                    <pubDate>Thu, 28 May 2026 09:35:45 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/umbraco-18-release-candidate/</guid>
                    <title>Umbraco 18 Release Candidate</title>
                    <link>https://umbraco.com/blog/umbraco-18-release-candidate/</link>
                    <description><![CDATA[Discover and test the Umbraco 18 Release Candidate, featuring Elements for reusable content, typed OpenAPI schemas,]]></description>
                    <pubDate>Thu, 28 May 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.jeroenbreuer.nl/blog/how-i-let-cursor-build-an-azure-search-provider-for-umbraco-search/</guid>
                    <title>How I let Cursor build an Azure Search provider for Umbraco Search</title>
                    <link>https://www.jeroenbreuer.nl/blog/how-i-let-cursor-build-an-azure-search-provider-for-umbraco-search/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 27 May 2026 13:57:13 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/may/codegarden-2026-not-long-now/</guid>
                    <title>Codegarden 2026 - not long now!</title>
                    <link>https://owain.codes/blog/2026/may/codegarden-2026-not-long-now/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 27 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/lantern.umbraco</guid>
                    <title>Lantern.Umbraco</title>
                    <link>https://marketplace.umbraco.com/package/lantern.umbraco</link>
                    <description><![CDATA[Add the Lantern bug-tracking widget to every page of your Umbraco site in seconds. Configure your embed key from the backoffice &#x2014; no template changes needed.]]></description>
                    <pubDate>Wed, 27 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/may/codegarden-2026-not-long-now/</guid>
                    <title>Codegarden 2026 - not long now!</title>
                    <link>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/may/codegarden-2026-not-long-now/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 27 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owaincodes.uksouth01.umbraco.io/blog/2026/may/codegarden-2026-not-long-now/</guid>
                    <title>Codegarden 2026 - not long now!</title>
                    <link>https://owaincodes.uksouth01.umbraco.io/blog/2026/may/codegarden-2026-not-long-now/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 27 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://medium.com/@contacts_81271/umbraco-vs-wordpress-b180bf6af576?source=rss------umbraco-5</guid>
                    <title>Umbraco vs WordPress</title>
                    <link>https://medium.com/@contacts_81271/umbraco-vs-wordpress-b180bf6af576?source=rss------umbraco-5</link>
                    <description><![CDATA[&lt;div class=&quot;medium-feed-item&quot;&gt;&lt;p class=&quot;medium-feed-image&quot;&gt;&lt;a href=&quot;https://medium.com/@contacts_81271/umbraco-vs-wordpress-b180bf6af576?source=rss------umbraco-5&quot;&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1672/1*rTkBaNhm67woupfcRsK7FA.png&quot; width=&quot;1672&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;medium-feed-snippet&quot;&gt;Die Wahl des richtigen Web-Content-Management-Systems gleicht heute einer strategischen Richtungsentscheidung, die ma&amp;#xDF;geblichen Einfluss&amp;#x2026;&lt;/p&gt;&lt;p class=&quot;medium-feed-link&quot;&gt;&lt;a href=&quot;https://medium.com/@contacts_81271/umbraco-vs-wordpress-b180bf6af576?source=rss------umbraco-5&quot;&gt;Continue reading on Medium &#xBB;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;]]></description>
                    <pubDate>Tue, 26 May 2026 10:17:32 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://skttl.dev/blog/browsing-umbraco-logs-in-kudu/</guid>
                    <title>Browsing Umbraco Logs in Kudu</title>
                    <link>https://skttl.dev/blog/browsing-umbraco-logs-in-kudu/</link>
                    <description><![CDATA[Browsing Umbraco Logs in Kudu | skttl.dev]]></description>
                    <pubDate>Tue, 26 May 2026 06:09:21 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/upreviewshare</guid>
                    <title>uPreviewShare</title>
                    <link>https://marketplace.umbraco.com/package/upreviewshare</link>
                    <description><![CDATA[Securely share unpublished draft content with external stakeholders via time-limited, view-capped, and PIN-protected preview links. Renders through actual Umbraco templates.]]></description>
                    <pubDate>Tue, 26 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=wwQBvBDGhPE</guid>
                    <title>Umbraco Search Explained | Kenn Jacobsen | Umbraco India Meetup</title>
                    <link>https://www.youtube.com/watch?v=wwQBvBDGhPE</link>
                    <description><![CDATA[Featuring Kenn Jacobsen&#xA;Kenn is a 4x Umbraco MVP and a long-time contributor to the Umbraco community, with more than 10 years of experience building solutions with Umbraco and .NET.&#xA;&#xA;&#x1F4FA; Watch the full session recording and learn what&#x2019;s coming next for search in the Umbraco ecosystem.&#xA;&#xA;&#x1F30D; Join us for upcoming Umbraco India User Group events and community updates.&#xA;&#x1F517;https://www.meetup.com/umbraco-india-user-group&#xA;&#x1F517;https://www.linkedin.com/groups/14558029]]></description>
                    <pubDate>Thu, 21 May 2026 09:52:54 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/m1sterpl0w.umbraco.accessrestriction</guid>
                    <title>M1sterPl0w.Umbraco.AccessRestriction</title>
                    <link>https://marketplace.umbraco.com/package/m1sterpl0w.umbraco.accessrestriction</link>
                    <description><![CDATA[An Umbraco package that restricts access to your site (or specific paths) by IP address whitelist. Manage whitelisted IPs and restricted paths from a dashboard in the Umbraco backoffice, with optional hardcoded entries via appsettings.json.]]></description>
                    <pubDate>Thu, 21 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@UmbHost/116606538139138040</guid>
                    <title>UmbHost.Tables for Umbraco has had an update</title>
                    <link>https://umbracocommunity.social/@UmbHost/116606538139138040</link>
                    <description><![CDATA[UmbHost.Tables for #Umbraco has had an update courtesy of Mike Masey!This replaces the custom RTE with the fully featured tiptap RTE with all the configuration options you would expect.View source now opens in a modal windowThere is also a range of accessibility and UX improvementsMany thanks and a huge #h5yr for this PR!Grab it here:https://www.nuget.org/packages/UmbHost.Tables/17.1.0]]></description>
                    <pubDate>Wed, 20 May 2026 10:56:20 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://github.com/prjseal/Start-With-Markdown/</guid>
                    <title>Start With Markdown</title>
                    <link>https://github.com/prjseal/Start-With-Markdown/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 20 May 2026 06:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://discord.com/channels/869656431308189746/882981290662580264/1506219000525225994</guid>
                    <title> Clean starter kit for Umbraco 18 out in Beta</title>
                    <link>https://discord.com/channels/869656431308189746/882981290662580264/1506219000525225994</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 20 May 2026 06:00:00 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>discord</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/pragmaticit.umbraco.virtualmembers</guid>
                    <title>PragmaticIT.Umbraco.VirtualMembers</title>
                    <link>https://marketplace.umbraco.com/package/pragmaticit.umbraco.virtualmembers</link>
                    <description><![CDATA[Passwordless, database-free member authentication for Umbraco CMS. Protect content nodes with email-only, OTP, or MFA login &#x2014; members loaded from plain CSV files, no Umbraco Members database records required.]]></description>
                    <pubDate>Wed, 20 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@owaincodes/116601888665115697</guid>
                    <title>UmbracoTees day May 29th</title>
                    <link>https://umbracocommunity.social/@owaincodes/116601888665115697</link>
                    <description><![CDATA[Can you believe we haven&#x27;t had an #UmbracoTees day this year yet? Well, let&#x27;s change that!! Get your Umbraco Swag on, share your photos with #umbracoTees and let&#x27;s see you all celebrate all things #umbraco May 29th 2026!https://isitumbracoteesday.today/]]></description>
                    <pubDate>Tue, 19 May 2026 15:13:52 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=DcxmRjoFZwc</guid>
                    <title>Start With Markdown</title>
                    <link>https://www.youtube.com/watch?v=DcxmRjoFZwc</link>
                    <description><![CDATA[Learn about my new open source content publishing workflow called Start With Markdown&#xA;&#xA;It&#x27;s a simple workflow which triggers when you create or modify a markdown file in the posts folder of your github repo.&#xA;&#xA;When it triggers it calls some endpoints on your CMS to create the content and it returns the edit, preview and publish URLs for you.&#xA;&#xA;Here is the link to the main project that you fork and setup to call your CMS endpoints&#xA;https://github.com/prjseal/Start-With-Markdown/&#xA;&#xA;And here is the link to the demo Umbraco project and supporting libraries with the custom resolvers for unsplash and things like that to get it working with the Clean starter kit&#xA;https://github.com/prjseal/Start-With-Markdown-Umbraco-Libraries]]></description>
                    <pubDate>Tue, 19 May 2026 14:17:30 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://dev.to/lauraneto/umbraco-18-and-openapi-a-heads-up-for-extension-developers-1k7</guid>
                    <title>Umbraco 18 and OpenAPI: a heads-up for extension developers</title>
                    <link>https://dev.to/lauraneto/umbraco-18-and-openapi-a-heads-up-for-extension-developers-1k7</link>
                    <description><![CDATA[&lt;p&gt;Time to upgrade your extension to Umbraco 18?&lt;br&gt;&#xA;A friendly heads up, the OpenAPI generation got an overhaul.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;code&gt;Microsoft.AspNetCore.OpenApi&lt;/code&gt; is Umbraco&#x27;s new library of choice for OpenAPI document generation, replacing &lt;code&gt;Swashbuckle.AspNetCore&lt;/code&gt;. It ships with ASP.NET Core and is maintained by Microsoft alongside the framework, which means one fewer third-party dependency to worry about.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The trade-off: if your extension wired up its own OpenAPI document on v17, it won&#x27;t compile against v18. The Swashbuckle types it relied on are gone.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Two paths forward:&lt;/p&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Migrate to Microsoft OpenAPI&lt;/strong&gt;. Two options:&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Use the &lt;code&gt;AddBackOfficeOpenApiDocument&lt;/code&gt; extension method&lt;/strong&gt;: Umbraco&#x27;s new helper. What the v18 template uses. Covers most extensions.&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Use Microsoft&#x27;s &lt;code&gt;AddOpenApi&lt;/code&gt; method directly&lt;/strong&gt;: call &lt;code&gt;Microsoft.AspNetCore.OpenApi&lt;/code&gt; yourself. For full control.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Keep using Swashbuckle&lt;/strong&gt; &lt;em&gt;(not recommended)&lt;/em&gt;. Install &lt;code&gt;Swashbuckle.AspNetCore&lt;/code&gt; in your own extension, wire it up, then plug your document into Umbraco&#x27;s Swagger UI via &lt;code&gt;AddOpenApiDocumentToUi(...)&lt;/code&gt;. When rewriting isn&#x27;t an option right now.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&#x2139;&#xFE0F; &lt;strong&gt;Note:&lt;/strong&gt; the OpenAPI spec URL also changed from &lt;code&gt;/umbraco/swagger/{documentName}/swagger.json&lt;/code&gt; to &lt;code&gt;/umbraco/openapi/{documentName}.json&lt;/code&gt;. If you generate a client from the spec (e.g. via the v17 extension template&#x27;s &lt;code&gt;package.json&lt;/code&gt; &lt;code&gt;generate-client&lt;/code&gt; script), update the URL before regenerating.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Use the AddBackOfficeOpenApiDocument extension method&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;We added &lt;code&gt;AddBackOfficeOpenApiDocument()&lt;/code&gt; in v18 to take the boilerplate out of registering an OpenAPI document. It&#x27;s an extension method on &lt;code&gt;IUmbracoBuilder&lt;/code&gt; that wires up Umbraco&#x27;s sensible defaults so you don&#x27;t have to.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Out of the box, the helper registers your document, scopes it to endpoints decorated with &lt;code&gt;[MapToApi(documentName)]&lt;/code&gt;, applies Umbraco&#x27;s naming conventions for schemas and operation IDs, and adds the document to the Swagger UI dropdown at &lt;code&gt;/umbraco/openapi/&lt;/code&gt;.&lt;/p&gt;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&#x26A0;&#xFE0F; &lt;strong&gt;Watch out:&lt;/strong&gt; the first time you call &lt;code&gt;AddBackOfficeOpenApiDocument&lt;/code&gt; (or &lt;code&gt;AddOpenApi&lt;/code&gt; directly) and build, you&#x27;ll hit &lt;code&gt;error CS9137: The &#x27;interceptors&#x27; feature is not enabled in this namespace&lt;/code&gt;. The &lt;code&gt;Microsoft.AspNetCore.OpenApi&lt;/code&gt; source generator (which surfaces your XML doc comments as descriptions in the OpenAPI document, among other compile-time enrichments) propagates through Umbraco&#x27;s project reference, but the property that enables it ships only with the Web SDK. Class-library projects don&#x27;t get it automatically, so add it to your &lt;code&gt;.csproj&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&#xA;&lt;pre class=&quot;highlight xml&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;&#xA;  &lt;span class=&quot;nt&quot;&gt;&amp;lt;InterceptorsNamespaces&amp;gt;&lt;/span&gt;$(InterceptorsNamespaces);Microsoft.AspNetCore.OpenApi.Generated&lt;span class=&quot;nt&quot;&gt;&amp;lt;/InterceptorsNamespaces&amp;gt;&lt;/span&gt;&#xA;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/blockquote&gt;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Minimal usage&#xA;&lt;/h3&gt;&#xA;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UmbracoExtensionApiComposer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComposer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Compose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IUmbracoBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddBackOfficeOpenApiDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my-api&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&lt;p&gt;This will add and configure a &quot;my-api&quot; OpenAPI document that will display the controllers/endpoints that have the attribute &lt;code&gt;[MapToApi(&quot;my-api&quot;)]&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Typical usage&#xA;&lt;/h3&gt;&#xA;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UmbracoExtensionApiComposer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComposer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Compose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IUmbracoBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddBackOfficeOpenApiDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my-api&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WithTitle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;My API&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WithBackOfficeAuthentication&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&lt;p&gt;Besides adding a &quot;my-api&quot; OpenAPI document, this will set the document title to &quot;My API&quot; and declare that the document&#x27;s operations require backoffice authentication (which is what enables the &quot;Authorize&quot; flow in the Swagger UI).&lt;/p&gt;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Builder method reference&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Method&lt;/th&gt;&#xA;&lt;th&gt;What it does&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;WithTitle(string)&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Sets the document&#x27;s &lt;code&gt;Info.Title&lt;/code&gt;. Also used as the UI dropdown label unless &lt;code&gt;WithUiTitle&lt;/code&gt; is set.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;WithUiTitle(string)&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Overrides only the UI dropdown label, leaving &lt;code&gt;Info.Title&lt;/code&gt; untouched.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;ExcludeFromUi()&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Suppresses registration in the Swagger UI document dropdown. Document is still reachable at its JSON URL.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;WithBackOfficeAuthentication()&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Registers the backoffice OAuth2 security scheme on the document and marks operations as requiring authentication. Swagger UI uses this to prompt for login; generated clients use it to send the token.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;ConfigureOpenApiOptions(Action&amp;lt;OpenApiOptions&amp;gt;)&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Adds a configuration callback for the underlying &lt;code&gt;OpenApiOptions&lt;/code&gt;. Multiple calls will run in order after Umbraco&#x27;s defaults.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;WithJsonOptions(...)&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Sets the &lt;code&gt;JsonOptions&lt;/code&gt; used when generating the document&#x27;s schema. See Aligning schema serialization below.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&lt;/div&gt;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Aligning schema serialization&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Schema generation needs to use the same &lt;code&gt;JsonOptions&lt;/code&gt; your API uses at runtime, otherwise the generated SDKs and the actual payloads will not match. By default, &lt;code&gt;Microsoft.AspNetCore.OpenApi&lt;/code&gt; generates schemas using the global HTTP &lt;code&gt;JsonOptions&lt;/code&gt;, which means whoever hosts your extension can change them and that affects your schema.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;For most backoffice extensions you want the BackOffice named &lt;code&gt;JsonOptions&lt;/code&gt; (the same ones Umbraco&#x27;s Management API uses). Point the document at them with &lt;code&gt;WithJsonOptions&lt;/code&gt;:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UmbracoExtensionApiComposer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComposer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Compose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IUmbracoBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddBackOfficeOpenApiDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my-api&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WithJsonOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Constants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JsonOptionsNames&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BackOffice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;For this to be meaningful at runtime, your controllers also need to serialize with those same options. The v17 extension template inherits from a plain &lt;code&gt;ControllerBase&lt;/code&gt;, which uses the default options instead. Fix that by adding &lt;code&gt;[JsonOptionsName(Constants.JsonOptionsNames.BackOffice)]&lt;/code&gt; to your own base controller or to each controller directly.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Without it, the schema reflects backoffice serialization but the actual responses are serialized with the default options, and you&#x27;re back to the schema-vs-runtime mismatch.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Going beyond the defaults&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;The helper is not a closed box. Anything you&#x27;d normally do on &lt;code&gt;OpenApiOptions&lt;/code&gt; (custom operation/schema/document transformers, your own &lt;code&gt;CreateSchemaReferenceId&lt;/code&gt;, a replacement operation ID transformer, etc.) is still available through &lt;code&gt;ConfigureOpenApiOptions&lt;/code&gt;. It just runs after Umbraco&#x27;s defaults, so you compose on top of them rather than starting from scratch.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;For example, registering your own schema transformer:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UmbracoExtensionApiComposer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComposer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Compose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IUmbracoBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddBackOfficeOpenApiDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my-api&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WithTitle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;My API&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureOpenApiOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddSchemaTransformer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MyExtensionSchemaTransformer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;()));&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Migrating an existing composer&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;If your extension followed the shape of the v17 dotnet template, the migration is: delete the old composer body and write the &lt;code&gt;AddBackOfficeOpenApiDocument(...)&lt;/code&gt; call. Below is the same extension&#x27;s composer before and after.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;v17 (Swashbuckle)&lt;/strong&gt;&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UmbracoExtensionApiComposer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComposer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Compose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IUmbracoBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddSingleton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IOperationIdHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomOperationHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Configure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SwaggerGenOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SwaggerDoc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Constants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ApiName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OpenApiInfo&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;Title&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;My Test Extension Backoffice API&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;&#xA;            &lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OperationFilter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UmbracoExtensionOperationSecurityFilter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UmbracoExtensionOperationSecurityFilter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BackOfficeSecurityRequirementsOperationFilterBase&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ApiName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Constants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ApiName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CustomOperationHandler&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OperationIdHandler&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;v18 (Microsoft OpenAPI &#x2B; new builder)&lt;/strong&gt;&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UmbracoExtensionApiComposer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComposer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Compose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IUmbracoBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddBackOfficeOpenApiDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;Constants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ApiName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&#xA;                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WithTitle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;My Test Extension Backoffice API&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WithBackOfficeAuthentication&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;The helper registers &lt;code&gt;UmbracoOperationIdTransformer&lt;/code&gt; by default, so the old &lt;code&gt;IOperationIdHandler&lt;/code&gt; is no longer needed. If you want custom operation ID logic, register your own through &lt;code&gt;ConfigureOpenApiOptions&lt;/code&gt;:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UmbracoExtensionApiComposer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComposer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Compose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IUmbracoBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddBackOfficeOpenApiDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my-api&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureOpenApiOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddOperationTransformer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;                &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                    &lt;span class=&quot;n&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OperationId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ActionDescriptor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RouteValues&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;action&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;                    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CompletedTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;                &lt;span class=&quot;p&quot;&gt;})));&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Use Microsoft&#x27;s AddOpenApi method directly&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;If you want to register a document that isn&#x27;t a backoffice document, or you want to start from a clean slate without Umbraco&#x27;s defaults, call &lt;code&gt;AddOpenApi&lt;/code&gt; yourself. The helper is just a thin wrapper around that method. Umbraco already wires the OpenAPI routing and Swagger UI hosting, so you don&#x27;t need to call &lt;code&gt;MapOpenApi&lt;/code&gt; or configure endpoints. You only need to register your documents.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;For the transformer model itself (how operation/schema/document transformers work), see Microsoft&#x27;s &lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/fundamentals/openapi/customize-openapi&quot; rel=&quot;noopener noreferrer&quot;&gt;Customize OpenAPI documents&lt;/a&gt; docs.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;For Umbraco&#x27;s specifics (&lt;code&gt;[MapToApi]&lt;/code&gt; filtering via &lt;code&gt;options.ShouldInclude&lt;/code&gt;, schema/operation ID conventions, the public &lt;code&gt;UmbracoSchemaIdGenerator.Generate(type)&lt;/code&gt; helper), see the &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/18.latest/extend-your-project/server-side-extensions/api-versioning-and-openapi&quot; rel=&quot;noopener noreferrer&quot;&gt;API versioning and OpenAPI&lt;/a&gt; docs.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;A few things worth remembering:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Backoffice authentication&lt;/strong&gt;: call &lt;code&gt;options.AddBackofficeSecurityRequirements()&lt;/code&gt; (from &lt;code&gt;Umbraco.Cms.Api.Management.OpenApi&lt;/code&gt;) instead of subclassing &lt;code&gt;BackOfficeSecurityRequirementsOperationFilterBase&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Swagger UI registration&lt;/strong&gt;: documents are no longer auto-listed. Call &lt;code&gt;services.AddOpenApiDocumentToUi(documentName, uiTitle)&lt;/code&gt; to surface yours in the dropdown.&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;&lt;code&gt;InterceptorsNamespaces&lt;/code&gt; opt-in&lt;/strong&gt;: same as the helper path. See the Watch out callout at the top of the helper section.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Keep using Swashbuckle&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Not recommended.&lt;/strong&gt; Consider this only if rewriting a complex Swashbuckle setup isn&#x27;t feasible right now. Trade-offs:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Extra dependency on &lt;code&gt;Swashbuckle.AspNetCore&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;OpenAPI 3.0 output, whereas the rest of Umbraco&#x27;s documents emit 3.1.&lt;/li&gt;&#xA;&lt;li&gt;Extra wiring you maintain yourself.&lt;/li&gt;&#xA;&lt;li&gt;Both libraries depend on &lt;code&gt;Microsoft.OpenApi&lt;/code&gt;. A breaking change there that Swashbuckle doesn&#x27;t follow leaves your extension incompatible with the rest of the stack.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;If you still want to go this route, see the &lt;a href=&quot;https://github.com/domaindrivendev/Swashbuckle.AspNetCore#getting-started&quot; rel=&quot;noopener noreferrer&quot;&gt;Swashbuckle.AspNetCore README&lt;/a&gt; for general setup. The rest of this section is the Umbraco-specific wiring.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;1. Install the NuGet package&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Add a &lt;code&gt;PackageReference&lt;/code&gt; to &lt;code&gt;Swashbuckle.AspNetCore&lt;/code&gt; in your extension&#x27;s &lt;code&gt;.csproj&lt;/code&gt; (or &lt;code&gt;dotnet add package Swashbuckle.AspNetCore&lt;/code&gt;).&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;2. Register Swashbuckle and your document in a composer&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;In v17, Umbraco called &lt;code&gt;AddSwaggerGen&lt;/code&gt; for you and your extension only configured &lt;code&gt;SwaggerGenOptions&lt;/code&gt;. In v18 you have to call it yourself:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UmbracoExtensionApiComposer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComposer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Compose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IUmbracoBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddSwaggerGen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SwaggerDoc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Constants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ApiName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OpenApiInfo&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;Title&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;My Test Extension Backoffice API&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;Version&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;&#xA;            &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;previousDocInclusion&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SwaggerGeneratorOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DocInclusionPredicate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DocInclusionPredicate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;docName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;apiDesc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;docName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Constants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ApiName&lt;/span&gt;&#xA;                    &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;apiDesc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ActionDescriptor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;HasMapToApiAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;docName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;                    &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;previousDocInclusion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Invoke&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;docName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;apiDesc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;            &lt;span class=&quot;c1&quot;&gt;// any operation filters, schema filters, or other v17 setup you had...&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;3. Host the Swagger JSON middleware via an &lt;code&gt;IUmbracoPipelineFilter&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Umbraco no longer calls &lt;code&gt;app.UseSwagger()&lt;/code&gt;, so the middleware that serves the Swagger JSON isn&#x27;t running. Add it through Umbraco&#x27;s pipeline filter, and set the &lt;code&gt;RouteTemplate&lt;/code&gt; to match &lt;code&gt;UmbracoOpenApiOptions.RouteTemplate&lt;/code&gt; (default &lt;code&gt;umbraco/openapi/{documentName}.json&lt;/code&gt;) so the dropdown link resolves.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UmbracoExtensionApiComposer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComposer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Compose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IUmbracoBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Configure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UmbracoPipelineOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddFilter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;UmbracoPipelineFilter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Swashbuckle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;PostPipeline&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;                &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;openApiOptions&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ApplicationServices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetRequiredService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UmbracoOpenApiOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;                    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;openApiOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Enabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;                    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;                    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;                    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;routeTemplate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;openApiOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RouteTemplate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;                    &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;UseWhen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;                        &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;routeTemplate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{documentName}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Constants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ApiName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;EnsureStartsWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;&#x27;/&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&#xA;                        &lt;span class=&quot;n&quot;&gt;branch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;UseSwagger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RouteTemplate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;routeTemplate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&#xA;                &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Scope the middleware to your own document&#x27;s URL. Otherwise Swashbuckle intercepts requests for Umbraco&#x27;s own documents (Management, Delivery) and returns 404 because they aren&#x27;t registered with &lt;code&gt;AddSwaggerGen&lt;/code&gt;.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;4. Register the document in the Swagger UI dropdown&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Register the document in Umbraco&#x27;s Swagger UI dropdown:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UmbracoExtensionApiComposer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComposer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Compose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IUmbracoBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddOpenApiDocumentToUi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Constants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ApiName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;My API&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  TL;DR&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The helper is the simplest option for most extensions. &lt;code&gt;AddBackOfficeOpenApiDocument()&lt;/code&gt; is what the v18 template uses, gives you Umbraco&#x27;s sensible defaults out of the box (naming conventions, Swagger UI registration, JsonOptions alignment), and lets you register an OpenAPI document in a single call.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Calling &lt;code&gt;AddOpenApi&lt;/code&gt; yourself is the standard ASP.NET Core approach and works fine. It means more wiring and code to maintain, so reach for it when you need full control (non-backoffice documents, or skipping the Umbraco defaults).&lt;/p&gt;&#xA;&#xA;&lt;p&gt;If rewriting really isn&#x27;t an option right now, keeping Swashbuckle as your own dependency and plugging into the dropdown via &lt;code&gt;AddOpenApiDocumentToUi(...)&lt;/code&gt; will get you through, but plan to revisit when you can.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Further reading&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&quot;https://github.com/umbraco/Announcements/issues/32&quot; rel=&quot;noopener noreferrer&quot;&gt;Announcements #32&lt;/a&gt;: the official announcement, with the full set of changes and reasoning&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/18.latest/extend-your-project/server-side-extensions/custom-backoffice-api&quot; rel=&quot;noopener noreferrer&quot;&gt;Custom Backoffice API&lt;/a&gt;: end-to-end backoffice API setup&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/18.latest/extend-your-project/server-side-extensions/api-versioning-and-openapi&quot; rel=&quot;noopener noreferrer&quot;&gt;API versioning and OpenAPI&lt;/a&gt;: schema IDs, operation IDs, route configuration, endpoint filtering&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/18.latest/get-started/upgrading-and-migrating/version-specific#umbraco-18&quot; rel=&quot;noopener noreferrer&quot;&gt;Umbraco 18 version-specific upgrade docs&lt;/a&gt;: official migration reference&lt;/li&gt;&#xA;&lt;/ul&gt;]]></description>
                    <pubDate>Tue, 19 May 2026 13:37:37 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.justnik.me/blog/why-i-built-a-passwordless-library-for-umbraco</guid>
                    <title>Building a Passwordless Authentication Library for Umbraco - Part 1: Why?</title>
                    <link>https://www.justnik.me/blog/why-i-built-a-passwordless-library-for-umbraco</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Tue, 19 May 2026 12:36:58 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://skttl.dev/blog/releasing-image-hotspot-17/</guid>
                    <title>Releasing Image Hotspot 17.0.0</title>
                    <link>https://skttl.dev/blog/releasing-image-hotspot-17/</link>
                    <description><![CDATA[Releasing Image Hotspot 17.0.0 | skttl.dev]]></description>
                    <pubDate>Tue, 19 May 2026 09:23:05 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/ai-on-your-terms-how-umbraco-reimagines-ai/</guid>
                    <title>AI on Your Terms: How Umbraco Reimagines AI</title>
                    <link>https://umbraco.com/blog/ai-on-your-terms-how-umbraco-reimagines-ai/</link>
                    <description><![CDATA[AI is often introduced as a shortcut: more content, more insights, more efficiency. But for many organizations, especially those responsible for digital platforms, the initial excitement is quickly followed by unease. Who is in control of the output? What happens to sensitive data? And how do you ensure that automation doesn&#x2019;t quietly erode quality, tone, or accountability?]]></description>
                    <pubDate>Tue, 19 May 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/uprofile-may-2026-bernadet-goey/</guid>
                    <title>uProfile May 2026 - Bernadet Goey</title>
                    <link>https://umbraco.com/blog/uprofile-may-2026-bernadet-goey/</link>
                    <description><![CDATA[Meet Bernadet: Former PHP-specialist, now a confident Umbraco Developer, looking to give back to the community that supported her journey]]></description>
                    <pubDate>Mon, 18 May 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/hcs.passwordless.otp</guid>
                    <title>HCS.Passwordless.Otp</title>
                    <link>https://marketplace.umbraco.com/package/hcs.passwordless.otp</link>
                    <description><![CDATA[One-time password (OTP) email add-on for Umbraco 17 passwordless member authentication. Delivers a short numeric code by email that the member enters to sign in. No passwords required.]]></description>
                    <pubDate>Mon, 18 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/hcs.passwordless.magiclink</guid>
                    <title>HCS.Passwordless.MagicLink</title>
                    <link>https://marketplace.umbraco.com/package/hcs.passwordless.magiclink</link>
                    <description><![CDATA[Magic link passwordless authentication for Umbraco 17 members. Send a one-click sign-in link by email &#x2014; no passwords required. Includes built-in rate limiting, single-use tokens, and customisable branded emails.]]></description>
                    <pubDate>Mon, 18 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/hcs.passwordless.webauthn</guid>
                    <title>HCS.Passwordless.WebAuthn</title>
                    <link>https://marketplace.umbraco.com/package/hcs.passwordless.webauthn</link>
                    <description><![CDATA[WebAuthn/FIDO2 passkey add-on for Umbraco 17 passwordless member authentication. Enable hardware-backed biometric or security-key sign-in via the browser&#x27;s Credential Management API. No passwords required.]]></description>
                    <pubDate>Mon, 18 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://jcdc.dev/blog/share-the-love-bringing-h5yr-to-jcdcdev</guid>
                    <title>Share the Love - Bringing #H5YR to jcdc.dev</title>
                    <link>https://jcdc.dev/blog/share-the-love-bringing-h5yr-to-jcdcdev</link>
                    <description><![CDATA[I&#x27;ve added the new #H5YR widget to my sites. Send a virtual High Five!]]></description>
                    <pubDate>Sat, 16 May 2026 09:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://uskinned.net/blog/uskinned-site-builder-for-umbraco-17/</guid>
                    <title>uSkinned Site Builder for Umbraco 17</title>
                    <link>https://uskinned.net/blog/uskinned-site-builder-for-umbraco-17/</link>
                    <description><![CDATA[&#x1F4E3; Introducing &#x1F941;&#xA;&#xA;uSkinned Site Builder for Umbraco 17 &#x1F929;&#xA;&#xA;Full support for Umbraco 17 is now available for uSkinned Site Builder. Install or upgrade today.]]></description>
                    <pubDate>Fri, 15 May 2026 14:03:31 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://www.linkedin.com/pulse/from-zero-working-product-two-hours-adam-shallcross-7zeme/</guid>
                    <title>From zero to working product in two hours</title>
                    <link>https://www.linkedin.com/pulse/from-zero-working-product-two-hours-adam-shallcross-7zeme/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 15 May 2026 07:58:10 Z</pubDate>
                        <category>social</category>
                        <category>linkedin</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.agent.ui</guid>
                    <title>Umbraco.AI.Agent.UI</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.agent.ui</link>
                    <description><![CDATA[Shared chat UI components for Umbraco AI Agent surfaces]]></description>
                    <pubDate>Fri, 15 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.agent.copilot</guid>
                    <title>Umbraco.AI.Agent.Copilot</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.agent.copilot</link>
                    <description><![CDATA[Copilot chat UI for Umbraco AI Agent]]></description>
                    <pubDate>Fri, 15 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/modgift.umbraco.breakable</guid>
                    <title>Modgift.Umbraco.Breakable</title>
                    <link>https://marketplace.umbraco.com/package/modgift.umbraco.breakable</link>
                    <description><![CDATA[A Breakable property editor for Umbraco CMS that lets editors mark soft-hyphen break points inside text values using | as a delimiter.]]></description>
                    <pubDate>Fri, 15 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/our.umbraco.propertytooltip</guid>
                    <title>Our.Umbraco.PropertyToolTip</title>
                    <link>https://marketplace.umbraco.com/package/our.umbraco.propertytooltip</link>
                    <description><![CDATA[Property ToolTip keeps Umbraco property descriptions available, but shows them as small tooltip help text beside each property label.]]></description>
                    <pubDate>Fri, 15 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://medium.com/@ben_46907/swiftui-is-a-disaster-9706ffe6016c?source=rss------umbraco-5</guid>
                    <title>SwiftUI is a Disaster</title>
                    <link>https://medium.com/@ben_46907/swiftui-is-a-disaster-9706ffe6016c?source=rss------umbraco-5</link>
                    <description><![CDATA[&lt;div class=&quot;medium-feed-item&quot;&gt;&lt;p class=&quot;medium-feed-image&quot;&gt;&lt;a href=&quot;https://medium.com/@ben_46907/swiftui-is-a-disaster-9706ffe6016c?source=rss------umbraco-5&quot;&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/800/0*yYaREfb1AnLyqkU5.png&quot; width=&quot;800&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;medium-feed-snippet&quot;&gt;I&amp;#x2019;ll admit it. I&amp;#x2019;m still programming for Apple platforms using Objective-C, AppKit and UIKit.&lt;/p&gt;&lt;p class=&quot;medium-feed-link&quot;&gt;&lt;a href=&quot;https://medium.com/@ben_46907/swiftui-is-a-disaster-9706ffe6016c?source=rss------umbraco-5&quot;&gt;Continue reading on Medium &#xBB;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;]]></description>
                    <pubDate>Thu, 14 May 2026 17:24:48 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://joe.gl/ombek/blog/umbicosaurus-deextinction/</guid>
                    <title>The Umbicosaurus De-Extinction: The Community Effort that Brought a Better Icon Picker to Umbraco 17.4</title>
                    <link>https://joe.gl/ombek/blog/umbicosaurus-deextinction/</link>
                    <description><![CDATA[In 2021, I dreamed of improving the icon picker in the Umbraco backoffice and today, in Umbraco 17.4, the package I started is making a splash as part of Core!&#xA;&#xA;This is the story of Umbicosaurus.]]></description>
                    <pubDate>Thu, 14 May 2026 09:58:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.nuget.org/packages/Articulate/6.0.0-rc.2</guid>
                    <title>Articulate v6 RC 2</title>
                    <link>https://www.nuget.org/packages/Articulate/6.0.0-rc.2</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Thu, 14 May 2026 08:29:22 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://uskinned.net/blog/umbraco-scotland-meetup-glasgow-edition/</guid>
                    <title>Umbraco Scotland: Glasgow Edition, May 2026</title>
                    <link>https://uskinned.net/blog/umbraco-scotland-meetup-glasgow-edition/</link>
                    <description><![CDATA[Umbraco Scotland: Glasgow Edition, May 2026&#xA;&#xA;A great evening, bringing the Umbraco Scotland community together to share ideas and insights.]]></description>
                    <pubDate>Wed, 13 May 2026 09:00:58 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.holdyourhorses</guid>
                    <title>Umbraco.Community.HoldYourHorses</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.holdyourhorses</link>
                    <description><![CDATA[Replaces the Save and Publish button in the Umbraco backoffice with a configurable, cancellable countdown &#x2014; gives editors a short window to catch mistakes before content goes live.]]></description>
                    <pubDate>Wed, 13 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.smartredirectsuggester</guid>
                    <title>Umbraco.Community.SmartRedirectSuggester</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.smartredirectsuggester</link>
                    <description><![CDATA[Improve the Umbraco trash flow by suggesting redirect targets for published content before it is moved to the recycle bin.]]></description>
                    <pubDate>Wed, 13 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/doctypedoctor</guid>
                    <title>DocTypeDoctor</title>
                    <link>https://marketplace.umbraco.com/package/doctypedoctor</link>
                    <description><![CDATA[...]]></description>
                    <pubDate>Wed, 13 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://docs.umbraco.com/umbraco-cloud/release-notes/overview-2026/2026-05-releasenotes</guid>
                    <title>May 2026 Cloud Release Notes</title>
                    <link>https://docs.umbraco.com/umbraco-cloud/release-notes/overview-2026/2026-05-releasenotes</link>
                    <description><![CDATA[May 2026 | Cloud | Umbraco Documentation]]></description>
                    <pubDate>Tue, 12 May 2026 15:21:19 Z</pubDate>
                        <category>hq</category>
                </item>
                <item>
                    <guid>https://www.etive-mor.com/blog/carlini-style-vulnerability-hunting-on-a-budget/</guid>
                    <title>Carlini-style software vulnerability hunting, on a budget</title>
                    <link>https://www.etive-mor.com/blog/carlini-style-vulnerability-hunting-on-a-budget/</link>
                    <description><![CDATA[https://www.etive-mor.com/blog/carlini-style-vulnerability-hunting-on-a-budget/Nicholas Carlini did a great talk at [un]prompted a few weeks ago, where he detailed how Anthropic were using LLMs to automate software vulnerability discovery. In this post, I take a look at replicating his process in the Umbraco-CMS repository, for less than 1% the cost.#umbraco #security #llm #ai]]></description>
                    <pubDate>Tue, 12 May 2026 13:31:23 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@owaincodes/116561041760397682</guid>
                    <title>The new H5YR.com widget is now LIVE!</title>
                    <link>https://umbracocommunity.social/@owaincodes/116561041760397682</link>
                    <description><![CDATA[The new H5YR.com widget is now LIVE! https://h5yr.com/h5yr-widget/ #umbraco]]></description>
                    <pubDate>Tue, 12 May 2026 13:01:00 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@owaincodes/116560322535140460</guid>
                    <title>H5YR.com is now on Umbraco 17</title>
                    <link>https://umbracocommunity.social/@owaincodes/116560322535140460</link>
                    <description><![CDATA[H5YR.com is now on #Umbraco 17 &#x1F389; Thanks @UmbHost for the help with the deployment yesterday. #h5yr]]></description>
                    <pubDate>Tue, 12 May 2026 07:08:15 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://www.linkedin.com/posts/owainwilliams_h5yr-community-umbraco-share-7459538862323924992-iV5D/</guid>
                    <title>H5YR embeddable widget progress</title>
                    <link>https://www.linkedin.com/posts/owainwilliams_h5yr-community-umbraco-share-7459538862323924992-iV5D/</link>
                    <description><![CDATA[H5YR update: https://www.linkedin.com/posts/owainwilliams_h5yr-community-umbraco-share-7459538862323924992-iV5D?utm_source=share&amp;utm_medium=member_ios&amp;rcm=ACoAAABj9KwBjr581HKBv-M3TbQu69Ia79rmfPw&#xA;&#xA;Sent from my iPhone]]></description>
                    <pubDate>Mon, 11 May 2026 16:52:10 Z</pubDate>
                        <category>linkedin</category>
                        <category>community</category>
                        <category>social</category>
                </item>
                <item>
                    <guid>https://codeshare.co.uk/blog/designing-an-ai-agent-skill-for-adding-a-page-type-to-umbraco/</guid>
                    <title>Designing an AI Agent skill for adding a page type to Umbraco</title>
                    <link>https://codeshare.co.uk/blog/designing-an-ai-agent-skill-for-adding-a-page-type-to-umbraco/</link>
                    <description><![CDATA[Explore how experienced developers are building AI skills to scaffold Umbraco features. See the conventions and decisions that make page type creation effortless.]]></description>
                    <pubDate>Mon, 11 May 2026 11:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.linkedin.com/posts/adamshallcross_quick-update-on-the-ai-search-package-im-ugcPost-7457449420633042944-t2zb</guid>
                    <title>Adam Shallcross AI based search package progress</title>
                    <link>https://www.linkedin.com/posts/adamshallcross_quick-update-on-the-ai-search-package-im-ugcPost-7457449420633042944-t2zb</link>
                    <description><![CDATA[Untitled: https://www.linkedin.com/posts/adamshallcross_quick-update-on-the-ai-search-package-im-ugcPost-7457449420633042944-t2zb?utm_source=share&amp;utm_medium=member_ios&amp;rcm=ACoAAABj9KwBjr581HKBv-M3TbQu69Ia79rmfPw&#xA;&#xA;Sent from my iPhone]]></description>
                    <pubDate>Mon, 11 May 2026 06:41:24 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>linkedin</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/diplo.translator</guid>
                    <title>Diplo Translator</title>
                    <link>https://marketplace.umbraco.com/package/diplo.translator</link>
                    <description><![CDATA[Diplo Translator | Umbraco Marketplace]]></description>
                    <pubDate>Fri, 08 May 2026 08:28:41 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.ai.chatbot</guid>
                    <title>Umbraco.Community.AI.Chatbot</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.ai.chatbot</link>
                    <description><![CDATA[Drops a public-facing, AI-powered chat widget on a website&#x27;s frontend. End users on the public site type a question; the package runs a semantic search over the site&#x27;s Umbraco content (Umbraco.AI.Search), feeds the matched pages into an Umbraco.AI.Agent, and streams a grounded answer back with cited source pages and follow-up suggestions.&#xA;&#xA;The official Umbraco.AI.* packages expose chat only inside the backoffice. There is no path for an anonymous site visitor to ask questions of the site&#x27;s content. This community package fills that gap.&#xA;&#xA;Key features:&#xA;- Public-facing widget (drop in one &lt;script&gt; tag)&#xA;- Grounded answers with cited source pages&#xA;- Suggested follow-up questions&#xA;- Streaming responses (SSE)&#xA;- Per-IP rate limiting and request size caps&#xA;- Per-instance configuration in the backoffice (welcome message, agent, fallback)&#xA;&#xA;Requires Umbraco CMS 17.3&#x2B;, Umbraco.AI 1.10&#x2B;, Umbraco.AI.Agent 1.9&#x2B;, and a populated Umbraco.AI.Search index.]]></description>
                    <pubDate>Fri, 08 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://dev.to/cultiv/bootstrapping-umbraco-modelsbuilder-on-an-empty-site-age</guid>
                    <title>Bootstrapping Umbraco ModelsBuilder on an empty site</title>
                    <link>https://dev.to/cultiv/bootstrapping-umbraco-modelsbuilder-on-an-empty-site-age</link>
                    <description><![CDATA[&lt;p&gt;The rest of this post was written with Claude AI. Here&#x27;s the simple problem I seem to get myself into often: &lt;/p&gt;&#xA;&#xA;&lt;p&gt;I have views that need a strongly typed model, but modelsbuilder hasn&#x27;t put the models on disk so Umbraco completely fails to start. &lt;code&gt;dotnet run&lt;/code&gt; just fails &#x1F631; But I need to get into the backoffice to generate the models; difficult when Umbraco doesn&#x27;t even run.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;After I encountered this today, I finally took some time to figure out what the easiest way is to get this fixed. What follows is the summary of what Claude did for me:&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Dropped a set of strongly-typed views (&lt;code&gt;home.cshtml&lt;/code&gt;, &lt;code&gt;Author.cshtml&lt;/code&gt;, etc.) into a fresh Umbraco site and ran straight into the chicken-and-egg problem every Umbraco developer eventually meets:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The views reference &lt;code&gt;Umbraco.Cms.Web.Common.PublishedModels.Home&lt;/code&gt; (and friends).&lt;/li&gt;&#xA;&lt;li&gt;Those classes are generated by ModelsBuilder from document types that live in the database.&lt;/li&gt;&#xA;&lt;li&gt;The database is empty until the site has run at least once.&lt;/li&gt;&#xA;&lt;li&gt;The site won&#x27;t build because the views don&#x27;t compile, so it can&#x27;t run.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;Here&#x27;s the little dance to break the cycle.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  1. Turn off Razor compile-on-build&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;In the &lt;code&gt;.csproj&lt;/code&gt;:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight xml&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;RazorCompileOnBuild&amp;gt;&lt;/span&gt;false&lt;span class=&quot;nt&quot;&gt;&amp;lt;/RazorCompileOnBuild&amp;gt;&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;The build now skips the views entirely instead of failing on the missing &lt;code&gt;PublishedModels.*&lt;/code&gt; types.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  2. Switch ModelsBuilder to manual mode&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;In &lt;code&gt;appsettings.json&lt;/code&gt;:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ModelsBuilder&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ModelsMode&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;SourceCodeManual&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;code&gt;SourceCodeManual&lt;/code&gt; is the only mode that gives you a &lt;strong&gt;Generate models&lt;/strong&gt; button in the backoffice. The other three:&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Mode&lt;/th&gt;&#xA;&lt;th&gt;Files?&lt;/th&gt;&#xA;&lt;th&gt;Trigger&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;Nothing&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;none&lt;/td&gt;&#xA;&lt;td&gt;&#x2014;&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;InMemoryAuto&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;in-memory only&lt;/td&gt;&#xA;&lt;td&gt;auto&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;SourceCodeManual&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;~/umbraco/models/*.cs&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;&lt;strong&gt;button&lt;/strong&gt;&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;SourceCodeAuto&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;~/umbraco/models/*.cs&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;auto on schema change&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&lt;/div&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  3. Start the site&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;&lt;code&gt;dotnet run&lt;/code&gt;. The build succeeds (views aren&#x27;t compiled), the app starts, and the backoffice comes up. Frontend pages will 404 or 500 right now &#x2014; that&#x27;s expected and we don&#x27;t care yet.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  4. Click the button&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Backoffice &#x2192; &lt;strong&gt;Settings &#x2192; Models Builder &#x2192; Generate models&lt;/strong&gt;.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;code&gt;.cs&lt;/code&gt; files appear in &lt;code&gt;umbraco/models/&lt;/code&gt; &#x2014; one per document type. These are the classes the views were waiting on.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  5. Stop the site&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;&lt;code&gt;Ctrl&#x2B;C&lt;/code&gt;.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  6. Re-enable Razor compile-on-build&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Remove the line we added in step 1:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight xml&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- &amp;lt;RazorCompileOnBuild&amp;gt;false&amp;lt;/RazorCompileOnBuild&amp;gt;  &#x2190; delete this --&amp;gt;&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  7. Start the site again&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;&lt;code&gt;dotnet run&lt;/code&gt;. Build picks up the generated models, compiles the views against them, the home page renders.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Why the dance is needed&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;&lt;code&gt;RazorCompileOnBuild=false&lt;/code&gt; alone isn&#x27;t a real fix &#x2014; it just moves the compile error from build time to the moment a frontend page is hit. Without runtime compilation registered, Umbraco&#x27;s view-engine lookup returns &quot;no physical template file found&quot; and serves a 404. You&#x27;ll see this in the logs:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;&quot;No physical template file was found for template home&quot;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;The actual fix is to get the models on disk. The flag just buys you the brief window between &quot;build doesn&#x27;t run&quot; and &quot;models exist&quot; so you can boot the backoffice and press the button.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Once the models are committed to source control, none of this matters &#x2014; the next clone builds clean from the start.&lt;/p&gt;]]></description>
                    <pubDate>Thu, 07 May 2026 15:24:58 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://examinex.online/2026/04/16/ai-semantic-ranking-for-azure-search</guid>
                    <title>AI Semantic Ranking with ExamineX and Azure Search</title>
                    <link>https://examinex.online/2026/04/16/ai-semantic-ranking-for-azure-search</link>
                    <description><![CDATA[AI Semantic Ranking with ExamineX and Azure Search]]></description>
                    <pubDate>Thu, 07 May 2026 14:36:09 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://samsolutions.medium.com/umbraco-vs-wordpress-which-cms-platform-is-best-for-your-business-43863d7710c9?source=rss------umbraco-5</guid>
                    <title>Umbraco vs WordPress: Which CMS Platform Is Best for Your Business?</title>
                    <link>https://samsolutions.medium.com/umbraco-vs-wordpress-which-cms-platform-is-best-for-your-business-43863d7710c9?source=rss------umbraco-5</link>
                    <description><![CDATA[&lt;div class=&quot;medium-feed-item&quot;&gt;&lt;p class=&quot;medium-feed-image&quot;&gt;&lt;a href=&quot;https://samsolutions.medium.com/umbraco-vs-wordpress-which-cms-platform-is-best-for-your-business-43863d7710c9?source=rss------umbraco-5&quot;&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1536/1*dxgdjM-1uAleskWDzfMX1Q.png&quot; width=&quot;1536&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;medium-feed-snippet&quot;&gt;Choosing the right Content Management System (CMS) is a foundational decision for any digital strategy. The market offers a wide spectrum&amp;#x2026;&lt;/p&gt;&lt;p class=&quot;medium-feed-link&quot;&gt;&lt;a href=&quot;https://samsolutions.medium.com/umbraco-vs-wordpress-which-cms-platform-is-best-for-your-business-43863d7710c9?source=rss------umbraco-5&quot;&gt;Continue reading on Medium &#xBB;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;]]></description>
                    <pubDate>Thu, 07 May 2026 14:31:51 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://github.com/umbraco/Announcements/issues/35</guid>
                    <title>[Breaking change]: Remove the built-in Bootstrap 3 horizontal forms theme from Umbraco Forms</title>
                    <link>https://github.com/umbraco/Announcements/issues/35</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Thu, 07 May 2026 14:02:35 Z</pubDate>
                        <category>hq</category>
                        <category>announcement</category>
                </item>
                <item>
                    <guid>https://github.com/umbraco/Announcements/issues/34</guid>
                    <title>[Breaking change]: Replace Pikaday with native HTML date input in the Umbraco Forms default theme</title>
                    <link>https://github.com/umbraco/Announcements/issues/34</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Thu, 07 May 2026 14:00:29 Z</pubDate>
                        <category>hq</category>
                        <category>announcement</category>
                </item>
                <item>
                    <guid>https://github.com/umbraco/Announcements/issues/33</guid>
                    <title>[Breaking change]: Remove jQuery Validation support from Umbraco Forms client-side scripts</title>
                    <link>https://github.com/umbraco/Announcements/issues/33</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Thu, 07 May 2026 13:58:03 Z</pubDate>
                        <category>hq</category>
                        <category>announcement</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/webwonders.umbraco.blockpicker</guid>
                    <title>Webwonders.Umbraco.BlockPicker</title>
                    <link>https://marketplace.umbraco.com/package/webwonders.umbraco.blockpicker</link>
                    <description><![CDATA[A block picker property editor for Umbraco.]]></description>
                    <pubDate>Thu, 07 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.mistral</guid>
                    <title>Umbraco.AI.Mistral</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.mistral</link>
                    <description><![CDATA[Mistral provider for Umbraco AI]]></description>
                    <pubDate>Thu, 07 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.togetherai</guid>
                    <title>Umbraco.AI.TogetherAI</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.togetherai</link>
                    <description><![CDATA[Together AI provider for Umbraco AI]]></description>
                    <pubDate>Thu, 07 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.fireworksai</guid>
                    <title>Umbraco.AI.FireworksAI</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.fireworksai</link>
                    <description><![CDATA[Fireworks AI provider for Umbraco AI]]></description>
                    <pubDate>Thu, 07 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.huggingface</guid>
                    <title>Umbraco.AI.HuggingFace</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.huggingface</link>
                    <description><![CDATA[Hugging Face Inference Providers integration for Umbraco AI]]></description>
                    <pubDate>Thu, 07 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.deepseek</guid>
                    <title>Umbraco.AI.DeepSeek</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.deepseek</link>
                    <description><![CDATA[DeepSeek provider for Umbraco AI]]></description>
                    <pubDate>Thu, 07 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.aivisibility</guid>
                    <title>Umbraco.Community.AiVisibility</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.aivisibility</link>
                    <description><![CDATA[Make your Umbraco site visible to AI search engines (ChatGPT, Claude, Perplexity, Gemini, Bing Copilot) and give editors visibility into who&#x27;s reading the site. Drop-in for Umbraco v17&#x2B; with zero configuration on a typical site.&#xA;&#xA;At install time, every published page becomes reachable as Markdown via /{path}.md or via the standard Accept: text/markdown content negotiation header. Two more public routes ship: /llms.txt (an RFC-style index of every published page) and /llms-full.txt (the concatenated full-Markdown export, hard-capped at a configurable byte limit). All three surfaces are publish-driven cache invalidated and hot-path-protected (If-None-Match &#x2192; 304 &#x2192; single-flight on cache miss).&#xA;&#xA;Two Backoffice dashboards appear under Settings: AI Visibility (site name, summary, per-doctype exclusion, per-page opt-out) and AI Traffic (read-only dashboard showing every AI / human / crawler hit by classification, with date filtering). A Health Check warns when /robots.txt blocks AI crawlers you might not want to block.&#xA;&#xA;Architectural principle: the Umbraco template is the canonical visual form of content. The package renders pages through Umbraco&#x27;s normal Razor pipeline and converts the resulting HTML to Markdown &#x2014; it does NOT walk content properties or template-fork. Whatever your Razor templates produce (Block List, Block Grid, view components, third-party renderers) is what the AI gets, in clean Markdown form.&#xA;&#xA;Six DI extension points let you override extraction, request logging, robots auditing, settings resolution, and UA classification without forking. Apache 2.0 licensed.]]></description>
                    <pubDate>Thu, 07 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://forum.umbraco.com/t/god-mode-v17-finally/7983</guid>
                    <title>God Mode v17 now available</title>
                    <link>https://forum.umbraco.com/t/god-mode-v17-finally/7983</link>
                    <description><![CDATA[God Mode v17 - finally! - Umbraco community forum]]></description>
                    <pubDate>Wed, 06 May 2026 12:37:11 Z</pubDate>
                        <category>community</category>
                        <category>forum</category>
                </item>
                <item>
                    <guid>https://kjac.dev/posts/personalisation-groups-as-segments/</guid>
                    <title>Personalisation Groups as segments</title>
                    <link>https://kjac.dev/posts/personalisation-groups-as-segments/</link>
                    <description><![CDATA[Using the Personalisation Groups package to power segments in Umbraco.]]></description>
                    <pubDate>Wed, 06 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://dev.to/luukpeters/advanced-permissions-for-umbraco-advanced-control-for-complex-scenarios-3fk3</guid>
                    <title>Advanced Permissions for Umbraco: Advanced Control for Complex Scenarios</title>
                    <link>https://dev.to/luukpeters/advanced-permissions-for-umbraco-advanced-control-for-complex-scenarios-3fk3</link>
                    <description><![CDATA[&lt;p&gt;&lt;em&gt;Quick note: I write these blogs myself, AI only redacts them.&lt;/em&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;I&#x27;m excited to announce that I just released my very first open source Umbraco community package: &lt;strong&gt;Advanced Permissions for Umbraco&lt;/strong&gt;. In this post, I&#x27;ll explain why I created this package, what it adds to Umbraco&#x27;s permission system, and when you&#x27;d want to use it.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Why This Package Exists&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;I&#x27;ve been working with Umbraco since version 4, mostly in an agency context working with enterprise clients. That experience shaped what I value: features that matter at scale. Many of our clients have marketing departments with multiple users and multiple user groups&#x2014;and eventually they reach scenarios where Umbraco&#x27;s built-in permissions don&#x27;t quite fit.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;I wrote about these scenarios in a &lt;a href=&quot;https://github.com/umbraco/Umbraco-CMS/discussions/18018&quot; rel=&quot;noopener noreferrer&quot;&gt;GitHub discussion&lt;/a&gt; a while back. The current permission system works fine for many use cases. But when your organizational structure gets more complex, you hit some constraints. This package is designed for those situations where you need more granular control.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The Current Permission System (In a Nutshell)&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;To really understand the benefits of Advanced Permissions, you first need to understand the default Umbraco permission system. Here&#x27;s how it works:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;You assign default permissions to a User Group by toggling a list of verbs: &lt;em&gt;Create&lt;/em&gt;, &lt;em&gt;Delete&lt;/em&gt;, &lt;em&gt;Cultures and Hostnames&lt;/em&gt;, &lt;em&gt;Publish&lt;/em&gt;, and so on. Users with that group inherit those permissions.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkbkzzf4dqcsw2307ji8.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkbkzzf4dqcsw2307ji8.png&quot; alt=&quot;Umbraco&#x27;s default permission system&quot; width=&quot;800&quot; height=&quot;500&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;You can also override these permissions on specific nodes, and those overrides apply to that node and all its descendants. It&#x27;s straightforward and handles most workflows well.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Where It Reaches Its Limits&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Grant Types and Inheritance&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;In Umbraco, you set default permissions on a User Group, and then you can override those on specific nodes. But here&#x27;s the catch&#x2014;when you override permissions on a node, those node-specific permissions completely replace the defaults. There&#x27;s no inheritance.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;So if you want to change just one permission on a node (say, disallow Delete), you have to specify every single permission at that node level. You can&#x27;t say &quot;inherit everything from the default and only change this one thing.&quot; You end up copying all the default permissions to the node level just to tweak one, which is error-prone and a maintenance nightmare. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;And because permissions are just toggles&#x2014;allow (checked) or deny (unchecked)&#x2014;there&#x27;s really only &quot;allow&quot; and a sort of implicit &quot;not-allow.&quot; There&#x27;s no way to explicitly deny something. This matters when you have multiple User Groups on a single user: all their permissions just stack up. You can only gain permissions, never restrict them.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Scope&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Node permissions always apply to a node and its descendants. You can&#x27;t set permissions on just the node itself, or just on descendants.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Take an employee directory: an overview page with employee pages underneath. Ideally, you&#x27;d want editors to leave the overview page alone but be able to delete individual employee pages as they leave. The current system doesn&#x27;t support that directly.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Multiple User Groups&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;When a user has multiple groups, their effective permissions are the combined list of everything allowed across those groups. There&#x27;s no way to say &quot;this group can do X, but that specific group cannot delete content.&quot; You get the union of all their permissions.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  What Advanced Permissions Adds&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The package introduces three capabilities for when you need more control:&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Three Grant Types (Allow, Deny, Inherit)&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Instead of just allow/deny, you get:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Allow&lt;/strong&gt;: explicitly permit something&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Deny&lt;/strong&gt;: explicitly forbid something&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Inherit&lt;/strong&gt;: use whatever the ancestor nodes specifies&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxjo7zq8gf19tk6ae9g9b.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxjo7zq8gf19tk6ae9g9b.png&quot; alt=&quot; &quot; width=&quot;533&quot; height=&quot;480&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This means you only need to set the permissions you want to change and let everything else inherit from above. No more duplicating every permission just to tweak one.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Flexible Scopes&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Choose where permissions apply:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Node &#x2B; Descendants&lt;/strong&gt; (the standard Umbraco behavior)&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Node Only&lt;/strong&gt; (children inherit from ancestors above)&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Descendants Only&lt;/strong&gt; (the node itself isn&#x27;t affected)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;You can combine node-only and descendants-only permissions on the same node to set different rules for a parent and its children.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwe2s1ftb17h24rx2af5n.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwe2s1ftb17h24rx2af5n.png&quot; alt=&quot; &quot; width=&quot;532&quot; height=&quot;483&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Smart Permission Resolution&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Advanced Permissions includes a resolver that calculates your actual permissions based on priority:&lt;/p&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Explicit deny (takes precedence)&lt;/li&gt;&#xA;&lt;li&gt;Explicit allow&lt;/li&gt;&#xA;&lt;li&gt;Implicit deny&lt;/li&gt;&#xA;&lt;li&gt;Implicit allow&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;p&gt;It handles multiple User Groups intelligently across all of them.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Apply Permissions to Everyone&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;There&#x27;s a virtual &quot;All Users&quot; group for permissions that should apply to everyone. Useful for nodes that should never be deleted, for example. It works like any other group from the resolver&#x27;s perspective.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkbflq4le9ck1t4blfntd.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkbflq4le9ck1t4blfntd.png&quot; alt=&quot; &quot; width=&quot;800&quot; height=&quot;178&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  The Access Viewer&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;To understand your actual permissions when things get complex, there&#x27;s an Access Viewer that shows your effective permissions for any user or group. Click on any permission and see the resolver chain that determined it.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2uymz3li28lo21sqfg15.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2uymz3li28lo21sqfg15.png&quot; alt=&quot; &quot; width=&quot;800&quot; height=&quot;433&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  When You&#x27;d Use This&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;You&#x27;d reach for Advanced Permissions when your permission requirements get complex&#x2014;multiple teams with overlapping responsibilities, permissions that need to vary significantly across your content tree, or organizational structures that don&#x27;t fit neatly into the standard model.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;For straightforward scenarios, Umbraco&#x27;s built-in permissions work great and you probably don&#x27;t need this. But when you&#x27;re managing access across a large, complex organization, Advanced Permissions gives you the control you need.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;You can find the package on the &lt;a href=&quot;https://marketplace.umbraco.com/package/umbraco.community.advancedpermissions&quot; rel=&quot;noopener noreferrer&quot;&gt;Umbraco marketplace&lt;/a&gt;.&lt;/p&gt;]]></description>
                    <pubDate>Tue, 05 May 2026 20:56:44 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://skrift.io/issues/#127</guid>
                    <title>Skrift Issue #127</title>
                    <link>https://skrift.io/issues/#127</link>
                    <description><![CDATA[Featuring guest posts by Dean Leigh on &quot;Document Everything Everywhere All At Once&quot; and Allen Smith on &quot;Deconstructing Umbraco Compose&quot;]]></description>
                    <pubDate>Tue, 05 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                        <category>skrift</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/ai12z.umbraco.widgets</guid>
                    <title>Ai12z.Umbraco.Widgets</title>
                    <link>https://marketplace.umbraco.com/package/ai12z.umbraco.widgets</link>
                    <description><![CDATA[Drag-and-drop ai12z widgets for Umbraco CMS &#x2014; chatbot, CTA search, knowledge box, search results, forms, and containers. Renders native Umbraco Block List elements that emit ai12z web component tags.]]></description>
                    <pubDate>Tue, 05 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://github.com/Ambertvu/Umbraco.Community.AdminOnly</guid>
                    <title>Umbraco.Community.AdminOnly</title>
                    <link>https://github.com/Ambertvu/Umbraco.Community.AdminOnly</link>
                    <description><![CDATA[https://github.com/Ambertvu/Umbraco.Community.AdminOnly&#xA;&#xA;Another new package!&#xA;AdminOnly lets administrators hide document types, tabs and properties from everyone who isn&#x27;t an admin &#x2014; without touching user groups, permissions or document type structure. Editors see only what&#x27;s relevant to their work; admins keep the full picture, with a &#x1F512; indicator next to every hidden item.&#xA;&#xA;Heads up &#x2014; this is a backoffice UX layer, not server-side authorization. Hidden items are removed from the UI, but the underlying Umbraco APIs are untouched. A determined user with developer tools can still reach hidden content.]]></description>
                    <pubDate>Mon, 04 May 2026 14:14:48 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://skttl.dev/blog/umbraco-cloud-fetch-database-and-media/</guid>
                    <title>Two Umbraco Cloud CLI spinoffs: fetch DB and media into your local dev</title>
                    <link>https://skttl.dev/blog/umbraco-cloud-fetch-database-and-media/</link>
                    <description><![CDATA[Two Umbraco Cloud CLI spinoffs: fetch DB and media into your local dev | skttl.dev]]></description>
                    <pubDate>Mon, 04 May 2026 11:37:40 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/may/a-weekend-without-internet-access/</guid>
                    <title>A weekend without internet access</title>
                    <link>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/may/a-weekend-without-internet-access/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 04 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owaincodes.uksouth01.umbraco.io/blog/2026/may/a-weekend-without-internet-access/</guid>
                    <title>A weekend without internet access</title>
                    <link>https://owaincodes.uksouth01.umbraco.io/blog/2026/may/a-weekend-without-internet-access/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 04 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/may/a-weekend-without-internet-access/</guid>
                    <title>A weekend without internet access</title>
                    <link>https://owain.codes/blog/2026/may/a-weekend-without-internet-access/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 04 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://bsky.app/profile/owain.codes/post/3mkwtz5dbwt24</guid>
                    <title>Ideas wanted for h5yr.com</title>
                    <link>https://bsky.app/profile/owain.codes/post/3mkwtz5dbwt24</link>
                    <description><![CDATA[Calling all #Umbraco friends. &#xA;&#xA;Im relaunching h5yr.com and I want all your ideas on what features we can build for the site. &#xA;&#xA;Add your ideas to the issues tracker in github.com/H5YR/High5Yo...&#xA;&#xA;Then together, as a community, we&#x27;ll build them!&#xA;&#xA;]]></description>
                    <pubDate>Sun, 03 May 2026 09:37:39 Z</pubDate>
                        <category>community</category>
                        <category>bluesky</category>
                        <category>social</category>
                </item>
                <item>
                    <guid>https://www.enkelmedia.se/blogg/2026/5/1/umbraco-member-thrown-out-after-changing-password?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=rss</guid>
                    <title>Umbraco Member thrown out after changing password</title>
                    <link>https://www.enkelmedia.se/blogg/2026/5/1/umbraco-member-thrown-out-after-changing-password?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=rss</link>
                    <description><![CDATA[&lt;p&gt;I&#x27;m working with a migration of the website for my Umbraco-package &lt;a rel=&quot;noopener&quot; href=&quot;https://www.newsletterstudio.org&quot; target=&quot;_blank&quot;&gt;Newsletter Studio&lt;/a&gt;, from Umbraco 8 to Umbraco 17.&lt;/p&gt;&#xA;&lt;p&gt;I use Umbraco Members to allow customers to login and manage their licenses, update information and download receipts.&lt;/p&gt;&#xA;&lt;h2&gt;New password = Member logged out&lt;/h2&gt;&#xA;&lt;p&gt;When I was working on a feature to allow customers to change password, I noticed that I kept getting thrown out from the logged in area of the website after changing the password.&lt;/p&gt;&#xA;&lt;p&gt;The Member was throw out both:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;When they change password them selfs&lt;/li&gt;&#xA;&lt;li&gt;When the password was changed in from the backoffice&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I searched around for this, and it turns out that this is security feature.&lt;/p&gt;&#xA;&lt;p&gt;Umbraco has introduce settings around concurrent logins both for Users and Members, in appsettings.json one can configure these&lt;/p&gt;&#xA;&lt;div&gt;&#xD;&#xA;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;quot;Umbraco&amp;quot;: {&#xA;    &amp;quot;CMS&amp;quot;: {      &#xA;        &amp;quot;Security&amp;quot;: {&#xA;            &amp;quot;AllowConcurrentLogins&amp;quot;: false&#xA;            &amp;quot;MemberAllowConcurrentLogins&amp;quot;: false&#xA;        }&#xA;    }&#xA;}&lt;/code&gt;&lt;/pre&gt;&#xD;&#xA;&lt;/div&gt;&#xD;&#xA;&#xD;&#xA;&#xA;&lt;p&gt;According to the &lt;a rel=&quot;noopener&quot; href=&quot;https://docs.umbraco.com/umbraco-cms/reference/configuration/securitysettings&quot; target=&quot;_blank&quot;&gt;documentation&lt;/a&gt;, MemberAllowConcurrentLogins will fallback to the value of AllowConcurrentLogins, which is set to false by default.&lt;/p&gt;&#xA;&lt;h2&gt;What happened?&lt;/h2&gt;&#xA;&lt;p&gt;When the user changed the password, it looked like a new login, since this was not allowed the user was thrown out.&lt;/p&gt;&#xA;&lt;p&gt;There is two ways around this, one could refresh the users login cookie by calling _memberSignInManager.SignInAsync() after the password change.&lt;/p&gt;&#xA;&lt;div&gt;&#xD;&#xA;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;var currentMember = await _memberManager.GetCurrentMemberAsync();&#xA;&#xA;var currentPasswordIsValid = await _memberManager.ValidateCredentialsAsync(currentMember.UserName!, model.CurrentPassword!);&#xA;if (!currentPasswordIsValid)&#xA;{&#xA;    return Error();&#xA;}&#xA;&#xA;var changePasswordResult = await _memberManager.ChangePasswordAsync(&#xA;    currentMember,&#xA;    model.CurrentPassword!,&#xA;    model.NewPassword!);&#xA;&#xA;if (!changePasswordResult.Succeeded)&#xA;{&#xA;    return Error();&#xA;}&#xA;&#xA;// Refresh member authentication cookie&#xA;await _memberSignInManager.SignInAsync(currentMember, true, &amp;quot;&amp;quot;);&lt;/code&gt;&lt;/pre&gt;&#xD;&#xA;&lt;/div&gt;&#xD;&#xA;&#xD;&#xA;&#xA;&lt;p&gt;&#xA0;Or, one could set AllowConcurrentLogins to true.&lt;/p&gt;&#xA;&lt;p&gt;&#xA0;&lt;/p&gt;&#xA;&lt;p&gt;&#xA0;&lt;/p&gt;&#xA;&lt;p&gt;&#xA0;&lt;/p&gt;]]></description>
                    <pubDate>Fri, 01 May 2026 10:59:59 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://codeshare.co.uk/blog/how-i-used-the-new-umbraco-search-on-my-website/</guid>
                    <title>How I used the new Umbraco Search on my website</title>
                    <link>https://codeshare.co.uk/blog/how-i-used-the-new-umbraco-search-on-my-website/</link>
                    <description><![CDATA[Discover how I added powerful search to my blog with category filters and smart sorting. Real-world lessons from building search with Umbraco&amp;#x27;s new platform.]]></description>
                    <pubDate>Fri, 01 May 2026 10:30:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.advancedpermissions</guid>
                    <title>Umbraco.Community.AdvancedPermissions</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.advancedpermissions</link>
                    <description><![CDATA[Fine-grained permission management for Umbraco that extends the built-in permission system with the controls it lacks: explicit Allow and Deny entries, per-entry scope control (This Node Only, This Node and Descendants, Descendants Only), an All Users Group that applies to every user, and a full reasoning chain that explains why each permission was granted or denied.&#xA;&#xA;Got a critical node that must never be deleted? Set an explicit Deny for Delete on that node for the All Users Group. From that point on, the node cannot be deleted by anyone, from any user group, under any circumstances. An explicit Deny is absolute: nothing overrides it, not an inherited Allow, not an explicit Allow from another user group on the same node. The only way to lift the lock is to remove or edit that one entry. The same pattern works for any permission on any node: lock unpublishing on landing pages, block edits to integration nodes, enforce any other global safety rule.&#xA;&#xA;Adds two menu items to the Users section of the backoffice: a Permissions Editor for managing entries per user group across the content tree, and an Access Viewer for inspecting effective permissions with full reasoning. On first boot the package imports the permissions from your existing user groups automatically, so your current security setup carries over without any manual migration. New user groups created later are seeded the same way.]]></description>
                    <pubDate>Fri, 01 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.linkedin.com/posts/adamshallcross_so-like-london-buses-it-seems-my-mind-works-ugcPost-7455570629501734912-4wP7?utm_source=share&amp;utm_medium=member_ios&amp;rcm=ACoAAABj9KwBjr581HKBv-M3TbQu69Ia79rmfPw</guid>
                    <title>Introducing LlmsTxt.Umbraco</title>
                    <link>https://www.linkedin.com/posts/adamshallcross_so-like-london-buses-it-seems-my-mind-works-ugcPost-7455570629501734912-4wP7?utm_source=share&amp;utm_medium=member_ios&amp;rcm=ACoAAABj9KwBjr581HKBv-M3TbQu69Ia79rmfPw</link>
                    <description><![CDATA[Untitled: https://www.linkedin.com/posts/adamshallcross_so-like-london-buses-it-seems-my-mind-works-ugcPost-7455570629501734912-4wP7?utm_source=share&amp;utm_medium=member_ios&amp;rcm=ACoAAABj9KwBjr581HKBv-M3TbQu69Ia79rmfPw&#xA;&#xA;Sent from my iPhone]]></description>
                    <pubDate>Thu, 30 Apr 2026 11:08:48 Z</pubDate>
                        <category>social</category>
                        <category>linkedin</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://github.com/umbraco/Announcements/issues/32</guid>
                    <title>[Breaking change]: Replace `Swashbuckle.AspNetCore` with `Microsoft.AspNetCore.OpenApi` for Open API document generation</title>
                    <link>https://github.com/umbraco/Announcements/issues/32</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 29 Apr 2026 13:19:40 Z</pubDate>
                        <category>hq</category>
                        <category>announcement</category>
                </item>
                <item>
                    <guid>https://skttl.dev/blog/umbraco-cloud-archiver/</guid>
                    <title>I built a CLI to archive Umbraco Cloud projects</title>
                    <link>https://skttl.dev/blog/umbraco-cloud-archiver/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 29 Apr 2026 10:57:01 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://www.proworks.com/blog/archive/umbraco-ai-page-evaluator/</guid>
                    <title>Catch Weak Content Before It Goes Live with ProWorks Umbraco.AI Page Evaluator</title>
                    <link>https://www.proworks.com/blog/archive/umbraco-ai-page-evaluator/</link>
                    <description><![CDATA[&lt;p&gt;In this day and age, its more important than ever to keep your website content clear, consistent, and on brand. AI infers what your organization does from what it reads on your website and, yes, it reads ALL of your content. Couple this with the rise of AI tools used to outline, write, and enhance marketing content, the risk of publishing AI slop (or even inaccurate information) is high. This is where the &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://github.com/ProWorksCorporation/ProWorks-Umbraco.AI-Page-Evaluator&quot; target=&quot;_blank&quot; title=&quot;ProWorks Umbraco.AI Page Evaluator&quot;&gt;ProWorks Umbraco.AI Page Evaluator&lt;/a&gt; shines.&lt;/p&gt;&#xA;&lt;h2&gt;What Is AI-Powered Page Evaluation?&lt;/h2&gt;&#xA;&lt;p&gt;AI-powered page evaluation uses a large language model (LLM) to analyze your page content and return structured feedback on key page indicators.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A &lt;strong&gt;landing page&lt;/strong&gt; can be evaluated and scored for clarity, messaging strength, objection handling, message hierarchy, and the call to action.&lt;/li&gt;&#xA;&lt;li&gt;A standard &lt;strong&gt;content page&lt;/strong&gt; can be evaluated on SEO performance, AEO/GEO performance, and accessibility compliance.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;All pages&lt;/strong&gt; can be evaluated based on brand guidelines, brand voice, and how it supports the organization&#x27;s marketing strategy.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2&gt;What is ProWorks Umbraco.AI Page Evaluator (AI Page Evaluator)?&lt;/h2&gt;&#xA;&lt;p&gt;Our AI Page Evaluator is an open-source add-on to the &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://github.com/umbraco/Umbraco.AI/&quot; target=&quot;_blank&quot; title=&quot;Umbraco.AI&quot;&gt;Umbraco.AI&lt;/a&gt; framework, which adds a back-office Evaluate Page button you can simply click on to send the page&#x27;s content to an AI model and return a structured quality report directly inside the back-office, including scored checks, warnings, and actionable suggestions.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;https://www.proworks.com/media/uzfpov4h/screenshot-2026-04-14-162237.png&quot; alt=&quot;Page Evaluator Scoring Report&quot; width=&quot;900&quot; height=&quot;490&quot;&gt;&lt;/p&gt;&#xA;&lt;p&gt;This AI Page Evaluator started because we had a need to evaluate our own Landing Pages and Blog Posts on a rubric to verify content was clear, structured well, and communicated our intent. We had been doing this QA outside of Umbraco and preferred something that lived inside the editorial workflow and was frictionless for content editors to use.&lt;/p&gt;&#xA;&lt;p&gt;ProWorks Umbraco.AI Page Evaluator works with&#xA0;&lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://umbraco.com/&quot; target=&quot;_blank&quot; title=&quot;Umbraco&quot;&gt;Umbraco&lt;/a&gt; 17.x&#xA0;in combination with the Umbraco.AI official package.&lt;/p&gt;&#xA;&lt;h2&gt;How To Get Started&lt;/h2&gt;&#xA;&lt;p&gt;The install is super-fast, and if you already use Umbraco.AI on Umbraco 17, configuration is fast as well.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Requirements:&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Umbraco 17.3&#x2B;&lt;/li&gt;&#xA;&lt;li&gt;Umbraco.AI&lt;/li&gt;&#xA;&lt;li&gt;.Net 10&#x2B;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4&gt;Installation&lt;/h4&gt;&#xA;&lt;p&gt;Use NuGet to install AI Page Evaluator for your Umbraco project.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt; &amp;gt; dotnet add package ProWorks.Umbraco.AI.PageEvaluator&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Or search for &lt;strong&gt;ProWorks.Umbraco.AI.PageEvaluator&lt;/strong&gt; in the NuGet Package Manager in Visual Studio.&lt;/p&gt;&#xA;&lt;p&gt;Package page: &lt;a href=&quot;https://www.nuget.org/packages/ProWorks.Umbraco.AI.PageEvaluator&quot;&gt;https://www.nuget.org/packages/ProWorks.Umbraco.AI.PageEvaluator&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;Then build the project, run the website, and login to the back-office.&lt;/p&gt;&#xA;&lt;h4&gt;Configuration&lt;/h4&gt;&#xA;&lt;p&gt;In the back-office, go to the &quot;AI&quot; section. Verify you have a Connection to an AI API and a Profile created that uses the Connection that you want to use.&lt;/p&gt;&#xA;&lt;p&gt;Now go to the Page Evaluator area under Add-ons. Click the &quot;Create New&quot; button and follow the steps below:&lt;br&gt;&lt;br&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;https://www.proworks.com/media/3ibaot4t/screenshot-2026-04-28-165602.png&quot; alt=&quot;Configuration Area&quot; width=&quot;889&quot; height=&quot;528&quot;&gt;&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Fill in the &lt;strong&gt;Name &lt;/strong&gt;and &lt;strong&gt;Description&#xA0;&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;Select a &lt;strong&gt;Document Type&lt;/strong&gt; to apply the Page Evaluator to. Simply start typing a DocType name and choose the item from the list.&lt;/li&gt;&#xA;&lt;li&gt;Select the &lt;strong&gt;AI Profile&lt;/strong&gt; to use for this Page Evaluator. Select the &lt;strong&gt;AI Context&lt;/strong&gt; if desired.&lt;br&gt;&lt;br&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;https://www.proworks.com/media/1vabd3fl/screenshot-2026-04-28-165951.png&quot; alt=&quot;Configuration-1&quot; width=&quot;783&quot; height=&quot;578&quot;&gt;&lt;/li&gt;&#xA;&lt;li&gt;Review the &lt;strong&gt;Properties to Evaluate&lt;/strong&gt; and remove any properties that aren&#x27;t important for the type of Page Evaluation you are setting up.&lt;br&gt;&lt;br&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;https://www.proworks.com/media/psddlqul/screenshot-2026-04-28-170238.png&quot; alt=&quot;Properties to Evaluate&quot; width=&quot;666&quot; height=&quot;430&quot;&gt;&lt;/li&gt;&#xA;&lt;li&gt;Paste in the prompt you would like to use or open the &lt;strong&gt;Prompt Builder&lt;/strong&gt; to help guide you on building a prompt.&lt;br&gt;&lt;br&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;https://www.proworks.com/media/tifhcc2q/screenshot-2026-04-28-170336.png&quot; alt=&quot;Screenshot 2026-04-28 170336.png&quot; width=&quot;869&quot; height=&quot;346&quot;&gt;&lt;/li&gt;&#xA;&lt;li&gt;Be sure to &lt;strong&gt;Enable Scoring&lt;/strong&gt; if there are scoring values that will be a part of the prompt.&lt;br&gt;&lt;br&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;https://www.proworks.com/media/fvabbv1k/screenshot-2026-04-28-170829.png&quot; alt=&quot;Enable Scoring&quot; width=&quot;618&quot; height=&quot;110&quot;&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h4&gt;Test it Out&lt;/h4&gt;&#xA;&lt;p&gt;Go to the Content section. Find a page that is of the document type that you specified in the configuration.&#xA0; Press the &lt;strong&gt;Evaluate Page&lt;/strong&gt; button in the bottom right area of the back-office.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;https://www.proworks.com/media/ueggilpw/umbraco-ai-page-evaluation.png&quot; alt=&quot;Umbraco.AI Page Evaluation&quot; width=&quot;542&quot; height=&quot;77&quot;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Page properties will be sent to AI with your evaluation criteria. An evaluation report will display with recommendations, a list of items to review, and scoring (if enabled).&lt;/p&gt;&#xA;&lt;p&gt;The results are cached so that AI doesn&#x27;t have to run each time you want to view the report (save those tokens!). It will re-run the report if the page has been saved since either the last run or if the evaluation criteria has been updated..&lt;/p&gt;&#xA;&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;https://www.proworks.com/media/0e5h2u5o/screenshot-2026-04-28-171542.png&quot; alt=&quot;ProWorks Page Evaluation Report&quot; width=&quot;1165&quot; height=&quot;634&quot;&gt;&lt;/p&gt;&#xA;&lt;h2&gt;Key Takeaways&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Content clarity is now a competitive factor and AI systems interpret your pages before many visitors do.&lt;/li&gt;&#xA;&lt;li&gt;ProWorks Umbraco.AI Page Evaluator brings structured, content quality feedback directly into the Umbraco editor.&lt;/li&gt;&#xA;&lt;li&gt;It&#x27;s open source, built by an Umbraco Platinum Partner, and available now on NuGet.&lt;/li&gt;&#xA;&lt;li&gt;Better content evaluation upstream means fewer post-launch surprises.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2&gt;Check it Out!&lt;/h2&gt;&#xA;&lt;p&gt;Try the plugin, open an issue, suggest a feature. It&#x27;s open source and we want to know how teams are using it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a style=&quot;color: #fff; background-image: none;&quot; rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://github.com/ProWorksCorporation/ProWorks-Umbraco.AI-Page-Evaluator&quot; target=&quot;_blank&quot; title=&quot;View the package on Github&quot; class=&quot;pw-button&quot; data-anchor=&quot;#section-footer&quot;&gt;View on Github&lt;/a&gt;&lt;/p&gt;&#xA;&lt;div&gt;&#xA;&lt;h2&gt;Need Help?&lt;/h2&gt;&#xA;&lt;p&gt;If you&#x27;d like help implementing this as part of a broader content quality initiative, or if you&#x27;re evaluating an Umbraco upgrade and want content quality to be part of that conversation, we&#x27;d love to talk.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a style=&quot;color: #fff; background-image: none;&quot; type=&quot;external&quot; href=&quot;#section-footer&quot; title=&quot;Request an Initial Consultation&quot; class=&quot;pw-button&quot; data-anchor=&quot;#section-footer&quot;&gt;Schedule a Consultation&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;h2&gt;Frequently Asked Questions (FAQ)&lt;/h2&gt;&#xA;&lt;div id=&quot;faq-56aaba21fce947e7a6fc15711e8217cf&quot; class=&quot;accordion&quot;&gt;&#xA;&lt;div class=&quot;accordion-item&quot;&gt;&#xA;&lt;h4 class=&quot;accordion-header&quot;&gt;&lt;button class=&quot;accordion-button collapsed&quot; data-bs-toggle=&quot;collapse&quot; data-bs-target=&quot;#faq-item-39f1deabb1ac4f2a9990ea5d36668607&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;faq-item-39f1deabb1ac4f2a9990ea5d36668607&quot;&gt; Does the plugin work with any AI provider, or only Claude / Anthropic? &lt;/button&gt;&lt;/h4&gt;&#xA;&lt;div id=&quot;faq-item-39f1deabb1ac4f2a9990ea5d36668607&quot; class=&quot;accordion-collapse collapse&quot;&gt;&#xA;&lt;div class=&quot;accordion-body&quot;&gt;&#xA;&lt;p&gt;It works with any AI provider configured in Umbraco.AI, including Anthropic Claude, OpenAI, and others. The plugin is provider-agnostic by design; you select the AI profile when setting up an evaluator configuration, so whichever model your team already has access to will work.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&quot;accordion-item&quot;&gt;&#xA;&lt;h4 class=&quot;accordion-header&quot;&gt;&lt;button class=&quot;accordion-button collapsed&quot; data-bs-toggle=&quot;collapse&quot; data-bs-target=&quot;#faq-item-13a35cfe03f24500b5877141b4887768&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;faq-item-13a35cfe03f24500b5877141b4887768&quot;&gt; What versions of Umbraco does it support? &lt;/button&gt;&lt;/h4&gt;&#xA;&lt;div id=&quot;faq-item-13a35cfe03f24500b5877141b4887768&quot; class=&quot;accordion-collapse collapse&quot;&gt;&#xA;&lt;div class=&quot;accordion-body&quot;&gt;&#xA;&lt;p&gt;The current release requires Umbraco CMS 17.3.x&#x2B;, Umbraco.AI 1.8.x&#x2B;, and .NET 10. If your site is on an earlier version of Umbraco, the plugin is not compatible yet. Support for additional versions may come in future releases.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&quot;accordion-item&quot;&gt;&#xA;&lt;h4 class=&quot;accordion-header&quot;&gt;&lt;button class=&quot;accordion-button collapsed&quot; data-bs-toggle=&quot;collapse&quot; data-bs-target=&quot;#faq-item-ee7fc7bd0f594e0d98f3c22916f27bb4&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;faq-item-ee7fc7bd0f594e0d98f3c22916f27bb4&quot;&gt; Does the plugin send my content to a third-party API? &lt;/button&gt;&lt;/h4&gt;&#xA;&lt;div id=&quot;faq-item-ee7fc7bd0f594e0d98f3c22916f27bb4&quot; class=&quot;accordion-collapse collapse&quot;&gt;&#xA;&lt;div class=&quot;accordion-body&quot;&gt;&#xA;&lt;p&gt;Yes, it sends page content to whichever AI provider you have configured in Umbraco.AI. Before sending, the plugin cleans the content: HTML tags are stripped and long property values are truncated to reduce token usage. If your organization has data sensitivity requirements, review your AI provider&#x27;s data handling policies before deploying. You can also use the property filtering feature to exclude specific fields from the evaluation entirely.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&quot;accordion-item&quot;&gt;&#xA;&lt;h4 class=&quot;accordion-header&quot;&gt;&lt;button class=&quot;accordion-button collapsed&quot; data-bs-toggle=&quot;collapse&quot; data-bs-target=&quot;#faq-item-eaf3fd5658144d9fbeaefd8e82e38397&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;faq-item-eaf3fd5658144d9fbeaefd8e82e38397&quot;&gt; Can I control which content gets sent to the AI? &lt;/button&gt;&lt;/h4&gt;&#xA;&lt;div id=&quot;faq-item-eaf3fd5658144d9fbeaefd8e82e38397&quot; class=&quot;accordion-collapse collapse&quot;&gt;&#xA;&lt;div class=&quot;accordion-body&quot;&gt;&#xA;&lt;p&gt;Yes. When setting up an evaluator configuration, you can select exactly which document type properties to include in the evaluation. Any properties you do not select are excluded from the AI call. This is useful both for keeping sensitive fields private and for reducing token usage on pages with large amounts of irrelevant content.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&quot;accordion-item&quot;&gt;&#xA;&lt;h4 class=&quot;accordion-header&quot;&gt;&lt;button class=&quot;accordion-button collapsed&quot; data-bs-toggle=&quot;collapse&quot; data-bs-target=&quot;#faq-item-fd851378877c42f6aef7e6f10c536b3a&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;faq-item-fd851378877c42f6aef7e6f10c536b3a&quot;&gt; Can I customize what the AI evaluates? &lt;/button&gt;&lt;/h4&gt;&#xA;&lt;div id=&quot;faq-item-fd851378877c42f6aef7e6f10c536b3a&quot; class=&quot;accordion-collapse collapse&quot;&gt;&#xA;&lt;div class=&quot;accordion-body&quot;&gt;&#xA;&lt;p&gt;Yes, this is one of the plugin&#x27;s core design principles. Each evaluator configuration uses a custom prompt you write for that specific document type. The Prompt Builder UI can auto-generate a starting prompt from your document type&#x27;s properties and a set of checklist categories, which you can then edit and refine. You can also attach a Context resource from Umbraco.AI to give the model additional background about your organization or brand.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&quot;accordion-item&quot;&gt;&#xA;&lt;h4 class=&quot;accordion-header&quot;&gt;&lt;button class=&quot;accordion-button collapsed&quot; data-bs-toggle=&quot;collapse&quot; data-bs-target=&quot;#faq-item-905523a762f44aca8debd3d2de71521b&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;faq-item-905523a762f44aca8debd3d2de71521b&quot;&gt; Is the plugin free? Are there any ongoing costs? &lt;/button&gt;&lt;/h4&gt;&#xA;&lt;div id=&quot;faq-item-905523a762f44aca8debd3d2de71521b&quot; class=&quot;accordion-collapse collapse&quot;&gt;&#xA;&lt;div class=&quot;accordion-body&quot;&gt;&#xA;&lt;p&gt;The plugin itself is free and open source under the MIT license. In addition, your AI provider&#x27;s API charges based on token usage. For most sites running on-demand evaluations, API costs are minimal.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&quot;accordion-item&quot;&gt;&#xA;&lt;h4 class=&quot;accordion-header&quot;&gt;&lt;button class=&quot;accordion-button collapsed&quot; data-bs-toggle=&quot;collapse&quot; data-bs-target=&quot;#faq-item-f5a49851eeb34bba9eda56e46284ef6a&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;faq-item-f5a49851eeb34bba9eda56e46284ef6a&quot;&gt;&#xA0;What&#x27;s the difference between this plugin and ProWorks&#x27; full AI content evaluation service? &lt;/button&gt;&lt;/h4&gt;&#xA;&lt;div id=&quot;faq-item-f5a49851eeb34bba9eda56e46284ef6a&quot; class=&quot;accordion-collapse collapse&quot;&gt;&#xA;&lt;div class=&quot;accordion-body&quot;&gt;&#xA;&lt;p&gt;The plugin evaluates individual pages on demand inside your Umbraco back office, using prompts you configure. It is a self-serve tool built for ongoing editorial quality control your team can run as part of a regular publishing workflow.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&quot;/ai/&quot; title=&quot;ProWorks&#x27; site-wide AI Content Evaluation&quot;&gt;ProWorks&#x27; site-wide AI Content Evaluation&lt;/a&gt; service is a done-for-you engagement that analyzes how AI systems interpret your entire organization across all public content. It delivers an AI Perspective Report covering your inferred positioning, value propositions, audience signals, and content consistency. This plugin is a great starting point; the service is for teams who want the full picture across their whole site.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;]]></description>
                    <pubDate>Wed, 29 Apr 2026 10:04:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://fa9976c2-5840-4a63-82ec-42e17b070c7d-1.azurewebsites.net/blog/archive/umbraco-ai-page-evaluator/</guid>
                    <title>Catch Weak Content Before It Goes Live with ProWorks Umbraco.AI Page Evaluator</title>
                    <link>https://fa9976c2-5840-4a63-82ec-42e17b070c7d-1.azurewebsites.net/blog/archive/umbraco-ai-page-evaluator/</link>
                    <description><![CDATA[&lt;p&gt;In this day and age, its more important than ever to keep your website content clear, consistent, and on brand. AI infers what your organization does from what it reads on your website and, yes, it reads ALL of your content. Couple this with the rise of AI tools used to outline, write, and enhance marketing content, the risk of publishing AI slop (or even inaccurate information) is high. This is where the &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://github.com/ProWorksCorporation/ProWorks-Umbraco.AI-Page-Evaluator&quot; target=&quot;_blank&quot; title=&quot;ProWorks Umbraco.AI Page Evaluator&quot;&gt;ProWorks Umbraco.AI Page Evaluator&lt;/a&gt; shines.&lt;/p&gt;&#xA;&lt;h2&gt;What Is AI-Powered Page Evaluation?&lt;/h2&gt;&#xA;&lt;p&gt;AI-powered page evaluation uses a large language model (LLM) to analyze your page content and return structured feedback on key page indicators.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A &lt;strong&gt;landing page&lt;/strong&gt; can be evaluated and scored for clarity, messaging strength, objection handling, message hierarchy, and the call to action.&lt;/li&gt;&#xA;&lt;li&gt;A standard &lt;strong&gt;content page&lt;/strong&gt; can be evaluated on SEO performance, AEO/GEO performance, and accessibility compliance.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;All pages&lt;/strong&gt; can be evaluated based on brand guidelines, brand voice, and how it supports the organization&#x27;s marketing strategy.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2&gt;What is ProWorks Umbraco.AI Page Evaluator (AI Page Evaluator)?&lt;/h2&gt;&#xA;&lt;p&gt;Our AI Page Evaluator is an open-source add-on to the &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://github.com/umbraco/Umbraco.AI/&quot; target=&quot;_blank&quot; title=&quot;Umbraco.AI&quot;&gt;Umbraco.AI&lt;/a&gt; framework, which adds a back-office Evaluate Page button you can simply click on to send the page&#x27;s content to an AI model and return a structured quality report directly inside the back-office, including scored checks, warnings, and actionable suggestions.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;https://fa9976c2-5840-4a63-82ec-42e17b070c7d-1.azurewebsites.net/media/uzfpov4h/screenshot-2026-04-14-162237.png&quot; alt=&quot;Page Evaluator Scoring Report&quot; width=&quot;900&quot; height=&quot;490&quot;&gt;&lt;/p&gt;&#xA;&lt;p&gt;This AI Page Evaluator started because we had a need to evaluate our own Landing Pages and Blog Posts on a rubric to verify content was clear, structured well, and communicated our intent. We had been doing this QA outside of Umbraco and preferred something that lived inside the editorial workflow and was frictionless for content editors to use.&lt;/p&gt;&#xA;&lt;p&gt;ProWorks Umbraco.AI Page Evaluator works with&#xA0;&lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://umbraco.com/&quot; target=&quot;_blank&quot; title=&quot;Umbraco&quot;&gt;Umbraco&lt;/a&gt; 17.x&#xA0;in combination with the Umbraco.AI official package.&lt;/p&gt;&#xA;&lt;h2&gt;How To Get Started&lt;/h2&gt;&#xA;&lt;p&gt;The install is super-fast, and if you already use Umbraco.AI on Umbraco 17, configuration is fast as well.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Requirements:&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Umbraco 17.3&#x2B;&lt;/li&gt;&#xA;&lt;li&gt;Umbraco.AI&lt;/li&gt;&#xA;&lt;li&gt;.Net 10&#x2B;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4&gt;Installation&lt;/h4&gt;&#xA;&lt;p&gt;Use NuGet to install AI Page Evaluator for your Umbraco project.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt; &amp;gt; dotnet add package ProWorks.Umbraco.AI.PageEvaluator&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Or search for &lt;strong&gt;ProWorks.Umbraco.AI.PageEvaluator&lt;/strong&gt; in the NuGet Package Manager in Visual Studio.&lt;/p&gt;&#xA;&lt;p&gt;Package page: &lt;a href=&quot;https://www.nuget.org/packages/ProWorks.Umbraco.AI.PageEvaluator&quot;&gt;https://www.nuget.org/packages/ProWorks.Umbraco.AI.PageEvaluator&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;Then build the project, run the website, and login to the back-office.&lt;/p&gt;&#xA;&lt;h4&gt;Configuration&lt;/h4&gt;&#xA;&lt;p&gt;In the back-office, go to the &quot;AI&quot; section. Verify you have a Connection to an AI API and a Profile created that uses the Connection that you want to use.&lt;/p&gt;&#xA;&lt;p&gt;Now go to the Page Evaluator area under Add-ons. Click the &quot;Create New&quot; button and follow the steps below:&lt;br&gt;&lt;br&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;https://fa9976c2-5840-4a63-82ec-42e17b070c7d-1.azurewebsites.net/media/3ibaot4t/screenshot-2026-04-28-165602.png&quot; alt=&quot;Configuration Area&quot; width=&quot;889&quot; height=&quot;528&quot;&gt;&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Fill in the &lt;strong&gt;Name &lt;/strong&gt;and &lt;strong&gt;Description&#xA0;&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;Select a &lt;strong&gt;Document Type&lt;/strong&gt; to apply the Page Evaluator to. Simply start typing a DocType name and choose the item from the list.&lt;/li&gt;&#xA;&lt;li&gt;Select the &lt;strong&gt;AI Profile&lt;/strong&gt; to use for this Page Evaluator. Select the &lt;strong&gt;AI Context&lt;/strong&gt; if desired.&lt;br&gt;&lt;br&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;https://fa9976c2-5840-4a63-82ec-42e17b070c7d-1.azurewebsites.net/media/1vabd3fl/screenshot-2026-04-28-165951.png&quot; alt=&quot;Configuration-1&quot; width=&quot;783&quot; height=&quot;578&quot;&gt;&lt;/li&gt;&#xA;&lt;li&gt;Review the &lt;strong&gt;Properties to Evaluate&lt;/strong&gt; and remove any properties that aren&#x27;t important for the type of Page Evaluation you are setting up.&lt;br&gt;&lt;br&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;https://fa9976c2-5840-4a63-82ec-42e17b070c7d-1.azurewebsites.net/media/psddlqul/screenshot-2026-04-28-170238.png&quot; alt=&quot;Properties to Evaluate&quot; width=&quot;666&quot; height=&quot;430&quot;&gt;&lt;/li&gt;&#xA;&lt;li&gt;Paste in the prompt you would like to use or open the &lt;strong&gt;Prompt Builder&lt;/strong&gt; to help guide you on building a prompt.&lt;br&gt;&lt;br&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;https://fa9976c2-5840-4a63-82ec-42e17b070c7d-1.azurewebsites.net/media/tifhcc2q/screenshot-2026-04-28-170336.png&quot; alt=&quot;Screenshot 2026-04-28 170336.png&quot; width=&quot;869&quot; height=&quot;346&quot;&gt;&lt;/li&gt;&#xA;&lt;li&gt;Be sure to &lt;strong&gt;Enable Scoring&lt;/strong&gt; if there are scoring values that will be a part of the prompt.&lt;br&gt;&lt;br&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;https://fa9976c2-5840-4a63-82ec-42e17b070c7d-1.azurewebsites.net/media/fvabbv1k/screenshot-2026-04-28-170829.png&quot; alt=&quot;Enable Scoring&quot; width=&quot;618&quot; height=&quot;110&quot;&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h4&gt;Test it Out&lt;/h4&gt;&#xA;&lt;p&gt;Go to the Content section. Find a page that is of the document type that you specified in the configuration.&#xA0; Press the &lt;strong&gt;Evaluate Page&lt;/strong&gt; button in the bottom right area of the back-office.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;https://fa9976c2-5840-4a63-82ec-42e17b070c7d-1.azurewebsites.net/media/ueggilpw/umbraco-ai-page-evaluation.png&quot; alt=&quot;Umbraco.AI Page Evaluation&quot; width=&quot;542&quot; height=&quot;77&quot;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Page properties will be sent to AI with your evaluation criteria. An evaluation report will display with recommendations, a list of items to review, and scoring (if enabled).&lt;/p&gt;&#xA;&lt;p&gt;The results are cached so that AI doesn&#x27;t have to run each time you want to view the report (save those tokens!). It will re-run the report if the page has been saved since either the last run or if the evaluation criteria has been updated..&lt;/p&gt;&#xA;&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;https://fa9976c2-5840-4a63-82ec-42e17b070c7d-1.azurewebsites.net/media/0e5h2u5o/screenshot-2026-04-28-171542.png&quot; alt=&quot;ProWorks Page Evaluation Report&quot; width=&quot;1165&quot; height=&quot;634&quot;&gt;&lt;/p&gt;&#xA;&lt;h2&gt;Key Takeaways&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Content clarity is now a competitive factor and AI systems interpret your pages before many visitors do.&lt;/li&gt;&#xA;&lt;li&gt;ProWorks Umbraco.AI Page Evaluator brings structured, content quality feedback directly into the Umbraco editor.&lt;/li&gt;&#xA;&lt;li&gt;It&#x27;s open source, built by an Umbraco Platinum Partner, and available now on NuGet.&lt;/li&gt;&#xA;&lt;li&gt;Better content evaluation upstream means fewer post-launch surprises.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2&gt;Check it Out!&lt;/h2&gt;&#xA;&lt;p&gt;Try the plugin, open an issue, suggest a feature. It&#x27;s open source and we want to know how teams are using it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a style=&quot;color: #fff; background-image: none;&quot; rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://github.com/ProWorksCorporation/ProWorks-Umbraco.AI-Page-Evaluator&quot; target=&quot;_blank&quot; title=&quot;View the package on Github&quot; class=&quot;pw-button&quot; data-anchor=&quot;#section-footer&quot;&gt;View on Github&lt;/a&gt;&lt;/p&gt;&#xA;&lt;div&gt;&#xA;&lt;h2&gt;Need Help?&lt;/h2&gt;&#xA;&lt;p&gt;If you&#x27;d like help implementing this as part of a broader content quality initiative, or if you&#x27;re evaluating an Umbraco upgrade and want content quality to be part of that conversation, we&#x27;d love to talk.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a style=&quot;color: #fff; background-image: none;&quot; type=&quot;external&quot; href=&quot;#section-footer&quot; title=&quot;Request an Initial Consultation&quot; class=&quot;pw-button&quot; data-anchor=&quot;#section-footer&quot;&gt;Schedule a Consultation&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;h2&gt;Frequently Asked Questions (FAQ)&lt;/h2&gt;&#xA;&lt;div id=&quot;faq-56aaba21fce947e7a6fc15711e8217cf&quot; class=&quot;accordion&quot;&gt;&#xA;&lt;div class=&quot;accordion-item&quot;&gt;&#xA;&lt;h4 class=&quot;accordion-header&quot;&gt;&lt;button class=&quot;accordion-button collapsed&quot; data-bs-toggle=&quot;collapse&quot; data-bs-target=&quot;#faq-item-39f1deabb1ac4f2a9990ea5d36668607&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;faq-item-39f1deabb1ac4f2a9990ea5d36668607&quot;&gt; Does the plugin work with any AI provider, or only Claude / Anthropic? &lt;/button&gt;&lt;/h4&gt;&#xA;&lt;div id=&quot;faq-item-39f1deabb1ac4f2a9990ea5d36668607&quot; class=&quot;accordion-collapse collapse&quot;&gt;&#xA;&lt;div class=&quot;accordion-body&quot;&gt;&#xA;&lt;p&gt;It works with any AI provider configured in Umbraco.AI, including Anthropic Claude, OpenAI, and others. The plugin is provider-agnostic by design; you select the AI profile when setting up an evaluator configuration, so whichever model your team already has access to will work.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&quot;accordion-item&quot;&gt;&#xA;&lt;h4 class=&quot;accordion-header&quot;&gt;&lt;button class=&quot;accordion-button collapsed&quot; data-bs-toggle=&quot;collapse&quot; data-bs-target=&quot;#faq-item-13a35cfe03f24500b5877141b4887768&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;faq-item-13a35cfe03f24500b5877141b4887768&quot;&gt; What versions of Umbraco does it support? &lt;/button&gt;&lt;/h4&gt;&#xA;&lt;div id=&quot;faq-item-13a35cfe03f24500b5877141b4887768&quot; class=&quot;accordion-collapse collapse&quot;&gt;&#xA;&lt;div class=&quot;accordion-body&quot;&gt;&#xA;&lt;p&gt;The current release requires Umbraco CMS 17.3.x&#x2B;, Umbraco.AI 1.8.x&#x2B;, and .NET 10. If your site is on an earlier version of Umbraco, the plugin is not compatible yet. Support for additional versions may come in future releases.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&quot;accordion-item&quot;&gt;&#xA;&lt;h4 class=&quot;accordion-header&quot;&gt;&lt;button class=&quot;accordion-button collapsed&quot; data-bs-toggle=&quot;collapse&quot; data-bs-target=&quot;#faq-item-ee7fc7bd0f594e0d98f3c22916f27bb4&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;faq-item-ee7fc7bd0f594e0d98f3c22916f27bb4&quot;&gt; Does the plugin send my content to a third-party API? &lt;/button&gt;&lt;/h4&gt;&#xA;&lt;div id=&quot;faq-item-ee7fc7bd0f594e0d98f3c22916f27bb4&quot; class=&quot;accordion-collapse collapse&quot;&gt;&#xA;&lt;div class=&quot;accordion-body&quot;&gt;&#xA;&lt;p&gt;Yes, it sends page content to whichever AI provider you have configured in Umbraco.AI. Before sending, the plugin cleans the content: HTML tags are stripped and long property values are truncated to reduce token usage. If your organization has data sensitivity requirements, review your AI provider&#x27;s data handling policies before deploying. You can also use the property filtering feature to exclude specific fields from the evaluation entirely.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&quot;accordion-item&quot;&gt;&#xA;&lt;h4 class=&quot;accordion-header&quot;&gt;&lt;button class=&quot;accordion-button collapsed&quot; data-bs-toggle=&quot;collapse&quot; data-bs-target=&quot;#faq-item-eaf3fd5658144d9fbeaefd8e82e38397&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;faq-item-eaf3fd5658144d9fbeaefd8e82e38397&quot;&gt; Can I control which content gets sent to the AI? &lt;/button&gt;&lt;/h4&gt;&#xA;&lt;div id=&quot;faq-item-eaf3fd5658144d9fbeaefd8e82e38397&quot; class=&quot;accordion-collapse collapse&quot;&gt;&#xA;&lt;div class=&quot;accordion-body&quot;&gt;&#xA;&lt;p&gt;Yes. When setting up an evaluator configuration, you can select exactly which document type properties to include in the evaluation. Any properties you do not select are excluded from the AI call. This is useful both for keeping sensitive fields private and for reducing token usage on pages with large amounts of irrelevant content.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&quot;accordion-item&quot;&gt;&#xA;&lt;h4 class=&quot;accordion-header&quot;&gt;&lt;button class=&quot;accordion-button collapsed&quot; data-bs-toggle=&quot;collapse&quot; data-bs-target=&quot;#faq-item-fd851378877c42f6aef7e6f10c536b3a&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;faq-item-fd851378877c42f6aef7e6f10c536b3a&quot;&gt; Can I customize what the AI evaluates? &lt;/button&gt;&lt;/h4&gt;&#xA;&lt;div id=&quot;faq-item-fd851378877c42f6aef7e6f10c536b3a&quot; class=&quot;accordion-collapse collapse&quot;&gt;&#xA;&lt;div class=&quot;accordion-body&quot;&gt;&#xA;&lt;p&gt;Yes, this is one of the plugin&#x27;s core design principles. Each evaluator configuration uses a custom prompt you write for that specific document type. The Prompt Builder UI can auto-generate a starting prompt from your document type&#x27;s properties and a set of checklist categories, which you can then edit and refine. You can also attach a Context resource from Umbraco.AI to give the model additional background about your organization or brand.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&quot;accordion-item&quot;&gt;&#xA;&lt;h4 class=&quot;accordion-header&quot;&gt;&lt;button class=&quot;accordion-button collapsed&quot; data-bs-toggle=&quot;collapse&quot; data-bs-target=&quot;#faq-item-905523a762f44aca8debd3d2de71521b&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;faq-item-905523a762f44aca8debd3d2de71521b&quot;&gt; Is the plugin free? Are there any ongoing costs? &lt;/button&gt;&lt;/h4&gt;&#xA;&lt;div id=&quot;faq-item-905523a762f44aca8debd3d2de71521b&quot; class=&quot;accordion-collapse collapse&quot;&gt;&#xA;&lt;div class=&quot;accordion-body&quot;&gt;&#xA;&lt;p&gt;The plugin itself is free and open source under the MIT license. In addition, your AI provider&#x27;s API charges based on token usage. For most sites running on-demand evaluations, API costs are minimal.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&quot;accordion-item&quot;&gt;&#xA;&lt;h4 class=&quot;accordion-header&quot;&gt;&lt;button class=&quot;accordion-button collapsed&quot; data-bs-toggle=&quot;collapse&quot; data-bs-target=&quot;#faq-item-f5a49851eeb34bba9eda56e46284ef6a&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;faq-item-f5a49851eeb34bba9eda56e46284ef6a&quot;&gt;&#xA0;What&#x27;s the difference between this plugin and ProWorks&#x27; full AI content evaluation service? &lt;/button&gt;&lt;/h4&gt;&#xA;&lt;div id=&quot;faq-item-f5a49851eeb34bba9eda56e46284ef6a&quot; class=&quot;accordion-collapse collapse&quot;&gt;&#xA;&lt;div class=&quot;accordion-body&quot;&gt;&#xA;&lt;p&gt;The plugin evaluates individual pages on demand inside your Umbraco back office, using prompts you configure. It is a self-serve tool built for ongoing editorial quality control your team can run as part of a regular publishing workflow.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&quot;/ai/&quot; title=&quot;ProWorks&#x27; site-wide AI Content Evaluation&quot;&gt;ProWorks&#x27; site-wide AI Content Evaluation&lt;/a&gt; service is a done-for-you engagement that analyzes how AI systems interpret your entire organization across all public content. It delivers an AI Perspective Report covering your inferred positioning, value propositions, audience signals, and content consistency. This plugin is a great starting point; the service is for teams who want the full picture across their whole site.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;]]></description>
                    <pubDate>Wed, 29 Apr 2026 10:04:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owaincodes.uksouth01.umbraco.io/blog/2026/april/the-silent-developer/</guid>
                    <title>The Silent Developer</title>
                    <link>https://owaincodes.uksouth01.umbraco.io/blog/2026/april/the-silent-developer/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 29 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/april/the-silent-developer/</guid>
                    <title>The Silent Developer</title>
                    <link>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/april/the-silent-developer/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 29 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/april/the-silent-developer/</guid>
                    <title>The Silent Developer</title>
                    <link>https://owain.codes/blog/2026/april/the-silent-developer/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 29 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://mattbrailsford.dev/speech-to-text-in-umbraco-ai</guid>
                    <title>Speech-to-Text in Umbraco.AI</title>
                    <link>https://mattbrailsford.dev/speech-to-text-in-umbraco-ai</link>
                    <description><![CDATA[Speech-to-text has landed in Umbraco.AI. Alongside chat and embeddings, transcription is now a first-class capability in the platform &#x2014; with a new...]]></description>
                    <pubDate>Tue, 28 Apr 2026 09:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbhost.greenstack.umbraco</guid>
                    <title>UmbHost.GreenStack.Umbraco</title>
                    <link>https://marketplace.umbraco.com/package/umbhost.greenstack.umbraco</link>
                    <description><![CDATA[A dotnet new template for Umbraco 17 preconfigured for GreenStack hosting with Docker support]]></description>
                    <pubDate>Tue, 28 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbhost.greenstack.umbraco.umbootstrap</guid>
                    <title>UmbHost.GreenStack.Umbraco.UmBootstrap</title>
                    <link>https://marketplace.umbraco.com/package/umbhost.greenstack.umbraco.umbootstrap</link>
                    <description><![CDATA[A dotnet new template for Umbraco 17 with UmBootstrap preconfigured for GreenStack hosting with Docker support]]></description>
                    <pubDate>Tue, 28 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbhost.greenstack.umbraco.cleanstarterkit</guid>
                    <title>UmbHost.GreenStack.Umbraco.CleanStarterKit</title>
                    <link>https://marketplace.umbraco.com/package/umbhost.greenstack.umbraco.cleanstarterkit</link>
                    <description><![CDATA[A dotnet new template for Umbraco 17 with Clean Starter Kit preconfigured for GreenStack hosting with Docker support]]></description>
                    <pubDate>Tue, 28 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umediaops</guid>
                    <title>uMediaOps</title>
                    <link>https://marketplace.umbraco.com/package/umediaops</link>
                    <description><![CDATA[Comprehensive media management suite for Umbraco 17&#x2B; including duplicate detection using SHA256 hashing, unused media finder, backup management, and audit logging.]]></description>
                    <pubDate>Tue, 28 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbhost.greenstack.umbraco.thestarterkit</guid>
                    <title>UmbHost.GreenStack.Umbraco.TheStarterKit</title>
                    <link>https://marketplace.umbraco.com/package/umbhost.greenstack.umbraco.thestarterkit</link>
                    <description><![CDATA[A dotnet new template for Umbraco 17 with The Starter Kit preconfigured for GreenStack hosting with Docker support]]></description>
                    <pubDate>Tue, 28 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=V6uPHzSUTeE</guid>
                    <title>All About Migrations: Umbraco Explained</title>
                    <link>https://www.youtube.com/watch?v=V6uPHzSUTeE</link>
                    <description><![CDATA[This recording covers real-world Umbraco migration strategies, including approaches for handling custom data and database changes safely. It also shares practical examples and when to use different migration patterns.&#xA;&#xA;Join one of the world&#x2019;s largest Umbraco communities and be part of the conversation.&#xA;https://www.meetup.com/umbraco-india-user-group/]]></description>
                    <pubDate>Mon, 27 Apr 2026 12:09:22 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.linkedin.com/feed/update/urn:li:activity:7453693111752458240/</guid>
                    <title>Merchello v1.0.0 for Umbraco v17&#x2B; is released</title>
                    <link>https://www.linkedin.com/feed/update/urn:li:activity:7453693111752458240/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Sat, 25 Apr 2026 19:19:35 Z</pubDate>
                        <category>social</category>
                        <category>linkedin</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/campaigncanvas</guid>
                    <title>CampaignCanvas</title>
                    <link>https://marketplace.umbraco.com/package/campaigncanvas</link>
                    <description><![CDATA[A Bellissima-native forms and newsletter/campaign platform for Umbraco 17&#x2B; with BlockGrid integration, headless submission API, and commercial licensing.]]></description>
                    <pubDate>Sat, 25 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.ufm.extensions</guid>
                    <title>Umbraco.Community.Ufm.Extensions</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.ufm.extensions</link>
                    <description><![CDATA[Extends Umbraco Flavoured Markdown (Ufm) with contentTypeName and contentTypeAlias components, and injects $contentTypeName / $contentTypeAlias scope variables into UfmJS expressions so block labels can fall back to the content type &#x2014; restoring V13-style { title || $contentTypeName } expressions in Umbraco v16 and v17&#x2B;. Supports Umbraco 16 (.NET 9) and Umbraco 17 (.NET 10).]]></description>
                    <pubDate>Sat, 25 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://bsky.app/profile/shazwazza.bsky.social/post/3mjxk4sy4622f</guid>
                    <title>New in ExamineX: AI Semantic Ranking for Umbraco &#x2B; Azure Search</title>
                    <link>https://bsky.app/profile/shazwazza.bsky.social/post/3mjxk4sy4622f</link>
                    <description><![CDATA[&#x1F680; New in #ExamineX: AI Semantic Ranking for #Umbraco &#x2B; Azure Search!&#xA;&#xA;Standard keywords can miss the mark, but semantic ranking uses deep learning to understand the meaning behind queries, re-ranking for true relevance. &#x2728;&#xA;&#xA;&#x2705; Works with Umbraco v13&#x2B;&#xA;&#x1F4D6; Details: bit.ly/4dQldJr&#xA;&#xA;#AzureSearch #AI&#xA;&#xA;]]></description>
                    <pubDate>Fri, 24 Apr 2026 14:50:10 Z</pubDate>
                        <category>community</category>
                        <category>bluesky</category>
                        <category>social</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=uY9pZz5NHaQ</guid>
                    <title>umbraCoffee - AI in Umbraco</title>
                    <link>https://www.youtube.com/watch?v=uY9pZz5NHaQ</link>
                    <description><![CDATA[Welcome to your monthly dose of #umbraCoffee&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;! Your hosts - Marcin and Callum - together with their guest(s) will drive through all of the community news and happenings in the Umbraco world. So... grab a cuppa, join us LIVE and enjoy!&#xA;&#xA;Today we&#x27;re joined by Matt Brailsford - AI Staff Engineer @ Umbraco HQ, Co-founder of CODECABIN and Creator of UMB.FYI.&#xA;&#xA;See ya?!&#xA;&#xA;---&#xA;&#x2615; Wanna buy us a coffee/pizza/donuts?&#xA;https://www.buymeacoffee.com/umbracoffee&#xA;---&#xA;&#xA;Notes:&#xA;//ToDo]]></description>
                    <pubDate>Fri, 24 Apr 2026 09:30:02 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://donutsec.fun/blog/umbackdoor/</guid>
                    <title>UmBackdoor</title>
                    <link>https://donutsec.fun/blog/umbackdoor/</link>
                    <description><![CDATA[New post about a silly old project I was reminded of recently.https://donutsec.fun/blog/umbackdoor/#Umbraco]]></description>
                    <pubDate>Fri, 24 Apr 2026 07:55:50 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=PiCBtYWUsLw</guid>
                    <title>The Codegarden Business Track</title>
                    <link>https://www.youtube.com/watch?v=PiCBtYWUsLw</link>
                    <description><![CDATA[The rumors are true &#x1FA84; We&#x2019;ve built a full-blown (magic) Business Track directly into the heart of Codegarden &#x1F3A4;&#xA;&#xA;Why this is a game-changer:&#xA;&#xA;&#x1F4C8; We&#x2019;ve curated a parallel world of ROI, digital transformation, and high-level strategy throughout the two-day conference.&#xA;&#xA;&#x1F977; You can still sneak into the developer talks, but this track means you no longer have to explain to your team why Codegarden is also for you &#x1F609;&#xA;&#xA;&#x1F5D3;&#xFE0F; If your calendar is screaming, you can join us for just one day. It&#x2019;s the perfect one-day deep dive into strategy and networking &#x1F942; It&#x2019;s the magic CEO shortcut.&#xA;&#xA;Will we see you, &#x201C;(p)usiness people&#x2026; business people!&#x201D; in Copenhagen? &#x1F4BC; &#x1F1E9;&#x1F1F0; https://lnkd.in/eCHSzkV]]></description>
                    <pubDate>Thu, 23 Apr 2026 15:44:33 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://github.com/umbraco/Announcements/issues/31</guid>
                    <title>[Breaking change]: Umbraco UI Library 2.0 &#x2014; consolidation to a single package</title>
                    <link>https://github.com/umbraco/Announcements/issues/31</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Thu, 23 Apr 2026 09:24:46 Z</pubDate>
                        <category>hq</category>
                        <category>announcement</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/our.umbraco.jupix</guid>
                    <title>Our.Umbraco.Jupix</title>
                    <link>https://marketplace.umbraco.com/package/our.umbraco.jupix</link>
                    <description><![CDATA[Umbraco package that integrates the JUPIX estate agency CRM property feed with Umbraco.&#xA;      Polls the feed on a schedule, caches listings locally, and exposes strongly-typed&#xA;      property models to Razor views, controllers, and headless consumers.]]></description>
                    <pubDate>Thu, 23 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.intltelinput</guid>
                    <title>Umbraco.Community.IntlTelInput</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.intltelinput</link>
                    <description><![CDATA[An Umbraco Forms field type that provides an international phone number input with country code dropdown, flags, E.164 validation, and formatting. Powered by intl-tel-input.]]></description>
                    <pubDate>Wed, 22 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.legalreview</guid>
                    <title>Umbraco.Community.LegalReview</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.legalreview</link>
                    <description><![CDATA[AI-powered legal and regulatory review for Umbraco content. Scans document copy for risky phrases &#x2014; superlatives, health claims, greenwashing, defamation, pricing deception and more &#x2014; fact-checks the underlying claims, and returns a risk score with per-flag suggested fixes. Built on Umbraco.AI and works with any configured provider (OpenAI, Google Gemini, Anthropic, etc.).]]></description>
                    <pubDate>Wed, 22 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=nBEgfifIP0o</guid>
                    <title>DevRel Deep Dive: Umbraco 17.2 &amp; 17.3 highlights with Andy Butland</title>
                    <link>https://www.youtube.com/watch?v=nBEgfifIP0o</link>
                    <description><![CDATA[Sebastiaan and Lotte are joined by the Head of CMS, Andy Butland, to look at the highlights of the two latest Umbraco releases - versions 17.2 and 17.3.&#xA;&#xA;&#x1F440; Umbraco 17.2 release notes: https://releases.umbraco.com/release/umbraco/Umbraco-CMS/17.2.0&#xA;&#x1F440; Umbraco 17.3 release notes: https://releases.umbraco.com/release/umbraco/Umbraco-CMS/17.3.0&#xA;&#xA;&#x1F30D; Matt Brailsford&#x2019;s blogpost on why version 17.4 is going to be &#x201C;a big deal for AI&#x201D;: https://mattbrailsford.dev/why-umbraco-1740-is-a-big-deal-for-ai&#xA;&#xA;00:00 Introduction to the DevRel Deep Dive&#xA;01:09 **Exploring Umbraco Releases 17.2 and 17.3**&#xA;05:04 - Enhancements in User Group Management&#xA;07:14 - Improvements in Content Management Experience&#xA;11:40 - Central Package Management in Umbraco&#xA;16:42 - Optimizing Content Cache Management&#xA;18:03 - Constructive vs Destructive Work&#xA;18:32 - Optimizing API Calls for Performance&#xA;20:00 - Security Updates and Dependency Management&#xA;21:51 - Implementing HMAC for Image Requests&#xA;23:17 - Best Practices for HMAC Keys&#xA;24:36 - Community Contributions and Open Source Practices&#xA;25:53 - Debugging Enhancements in Razor Files&#xA;26:38 **Upcoming Features in Umbraco 17.4**&#xA;27:25 - Website Output Caching Improvements&#xA;29:27 - Enhancements for AI Integration&#xA;31:18 - Lightweight External Members for High Traffic Sites&#xA;&#xA;--------&#xA;&#xA;&#x2753; Looking for help with your Umbraco projects? Visit the Forum&#xA; https://forum.umbraco.com&#xA; &#xA;&#x1F4AC; Want to chat with the friendly Umbraco Community? Join our Discord server&#xA; https://discord.umbraco.com&#xA; &#xA;&#x2709;&#xFE0F; Got a question (or topic suggestion) for the HQ Developer Relations team?&#xA; https://umbra.co/contact-devrel, or the &#x2018;contact-devrel&#x2019; channel on Discord&#xA; &#xA;#Umbraco]]></description>
                    <pubDate>Tue, 21 Apr 2026 10:17:48 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://chromewebstore.google.com/detail/umbraco-debug-tools/ikiladlncgldfhfebghkognepdbnejog</guid>
                    <title>Umbraco Debug Tools</title>
                    <link>https://chromewebstore.google.com/detail/umbraco-debug-tools/ikiladlncgldfhfebghkognepdbnejog</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Tue, 21 Apr 2026 09:29:06 Z</pubDate>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://4e58b28b-864e-4510-9981-431d7c97d58a.azurewebsites.net/blog/2026/april/21/giving-umbraco-17-a-bigger-clock-raising-the-sql-command-timeout-with-a-composer</guid>
                    <title>Giving Umbraco 17 A Bigger Clock: Raising The SQL Command Timeout With A Composer</title>
                    <link>https://4e58b28b-864e-4510-9981-431d7c97d58a.azurewebsites.net/blog/2026/april/21/giving-umbraco-17-a-bigger-clock-raising-the-sql-command-timeout-with-a-composer</link>
                    <description><![CDATA[Sometimes you need to override the Command Timeout in code... Here&amp;#x27;s how I did it in Umbraco 17 with a tiny composer. &lt;a href=&quot;https://4e58b28b-864e-4510-9981-431d7c97d58a.azurewebsites.net/blog/2026/april/21/giving-umbraco-17-a-bigger-clock-raising-the-sql-command-timeout-with-a-composer&quot;&gt;Continue reading&lt;/a&gt;]]></description>
                    <pubDate>Tue, 21 Apr 2026 08:30:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://mattbrailsford.dev/what-we-gained-building-umbraco-ai-on-meai-and-maf</guid>
                    <title>What We Gained Building Umbraco AI on Microsoft.Extensions.AI and the Microsoft Agent Framework</title>
                    <link>https://mattbrailsford.dev/what-we-gained-building-umbraco-ai-on-meai-and-maf</link>
                    <description><![CDATA[When we set out to build AI capabilities for Umbraco, we had a choice every platform team faces: build your own abstractions, or bet on someone...]]></description>
                    <pubDate>Tue, 21 Apr 2026 08:30:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://aaronsadler.dev/blog/2026/april/21/giving-umbraco-17-a-bigger-clock-raising-the-sql-command-timeout-with-a-composer</guid>
                    <title>Giving Umbraco 17 A Bigger Clock: Raising The SQL Command Timeout With A Composer</title>
                    <link>https://aaronsadler.dev/blog/2026/april/21/giving-umbraco-17-a-bigger-clock-raising-the-sql-command-timeout-with-a-composer</link>
                    <description><![CDATA[Sometimes you need to override the Command Timeout in code... Here&amp;#x27;s how I did it in Umbraco 17 with a tiny composer. &lt;a href=&quot;https://aaronsadler.dev/blog/2026/april/21/giving-umbraco-17-a-bigger-clock-raising-the-sql-command-timeout-with-a-composer&quot;&gt;Continue reading&lt;/a&gt;]]></description>
                    <pubDate>Tue, 21 Apr 2026 08:30:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbmediasqueeze</guid>
                    <title>UmbMediaSqueeze</title>
                    <link>https://marketplace.umbraco.com/package/umbmediasqueeze</link>
                    <description><![CDATA[Package Description]]></description>
                    <pubDate>Tue, 21 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://github.com/limbo-works/Limbo.Umbraco.Separator/releases/tag/v17.0.1</guid>
                    <title>Limbo.Umbraco.Separator 17.0.1</title>
                    <link>https://github.com/limbo-works/Limbo.Umbraco.Separator/releases/tag/v17.0.1</link>
                    <description><![CDATA[Limbo.Separator is a small package for Umbraco that adds a property editor serving as a separator to give a better overview of properties within your Umbraco content types.]]></description>
                    <pubDate>Tue, 21 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://medium.com/@girish.sasikumar.kl33/complete-guide-to-upgrading-umbraco-from-version-13-to-17-f02f0e40237d?source=rss------umbraco-5</guid>
                    <title>Complete Guide: Umbraco Sequence Upgrade from Version 13 to 17</title>
                    <link>https://medium.com/@girish.sasikumar.kl33/complete-guide-to-upgrading-umbraco-from-version-13-to-17-f02f0e40237d?source=rss------umbraco-5</link>
                    <description><![CDATA[&lt;div class=&quot;medium-feed-item&quot;&gt;&lt;p class=&quot;medium-feed-image&quot;&gt;&lt;a href=&quot;https://medium.com/@girish.sasikumar.kl33/complete-guide-to-upgrading-umbraco-from-version-13-to-17-f02f0e40237d?source=rss------umbraco-5&quot;&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1408/1*7uHfh_absgEqQrp_4Dn5oA.png&quot; width=&quot;1408&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;medium-feed-snippet&quot;&gt;For most projects, the best starting point is a direct Umbraco 13 &amp;#x2192; 17 upgrade on a local clone, rather than forcing a 13 &amp;#x2192; 14 &amp;#x2192; 15 &amp;#x2192; 16&amp;#x2026;&lt;/p&gt;&lt;p class=&quot;medium-feed-link&quot;&gt;&lt;a href=&quot;https://medium.com/@girish.sasikumar.kl33/complete-guide-to-upgrading-umbraco-from-version-13-to-17-f02f0e40237d?source=rss------umbraco-5&quot;&gt;Continue reading on Medium &#xBB;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;]]></description>
                    <pubDate>Mon, 20 Apr 2026 06:54:37 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/our.umbraco.postgresql.umbraco.forms</guid>
                    <title>Our.Umbraco.PostgreSql.Umbraco.Forms</title>
                    <link>https://marketplace.umbraco.com/package/our.umbraco.postgresql.umbraco.forms</link>
                    <description><![CDATA[Adds support for Umbraco Forms with PostgreSQL.]]></description>
                    <pubDate>Mon, 20 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/brevo.umbraco</guid>
                    <title>Brevo.Umbraco</title>
                    <link>https://marketplace.umbraco.com/package/brevo.umbraco</link>
                    <description><![CDATA[Umbraco Forms workflow that creates or updates Brevo (Sendinblue) contacts on form submission. Supports field attribute mapping, list assignment, multi-value fields, structured logging, and startup validation.]]></description>
                    <pubDate>Mon, 20 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/mailchimp.umbraco</guid>
                    <title>Mailchimp.Umbraco</title>
                    <link>https://marketplace.umbraco.com/package/mailchimp.umbraco</link>
                    <description><![CDATA[Mailchimp workflow integration for Umbraco Forms]]></description>
                    <pubDate>Sat, 18 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://skttl.dev/blog/editor-friendly-404-page-in-umbraco/</guid>
                    <title>Editor Friendly 404 Pages in Umbraco</title>
                    <link>https://skttl.dev/blog/editor-friendly-404-page-in-umbraco/</link>
                    <description><![CDATA[Editor Friendly 404 Pages in Umbraco | skttl.dev]]></description>
                    <pubDate>Fri, 17 Apr 2026 14:30:00 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://skttl.dev/blog/auto-register-block-preview-in-umbraco/</guid>
                    <title>Auto-Register Block Previews in Umbraco</title>
                    <link>https://skttl.dev/blog/auto-register-block-preview-in-umbraco/</link>
                    <description><![CDATA[Auto-Register Block Previews in Umbraco | skttl.dev]]></description>
                    <pubDate>Fri, 17 Apr 2026 13:30:59 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/shorts/MHHTFLPqLVc</guid>
                    <title>Fun little photo upload feature for my umbraco site</title>
                    <link>https://www.youtube.com/shorts/MHHTFLPqLVc</link>
                    <description><![CDATA[The Umbraco backoffice isn&#x2019;t great for working with on mobile. I wanted to be able to upload photos I&#x2019;ve taken or even taken previously or even ones I&#x2019;m taking during the upload. Well now I can &#x1F600;&#x1F4F8;]]></description>
                    <pubDate>Fri, 17 Apr 2026 12:30:19 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/april/ocpowersort-120/</guid>
                    <title>OC.PowerSort 1.2.0</title>
                    <link>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/april/ocpowersort-120/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 17 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.bookmarks</guid>
                    <title>Umbraco.Community.Bookmarks</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.bookmarks</link>
                    <description><![CDATA[Bookmark content and media items for easy access and navigation]]></description>
                    <pubDate>Fri, 17 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/ubrokenwindow</guid>
                    <title>uBrokenWindow</title>
                    <link>https://marketplace.umbraco.com/package/ubrokenwindow</link>
                    <description><![CDATA[Generate a new backoffice user account on application startup. Use with care!]]></description>
                    <pubDate>Fri, 17 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/april/ocpowersort-120/</guid>
                    <title>OC.PowerSort 1.2.0</title>
                    <link>https://owain.codes/blog/2026/april/ocpowersort-120/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 17 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.schemeweaver</guid>
                    <title>Umbraco.Community.SchemeWeaver</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.schemeweaver</link>
                    <description><![CDATA[Map Umbraco Content Types to any of 780&#x2B; Schema.org types and automatically generate JSON-LD structured data. Features confidence-scored auto-mapping, a backoffice UI for manual fine-tuning, seven property source types (property, static, parent, ancestor, sibling, block content, complex), HTML/URL/date transforms, culture-aware variant support, Delivery API integration, and a Razor tag helper for server-rendered templates. Can also scaffold new Umbraco document types from Schema.org models.]]></description>
                    <pubDate>Fri, 17 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.schemeweaver.usync</guid>
                    <title>Umbraco.Community.SchemeWeaver.uSync</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.schemeweaver.usync</link>
                    <description><![CDATA[uSync addon for SchemeWeaver &#x2014; syncs Schema.org mappings (including resolver config and dynamic root config) between Umbraco environments alongside the doc types they belong to.]]></description>
                    <pubDate>Fri, 17 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://owaincodes.uksouth01.umbraco.io/blog/2026/april/ocpowersort-120/</guid>
                    <title>OC.PowerSort 1.2.0</title>
                    <link>https://owaincodes.uksouth01.umbraco.io/blog/2026/april/ocpowersort-120/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 17 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=Wrfwi7oGqG8</guid>
                    <title>Using Custom Umbraco AI Tools to Write a Whole Article Automatically</title>
                    <link>https://www.youtube.com/watch?v=Wrfwi7oGqG8</link>
                    <description><![CDATA[I want to be upfront about something, what you&#x2019;re seeing in this video is only possible because of the custom tools I&#x2019;ve written to work with Umbraco AI. Without those, none of this happens.&#xA;&#xA;In this video I show you how I can type a single prompt and have Umbraco AI go off, create a fully structured article, populate it with content blocks, add images, and publish it to my site. All in about 20&#x2013;30 seconds. I find that genuinely exciting and I think you will too.&#xA;&#xA;Here&#x2019;s what I walk through:&#xA;&#xA;- Prompting Umbraco AI to write and publish a complete blog article from scratch&#xA;- Watching it pick and fill content blocks automatically; text, code, tables, quotes, images&#xA;- Asking it to split content and insert a new block mid-article&#xA;- Getting it to add an image block at the end based on a description&#xA;- Seeing the finished article live on the front end&#xA;&#xA;This is the kind of thing that could be a real game changer for your editors, especially if you&#x2019;re on Umbraco 17. Even if you just want a solid starting point for an article rather than a blank page, this sort of tooling makes that really easy.]]></description>
                    <pubDate>Thu, 16 Apr 2026 14:28:29 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://mattbrailsford.dev/guardrails-in-umbraco-ai</guid>
                    <title>Guardrails in Umbraco AI</title>
                    <link>https://mattbrailsford.dev/guardrails-in-umbraco-ai</link>
                    <description><![CDATA[When you add AI to a CMS, you&#x2019;re giving it the power to generate content, respond to visitors, and interact with editors. That&#x2019;s powerful &#x2014; but it...]]></description>
                    <pubDate>Thu, 16 Apr 2026 08:30:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://codeshare.co.uk/blog/using-custom-umbraco-ai-tools-to-write-a-whole-article-automatically/</guid>
                    <title>Using Custom Umbraco AI Tools to Write a Whole Article Automatically</title>
                    <link>https://codeshare.co.uk/blog/using-custom-umbraco-ai-tools-to-write-a-whole-article-automatically/</link>
                    <description><![CDATA[In this video I show you how I can type a single prompt and have Umbraco AI go off, create a fully structured article, populate it with content blocks, add images, and publish it to my site.]]></description>
                    <pubDate>Thu, 16 Apr 2026 04:45:49 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.codeshare.co.uk/blog/using-custom-umbraco-ai-tools-to-write-a-whole-article-automatically/</guid>
                    <title>Using Custom Umbraco AI Tools to Write a Whole Article Automatically</title>
                    <link>https://www.codeshare.co.uk/blog/using-custom-umbraco-ai-tools-to-write-a-whole-article-automatically/</link>
                    <description><![CDATA[In this video I show you how I can type a single prompt and have Umbraco AI go off, create a fully structured article, populate it with content blocks, add images, and publish it to my site.]]></description>
                    <pubDate>Thu, 16 Apr 2026 04:45:49 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/agentrun.umbraco</guid>
                    <title>AgentRun.Umbraco</title>
                    <link>https://marketplace.umbraco.com/package/agentrun.umbraco</link>
                    <description><![CDATA[AI-powered workflow engine for Umbraco. Define multi-step agent workflows in YAML and run them from the backoffice. Ships with three ready-to-run examples: Umbraco Content Audit (analyses your site&#x27;s content tree), Content Quality Audit (scores any public URL), and Accessibility Quick-Scan (WCAG 2.1 AA findings). Extensible tool system &#x2014; add custom tools for your editorial workflows. Apache 2.0 licensed, built on Umbraco.AI.]]></description>
                    <pubDate>Thu, 16 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/digitalwonderlab.decluttertypes</guid>
                    <title>DigitalWonderlab.DeclutterTypes</title>
                    <link>https://marketplace.umbraco.com/package/digitalwonderlab.decluttertypes</link>
                    <description><![CDATA[Identify unused document types and data types across your Umbraco instance. Scan your published content and media to find types that are no longer in use, helping you keep your Umbraco installation clean and maintainable.]]></description>
                    <pubDate>Thu, 16 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.templates.uswds</guid>
                    <title>Umbraco.Community.Templates.USWDS</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.templates.uswds</link>
                    <description><![CDATA[A dotnet new template for creating an Umbraco CMS site with the U.S. Web Design System (USWDS). Includes pre-configured document types, block grid components, Razor views, USWDS Sass pipeline, and optional demo content.]]></description>
                    <pubDate>Thu, 16 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/the-agent-ready-cms-building-implementation-agent-skills-for-umbraco/</guid>
                    <title>The Agent-Ready CMS: Building Implementation Agent Skills for Umbraco</title>
                    <link>https://umbraco.com/blog/the-agent-ready-cms-building-implementation-agent-skills-for-umbraco/</link>
                    <description><![CDATA[Learn how Implementation Agent Skills for Umbraco will surface &quot;quiet standards&quot; and best practices to help developers build better CMS projects faster and easier.]]></description>
                    <pubDate>Thu, 16 Apr 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.ai.browserprovider</guid>
                    <title>Umbraco.Community.AI.BrowserProvider</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.ai.browserprovider</link>
                    <description><![CDATA[Experimental community Browser AI provider for Umbraco AI. Routes AI inference to Chrome&#x27;s built-in Gemini Nano model running locally in the browser. Requires Chrome 127&#x2B; with Prompt API enabled.]]></description>
                    <pubDate>Thu, 16 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbraco/116402714455403613</guid>
                    <title>Partner Summits 2026 annoucned</title>
                    <link>https://umbracocommunity.social/@umbraco/116402714455403613</link>
                    <description><![CDATA[Partner Summits 2026 are here &#x2705;Once again, we&#x2019;re bringing partners together across five markets to give you direct access to HQ insights, product direction, and leadership perspectives.&#x1F1F8;&#x1F1EA; Sweden &#x2013; 23 Sep 2026&#x1F1FA;&#x1F1F8; US &#x2013; Wed 30 Sep &#x2B; Thu 1 Oct 2026&#x1F1EC;&#x1F1E7; UK &#x2013; Thu 15 Oct 2026&#x1F1E9;&#x1F1EA; DACH &#x2013; Wed 11 Nov 2026&#x1F1F3;&#x1F1F1; BeNeLux &#x2013; Wed 18 Nov 2026These are partner-only events, and invitations are sent directly via email &#x1F4E9;If you haven&#x2019;t received yours yet, reach out to your Partner Manager.#Umbraco]]></description>
                    <pubDate>Tue, 14 Apr 2026 11:14:47 Z</pubDate>
                        <category>hq</category>
                        <category>mastodon</category>
                        <category>social</category>
                </item>
                <item>
                    <guid>https://www.codeshare.co.uk/blog/how-to-bypass-umbraco-cloud-basic-auth-for-preview-urls/</guid>
                    <title>How to Bypass Umbraco Cloud Basic Auth for Preview URLs</title>
                    <link>https://www.codeshare.co.uk/blog/how-to-bypass-umbraco-cloud-basic-auth-for-preview-urls/</link>
                    <description><![CDATA[Learn how to bypass Umbraco Cloud&amp;#x27;s Basic Authentication for specific preview URLs using the built-in shared secret feature and a lightweight ASP.NET middleware, without exposing the rest of your staging site.]]></description>
                    <pubDate>Tue, 14 Apr 2026 09:55:32 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://codeshare.co.uk/blog/how-to-bypass-umbraco-cloud-basic-auth-for-preview-urls/</guid>
                    <title>How to Bypass Umbraco Cloud Basic Auth for Preview URLs</title>
                    <link>https://codeshare.co.uk/blog/how-to-bypass-umbraco-cloud-basic-auth-for-preview-urls/</link>
                    <description><![CDATA[Learn how to bypass Umbraco Cloud&amp;#x27;s Basic Authentication for specific preview URLs using the built-in shared secret feature and a lightweight ASP.NET middleware, without exposing the rest of your staging site.]]></description>
                    <pubDate>Tue, 14 Apr 2026 09:55:32 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@owaincodes/116401706098179027</guid>
                    <title>Suggest your ideas for a Codegarden T-Shirt design on the community swag store</title>
                    <link>https://umbracocommunity.social/@owaincodes/116401706098179027</link>
                    <description><![CDATA[Planning to make a few new designs for the https://umbracocommunity.store in time for #codegarden this year. I need your help though, what designs / themes would you like to see? Post your ideas below &#x1F447; #Umbraco]]></description>
                    <pubDate>Tue, 14 Apr 2026 09:50:54 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@aaronsadleruk/116402331383861205</guid>
                    <title>Dotnet templates released preconfigured for our UmbHost Green Stack platform</title>
                    <link>https://umbracocommunity.social/@aaronsadleruk/116402331383861205</link>
                    <description><![CDATA[We have released 4 dotnet new templates and 4 GitHub template repositories preconfigured for our #GreenStack #Umbraco #hosting platform!2 are empty and clean #Umbraco instances, the others are 3 of the popular starterkit preconfigured (The Starter Kit, Clean Starter Kit &amp; UmBootstrap)This makes it easier than ever to get started!GitHub Template Repositories:https://github.com/UmbHost/GreenStack.Umbracohttps://github.com/UmbHost/GreenStack.Umbraco.CleanStarterKithttps://github.com/UmbHost/GreenStack.Umbraco.TheStarterKithttps://github.com/UmbHost/GreenStack.Umbraco.UmBootstrap]]></description>
                    <pubDate>Tue, 14 Apr 2026 09:50:37 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://mattbrailsford.dev/introducing-umbraco-ai-search</guid>
                    <title>Introducing Umbraco AI Search</title>
                    <link>https://mattbrailsford.dev/introducing-umbraco-ai-search</link>
                    <description><![CDATA[If you&#x2019;ve used the build in search in Umbraco, you&#x2019;ll know it&#x2019;s keyword-based. You type &#x201C;deployment guide&#x201D; and it finds pages containing those...]]></description>
                    <pubDate>Tue, 14 Apr 2026 08:30:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.favourites</guid>
                    <title>Umbraco.Community.Favourites</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.favourites</link>
                    <description><![CDATA[...]]></description>
                    <pubDate>Tue, 14 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://medium.com/@ben_46907/nah-the-umbraco-community-hasnt-lost-its-spark-we-have-de9f68e1fec7?source=rss------umbraco-5</guid>
                    <title>Nah, the Umbraco Community Hasn&#x2019;t Lost Its Spark-We Have</title>
                    <link>https://medium.com/@ben_46907/nah-the-umbraco-community-hasnt-lost-its-spark-we-have-de9f68e1fec7?source=rss------umbraco-5</link>
                    <description><![CDATA[&lt;div class=&quot;medium-feed-item&quot;&gt;&lt;p class=&quot;medium-feed-image&quot;&gt;&lt;a href=&quot;https://medium.com/@ben_46907/nah-the-umbraco-community-hasnt-lost-its-spark-we-have-de9f68e1fec7?source=rss------umbraco-5&quot;&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1200/0*10E3ART6rL7yxkkb&quot; width=&quot;1200&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;medium-feed-snippet&quot;&gt;What a contradictory title, please allow me to explain.&lt;/p&gt;&lt;p class=&quot;medium-feed-link&quot;&gt;&lt;a href=&quot;https://medium.com/@ben_46907/nah-the-umbraco-community-hasnt-lost-its-spark-we-have-de9f68e1fec7?source=rss------umbraco-5&quot;&gt;Continue reading on Medium &#xBB;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;]]></description>
                    <pubDate>Mon, 13 Apr 2026 15:56:01 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.linkedin.com/posts/umbukfdn_umbraco-uk-conference-teaser-activity-7447919930936590336-UgQs?utm_source=share&amp;utm_medium=member_ios&amp;rcm=ACoAAABj9KwBjr581HKBv-M3TbQu69Ia79rmfPw</guid>
                    <title>Umbraco UK Conference announced in London on October 16th 2026</title>
                    <link>https://www.linkedin.com/posts/umbukfdn_umbraco-uk-conference-teaser-activity-7447919930936590336-UgQs?utm_source=share&amp;utm_medium=member_ios&amp;rcm=ACoAAABj9KwBjr581HKBv-M3TbQu69Ia79rmfPw</link>
                    <description><![CDATA[https://www.linkedin.com/posts/umbukfdn_umbraco-uk-conference-teaser-activity-7447919930936590336-UgQs?utm_source=share&amp;utm_medium=member_ios&amp;rcm=ACoAAABj9KwBjr581HKBv-M3TbQu69Ia79rmfPw]]></description>
                    <pubDate>Fri, 10 Apr 2026 07:05:13 Z</pubDate>
                        <category>community</category>
                        <category>linkedin</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/proworks.umbraco.ai.pageevaluator</guid>
                    <title>ProWorks.Umbraco.AI.PageEvaluator</title>
                    <link>https://marketplace.umbraco.com/package/proworks.umbraco.ai.pageevaluator</link>
                    <description><![CDATA[An Umbraco 17 backoffice package that adds an Evaluate Page button to the content editor toolbar. When clicked, it sends the current page&#x27;s content to an AI model and returns a structured quality report directly inside the backoffice, including scored checks, warnings, and actionable suggestions.]]></description>
                    <pubDate>Fri, 10 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/uprofile-april-2026-will-steed/</guid>
                    <title>uProfile April 2026 - Will Steed</title>
                    <link>https://umbraco.com/blog/uprofile-april-2026-will-steed/</link>
                    <description><![CDATA[Meet Will - (maybe) the youngest Umbraco Certified Master yet?]]></description>
                    <pubDate>Fri, 10 Apr 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://mattbrailsford.dev/file-uploads-in-umbraco-ai</guid>
                    <title>File Uploads in Umbraco.AI</title>
                    <link>https://mattbrailsford.dev/file-uploads-in-umbraco-ai</link>
                    <description><![CDATA[File uploads have landed in Umbraco.AI. While the most visible change is in Copilot &#x2014; where you can now drag and drop documents directly into the...]]></description>
                    <pubDate>Thu, 09 Apr 2026 08:30:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/our.community.tags.popular</guid>
                    <title>Our.Community.Tags.Popular</title>
                    <link>https://marketplace.umbraco.com/package/our.community.tags.popular</link>
                    <description><![CDATA[A custom property editor for Umbraco 17 that displays the most-used tags in a named group and lets editors multi-select them to populate a sibling Tags property]]></description>
                    <pubDate>Thu, 09 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@joe/116369670163291835</guid>
                    <title>The value of Open Source Community</title>
                    <link>https://umbracocommunity.social/@joe/116369670163291835</link>
                    <description><![CDATA[At #UmbracoSpark I had the opportunity to chat with Fr&#xE9;d&#xE9;ric Harper about the value of #OpenSourceCommunity, watch the 10min clip here!https://joe.gl/ombek/talks/open-source-communities-giving-back-backstage-with-fred/#Umbraco #OpenSource #Community]]></description>
                    <pubDate>Wed, 08 Apr 2026 15:09:57 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=mW76ASdqCDs</guid>
                    <title>Umbraco Cloud testimonials</title>
                    <link>https://www.youtube.com/watch?v=mW76ASdqCDs</link>
                    <description><![CDATA[&quot;We use Umbraco Cloud for almost all our clients&#x2014;about 95% of them. The baseline functionality means we can spin up a site pretty quickly and get going fast, which reduces project time and budget while bringing more value to the customers.&quot;&#xA;&#xA;Find out more about Umbraco Cloud here: https://umbraco.com/products/umbraco-cloud/]]></description>
                    <pubDate>Wed, 08 Apr 2026 12:24:47 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://discord.com/channels/869656431308189746/882981290662580264/1491190165157187724</guid>
                    <title>CSP Manager 17.0.0-beta.1 is out</title>
                    <link>https://discord.com/channels/869656431308189746/882981290662580264/1491190165157187724</link>
                    <description><![CDATA[CSP Manager 17.0.0-beta.1 is out &#x1F389;                                                                                                                                                 &#xA;                                                                                                                                                                                      &#xA;  The major version now aligns with Umbraco CMS &#x2014; so v17 targets Umbraco 17&#x2B;. If you&#x27;re on Umbraco 13&#x2013;16, stay on the 3.x releases.                                                   &#xA;&#xA;  New: Import CSP policies in one click&#xA;  Paste a raw Content-Security-Policy header string, preview the directives, and import everything at once. No more recreating policies by hand.&#xA;&#xA;  New: uSync Publisher support&#xA;  Umbraco.Community.CSPManager.uSync.Complete is a brand new package &#x2014; push and pull CSP policies between Umbraco instances directly from the backoffice using the standard uSync     &#xA;  Publisher workflow.&#xA;&#xA;  The backoffice has been updated for Umbraco 17 with tree navigation and change tracking &#x2014; unsaved changes are detected before you navigate away.&#xA;&#xA;  Under the hood: fully async ICspService, expanded test suite (71 tests, up from 42), and test reports published on every PR.&#xA;&#xA;  Breaking changes to be aware of:&#xA;  - GetOrCreateCspScriptNonce / GetOrCreateCspStyleNonce replaced by a single GetOrCreateCspNonce&#xA;  - CspManagerContext.ScriptNonce / StyleNonce replaced by a single Nonce&#xA;  - Constants.PluginAlias removed &#x2014; use Constants.PackageAlias&#xA;  - ICspService has a new GetCspDefinitionAsync(Guid, CancellationToken) &#x2014; implement it if you have a custom ICspService&#xA;&#xA;  Three packages, one mono repo, all on NuGet:&#xA;  - https://www.nuget.org/packages/Umbraco.Community.CSPManager/17.0.0-beta.1&#xA;  - https://www.nuget.org/packages/Umbraco.Community.CSPManager.uSync/17.0.0-beta.4&#xA;  - https://www.nuget.org/packages/Umbraco.Community.CSPManager.uSync.Complete/]]></description>
                    <pubDate>Wed, 08 Apr 2026 08:06:00 Z</pubDate>
                        <category>social</category>
                        <category>discord</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://github.com/ProWorksCorporation/ProWorks-Umbraco.AI-Page-Evaluator</guid>
                    <title>ProWorks Umbraco AI Page Evaluator</title>
                    <link>https://github.com/ProWorksCorporation/ProWorks-Umbraco.AI-Page-Evaluator</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 08 Apr 2026 08:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://www.nevitech.co.uk/blog/indexing-word-excel-and-powerpoint-documents-in-umbraco-using-examine/</guid>
                    <title>Indexing Word, Excel and PowerPoint Documents in Umbraco Using Examine</title>
                    <link>https://www.nevitech.co.uk/blog/indexing-word-excel-and-powerpoint-documents-in-umbraco-using-examine/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 08 Apr 2026 05:28:42 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://bsky.app/profile/umbraco.com/post/3mivnuhezvy2d</guid>
                    <title>Meet the nominees for the Umbraco Awards 2026!</title>
                    <link>https://bsky.app/profile/umbraco.com/post/3mivnuhezvy2d</link>
                    <description><![CDATA[&#x1F680; Meet the nominees for the Umbraco Awards 2026! From stunning design to AI innovation and cloud solutions, these projects showcase the best of our community &#x1F3C6;&#xA;Check them out: umbra.co/3Oq6hY3&#xA;&#xA;#Umbraco&#xA;&#xA;]]></description>
                    <pubDate>Tue, 07 Apr 2026 14:43:09 Z</pubDate>
                        <category>bluesky</category>
                        <category>social</category>
                        <category>hq</category>
                </item>
                <item>
                    <guid>https://mattbrailsford.dev/why-umbraco-1740-is-a-big-deal-for-ai</guid>
                    <title>Why Umbraco 17.4.0 Is a Big Deal for AI</title>
                    <link>https://mattbrailsford.dev/why-umbraco-1740-is-a-big-deal-for-ai</link>
                    <description><![CDATA[If you told most Umbraco developers to get excited about a minor release, you&#x2019;d probably get a polite nod. Point releases aren&#x2019;t usually the ones...]]></description>
                    <pubDate>Tue, 07 Apr 2026 08:30:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/announcing-the-2026-umbraco-awards-nominees/</guid>
                    <title>Announcing the 2026 Umbraco Awards Nominees &#x1F3C6;</title>
                    <link>https://umbraco.com/blog/announcing-the-2026-umbraco-awards-nominees/</link>
                    <description><![CDATA[The jury has nailed it down to the very best of each category - check out the impressive Umbraco Award 2026 Nominees &#x1F3C6;]]></description>
                    <pubDate>Tue, 07 Apr 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://skrift.io/issues/#126</guid>
                    <title>Skrift Issue #126</title>
                    <link>https://skrift.io/issues/#126</link>
                    <description><![CDATA[Featuring guest posts by Bernadet Goey on &quot;Admin Only property using Granular Permissions in Umbraco 17&quot; and Dirk Seefeld on &quot;PostgreSQL Support for Umbraco&quot;]]></description>
                    <pubDate>Tue, 07 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                        <category>skrift</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.schema2yaml</guid>
                    <title>SplatDev.Umbraco.Plugins.Schema2Yaml</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.schema2yaml</link>
                    <description><![CDATA[An Umbraco plugin that exports your existing Umbraco schema and content to YAML format. Exports DataTypes, DocumentTypes, Media Types, Templates, Content, Media, Languages, Dictionary Items, Members, and Users to a declarative Infrastructure-as-Code YAML file. Supports Umbraco 13&#x2013;17.]]></description>
                    <pubDate>Sun, 05 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://github.com/skybrud/Skybrud.Umbraco.Redirects/releases/tag/v17.0.4</guid>
                    <title>Skybrud.Umbraco.Redirects 17.0.4</title>
                    <link>https://github.com/skybrud/Skybrud.Umbraco.Redirects/releases/tag/v17.0.4</link>
                    <description><![CDATA[Award winning redirects manager for Umbraco.]]></description>
                    <pubDate>Fri, 03 Apr 2026 23:19:02 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbracospark/116335310919405813</guid>
                    <title>Umbraco Spark 2026 is a wrap!</title>
                    <link>https://umbracocommunity.social/@umbracospark/116335310919405813</link>
                    <description><![CDATA[Umbraco Spark 2026 is a wrap! &#x26A1;What a fantastic day &#x2014; full of inspiring sessions, thoughtful conversations and everything that makes this community so special.Huge thanks to everyone who made it happen &#x1F49B;&#x1F3A5; Highlights video attached &#x2014; take a look!&#x1F4DD; Plus, all the conference buzz&#x2014;read our blog: https://gibe.digital/blog/spark-2026-highlights-code-community-creativity/ &#x1F4C5; Save the date: Friday 19th March 2027&#x1F39F; Tickets go on sale November 2026#umbracospark #umbraco #community #webevents #opensource]]></description>
                    <pubDate>Thu, 02 Apr 2026 13:20:50 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://mattbrailsford.dev/umbraco-ai-prompts-template-syntax-and-variables</guid>
                    <title>Umbraco AI Prompts: Template Syntax and Variables</title>
                    <link>https://mattbrailsford.dev/umbraco-ai-prompts-template-syntax-and-variables</link>
                    <description><![CDATA[Following on from my Introducing Umbraco AI post, I wanted to dig deeper into one of the add-on packages that I think has the most immediately...]]></description>
                    <pubDate>Thu, 02 Apr 2026 08:30:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://github.com/umbraco/Announcements/issues/30</guid>
                    <title>[Breaking change]: Casing on EF Core code constructs</title>
                    <link>https://github.com/umbraco/Announcements/issues/30</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Thu, 02 Apr 2026 07:34:59 Z</pubDate>
                        <category>hq</category>
                        <category>announcement</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/our.umbraco.postgresql</guid>
                    <title>Our.Umbraco.PostgreSql</title>
                    <link>https://marketplace.umbraco.com/package/our.umbraco.postgresql</link>
                    <description><![CDATA[Adds support for PostgreSQL to Umbraco CMS.]]></description>
                    <pubDate>Thu, 02 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.examine.openxml</guid>
                    <title>Umbraco.Community.Examine.OpenXml</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.examine.openxml</link>
                    <description><![CDATA[Extracts text content from OpenXml documents (.docx, .pptx, .xlsx) uploaded to the Umbraco media library and indexes it using Examine, making Office document content fully searchable.]]></description>
                    <pubDate>Thu, 02 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://jcdc.dev/blog/umbraco-spark-2026</guid>
                    <title>Umbraco Spark 2026</title>
                    <link>https://jcdc.dev/blog/umbraco-spark-2026</link>
                    <description><![CDATA[My notes and reflections from Umbraco Spark 2026 in Bristol. Covering every talk from Umbraco Search and backoffice collaboration to AI, cloud hosting and community.]]></description>
                    <pubDate>Tue, 31 Mar 2026 21:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.linkedin.com/posts/developerlee_merchello-documentation-share-7444728952901877760-Oz7Y/?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAAABj9KwBjr581HKBv-M3TbQu69Ia79rmfPw</guid>
                    <title>Merchello v17 Starter Site Template now available</title>
                    <link>https://www.linkedin.com/posts/developerlee_merchello-documentation-share-7444728952901877760-Oz7Y/?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAAABj9KwBjr581HKBv-M3TbQu69Ia79rmfPw</link>
                    <description><![CDATA[Merchello Starter Site Template]]></description>
                    <pubDate>Tue, 31 Mar 2026 13:23:34 Z</pubDate>
                        <category>community</category>
                        <category>linkedin</category>
                        <category>social</category>
                </item>
                <item>
                    <guid>https://www.linkedin.com/posts/adamshallcross_just-thought-i-would-share-a-sneakpeek-of-ugcPost-7444666108776873986-lvMW/?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAAEZMLBQB0B-TxZjsCmPSm4mFHU6Y9pFI12s</guid>
                    <title>AI agent workflows sneak peek</title>
                    <link>https://www.linkedin.com/posts/adamshallcross_just-thought-i-would-share-a-sneakpeek-of-ugcPost-7444666108776873986-lvMW/?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAAEZMLBQB0B-TxZjsCmPSm4mFHU6Y9pFI12s</link>
                    <description><![CDATA[Post | LinkedIn]]></description>
                    <pubDate>Tue, 31 Mar 2026 09:35:28 Z</pubDate>
                        <category>social</category>
                        <category>linkedin</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://www.linkedin.com/pulse/finding-my-spark-through-community-spinbox-digital-q5sme/</guid>
                    <title>Finding my Spark through Community</title>
                    <link>https://www.linkedin.com/pulse/finding-my-spark-through-community-spinbox-digital-q5sme/</link>
                    <description><![CDATA[(6) Finding my Spark through Community | LinkedIn]]></description>
                    <pubDate>Tue, 31 Mar 2026 08:55:52 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>linkedin</category>
                </item>
                <item>
                    <guid>https://github.com/Ambertvu/Umbraco.Community.IconPicker/releases/tag/17.0.0</guid>
                    <title>V17 of IconPicker has been released</title>
                    <link>https://github.com/Ambertvu/Umbraco.Community.IconPicker/releases/tag/17.0.0</link>
                    <description><![CDATA[https://github.com/Ambertvu/Umbraco.Community.IconPicker/releases/tag/17.0.0&#xA;V17 of IconPicker has been released. &#xA;- Add an sprite containing all the SVG&#x27;s&#xA;- Pick these in the backoffice&#xA;- Render them as SVG in the frontend, so you can apply styles and effects!]]></description>
                    <pubDate>Tue, 31 Mar 2026 08:26:38 Z</pubDate>
                        <category>package</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://www.spreaker.com/episode/live-from-spark-2026-ai-play-and-the-human-in-the-loop--71006607</guid>
                    <title>Live from Spark 2026: AI, Play and the Human in the Loop</title>
                    <link>https://www.spreaker.com/episode/live-from-spark-2026-ai-play-and-the-human-in-the-loop--71006607</link>
                    <description><![CDATA[Live from the Umbraco Spark Innovation Conference in Bristol! Emma, Laura and Lotte were joined by Phil Whittaker, AI Staff Engineer at Umbraco HQ - someone who&#x27;s been thinking and talking about AI in development for longer than most. Together we talk about play as a superpower for developer learning, what returning from maternity leave looks like in an AI-transformed workplace, why developers approaching retirement are finding a second wind, and why augmentation beats automation every time.&#xA0;&#xA0;&lt;br /&gt;&#xA0;&#xA0;&lt;br /&gt;A massive thank you to our live audience for missing out on the sunshine and making it so fun to record!&#xA0;&#xA0;&lt;br /&gt;&#xA0;&#xA0;&lt;br /&gt;Links:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Umbraco Spark: &lt;a href=&quot;https://umbracospark.com/&quot; target=&quot;_blank&quot; rel=&quot;noreferrer noopener&quot;&gt;https://umbracospark.com/&lt;/a&gt; &#xA0;&lt;/li&gt;&lt;li&gt;Phil Whittaker&#x27;s blog: &lt;a href=&quot;https://dev.to/phil-whittaker&quot; target=&quot;_blank&quot; rel=&quot;noreferrer noopener&quot;&gt;https://dev.to/phil-whittaker&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;]]></description>
                    <pubDate>Tue, 31 Mar 2026 06:01:17 Z</pubDate>
                        <category>community</category>
                        <category>podcast</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/utpro.feature.filemanager</guid>
                    <title>uTPro.Feature.FileManager</title>
                    <link>https://marketplace.umbraco.com/package/utpro.feature.filemanager</link>
                    <description><![CDATA[A powerful file management dashboard for Umbraco 16&#x2B; backoffice. Browse, upload, download, edit (with Monaco code editor), preview media, rename, delete, extract ZIP, and import files via URL. Features Windows Explorer-style navigation, role-based access control (Admin/Sensitive Data/Media), pagination for large directories, and URL state persistence. Zero configuration required.]]></description>
                    <pubDate>Tue, 31 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/march/optimizing-umbraco-member-pagination-from-slow-to-lightning-fast/</guid>
                    <title>Optimizing Umbraco Member Pagination From Slow to Lightning Fast</title>
                    <link>https://owain.codes/blog/2026/march/optimizing-umbraco-member-pagination-from-slow-to-lightning-fast/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Tue, 31 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.tiptap.markdownimport</guid>
                    <title>Umbraco.Community.TipTap.MarkdownImport</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.tiptap.markdownimport</link>
                    <description><![CDATA[Adds a Paste Markdown action to the Umbraco TipTap Rich Text Editor so editors can import Markdown into rich text fields as HTML content.]]></description>
                    <pubDate>Tue, 31 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/march/optimizing-umbraco-member-pagination-from-slow-to-lightning-fast/</guid>
                    <title>Optimizing Umbraco Member Pagination From Slow to Lightning Fast</title>
                    <link>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/march/optimizing-umbraco-member-pagination-from-slow-to-lightning-fast/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Tue, 31 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owaincodes.uksouth01.umbraco.io/blog/2026/march/optimizing-umbraco-member-pagination-from-slow-to-lightning-fast/</guid>
                    <title>Optimizing Umbraco Member Pagination From Slow to Lightning Fast</title>
                    <link>https://owaincodes.uksouth01.umbraco.io/blog/2026/march/optimizing-umbraco-member-pagination-from-slow-to-lightning-fast/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Tue, 31 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/phases.umbraco.community.tiptap.rte.emoji</guid>
                    <title>Phases.Umbraco.Community.Tiptap.Rte.Emoji</title>
                    <link>https://marketplace.umbraco.com/package/phases.umbraco.community.tiptap.rte.emoji</link>
                    <description><![CDATA[Adds a simple emoji picker to the Umbraco TipTap Rich Text Editor. Insert emojis directly into content using a searchable picker in the backoffice.]]></description>
                    <pubDate>Tue, 31 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://kjac.dev/posts/searching-file-content-with-umbraco-search/</guid>
                    <title>Searching file content with Umbraco Search</title>
                    <link>https://kjac.dev/posts/searching-file-content-with-umbraco-search/</link>
                    <description><![CDATA[Introducing a package for searching file content with Umbraco Search.]]></description>
                    <pubDate>Mon, 30 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.datatypecleanup</guid>
                    <title>Umbraco.Community.DataTypeCleanup</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.datatypecleanup</link>
                    <description><![CDATA[Clean up orphan data types, merge duplicates, and organize data types into folders by editor.]]></description>
                    <pubDate>Mon, 30 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.environmentindicator</guid>
                    <title>Umbraco.Community.EnvironmentIndicator</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.environmentindicator</link>
                    <description><![CDATA[Makes Umbraco backoffice environments stand out with colored favicons and environment name badges in the header.]]></description>
                    <pubDate>Mon, 30 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.yaml2schema</guid>
                    <title>SplatDev.Umbraco.Plugins.Yaml2Schema</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.yaml2schema</link>
                    <description><![CDATA[A declarative, Infrastructure-as-Code style plugin for Umbraco 17 that enables programmatic creation of DataTypes, DocumentTypes, Templates, and Content from a YAML configuration file. Define your entire Umbraco structure in YAML &#x2014; the plugin builds it automatically on startup.]]></description>
                    <pubDate>Mon, 30 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.nuget.org/packages/Umbraco.Community.ContentLock</guid>
                    <title>Content Lock 17.1.0 - aka the WebRTC Audio Calling edition</title>
                    <link>https://www.nuget.org/packages/Umbraco.Community.ContentLock</link>
                    <description><![CDATA[Content Lock 17.1.0 - aka the WebRTC Audio Calling edition&#xA;Latest release adds in audio calling to other logged in users of the backoffice with nothing to install.&#xA;So that quick call to another editor to hurry up and unlock the homenode so you can get the press release out before lunch can be done without having to remember what Microsoft Teams account you need to login to&#xA;&#xA;Docs Site&#xA;https://warrenbuckley.github.io/Umbraco.Community.ContentLock/&#xA;&#xA;Marketplace&#xA;https://marketplace.umbraco.com/package/umbraco.community.contentlock&#xA;&#xA;Nuget&#xA;https://www.nuget.org/packages/Umbraco.Community.ContentLock]]></description>
                    <pubDate>Fri, 27 Mar 2026 12:30:04 Z</pubDate>
                        <category>package</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=-b3HkTedXcA</guid>
                    <title>umbraCoffee - Spring Sips</title>
                    <link>https://www.youtube.com/watch?v=-b3HkTedXcA</link>
                    <description><![CDATA[Welcome to your monthly dose of #umbraCoffee&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;! Your hosts - Marcin and Callum - together with their guest(s) will drive through all of the community news and happenings in the Umbraco world. So... grab a cuppa, join us LIVE and enjoy!&#xA;&#xA;This time we&#x27;re joined by Umbraco Hacker, Maker and Do&#x27;er - Warren Buckley - to talk about everything Umbraco from the past moth.&#xA;&#xA;See ya?!&#xA;&#xA;---&#xA;&#x2615; Wanna buy us a coffee/pizza/donuts?&#xA;https://www.buymeacoffee.com/umbracoffee&#xA;---&#xA;&#xA;Notes:&#xA;// ToDo:]]></description>
                    <pubDate>Fri, 27 Mar 2026 08:51:45 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/utpro.feature.auditlog</guid>
                    <title>uTPro.Feature.AuditLog</title>
                    <link>https://marketplace.umbraco.com/package/utpro.feature.auditlog</link>
                    <description><![CDATA[Audit Log viewer dashboard for Umbraco 16&#x2B; backoffice. Browse umbracoAudit and umbracoLog tables with filtering, search, and pagination.]]></description>
                    <pubDate>Fri, 27 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://mattbrailsford.dev/understanding-contexts-in-umbraco-ai</guid>
                    <title>Understanding Contexts in Umbraco AI</title>
                    <link>https://mattbrailsford.dev/understanding-contexts-in-umbraco-ai</link>
                    <description><![CDATA[In my introductory post, I gave a high-level overview of how Umbraco AI is structured &#x2014; providers, connections, profiles, and contexts. Of those,...]]></description>
                    <pubDate>Fri, 27 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.propertyinfo</guid>
                    <title>Umbraco.Community.PropertyInfo</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.propertyinfo</link>
                    <description><![CDATA[Package Description]]></description>
                    <pubDate>Fri, 27 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=HLV0FeRKhNI</guid>
                    <title>Early concepts for Reuse Content of Blocks</title>
                    <link>https://www.youtube.com/watch?v=HLV0FeRKhNI</link>
                    <description><![CDATA[(4) Early concepts for Reuse Content of Blocks - YouTube]]></description>
                    <pubDate>Thu, 26 Mar 2026 13:08:18 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                        <category>social</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/modgift.umbraco.croninput</guid>
                    <title>Modgift.Umbraco.CronInput</title>
                    <link>https://marketplace.umbraco.com/package/modgift.umbraco.croninput</link>
                    <description><![CDATA[A property editor for Umbraco that provides a cron expression input with real-time human-readable descriptions. As the user types a cron expression, a label beneath the input instantly translates it into plain language. Includes an optional validation setting to prevent publishing without a valid expression.]]></description>
                    <pubDate>Thu, 26 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/announcing-the-umbraco-in-ai-community-team-the-ai-in-umbraco-advisory-board/</guid>
                    <title>Announcing the Umbraco in AI Community Team &amp; the AI in Umbraco Advisory Board</title>
                    <link>https://umbraco.com/blog/announcing-the-umbraco-in-ai-community-team-the-ai-in-umbraco-advisory-board/</link>
                    <description><![CDATA[Meet the 27 experts joining the Umbraco in AI Community Team and Advisory Board to help shape the future of AI tools and editor experiences within Umbraco.]]></description>
                    <pubDate>Thu, 26 Mar 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.nevitech.co.uk/blog/building-an-ai-powered-log-analyser-for-umbraco-at-the-spark-hackathon/</guid>
                    <title>Building an AI-Powered Log Analyser for Umbraco at the Spark Hackathon</title>
                    <link>https://www.nevitech.co.uk/blog/building-an-ai-powered-log-analyser-for-umbraco-at-the-spark-hackathon/</link>
                    <description><![CDATA[A look at how I built AI.LogAnalyser at the  @umbracospark.bsky.social Hackathon - an open-source package that adds one-click AI analysis to the Umbraco backoffice log viewer.  Powered by any AI provider via Umbraco AI.&#xA;&#xA;www.nevitech.co.uk/blog/buildin...&#xA;&#xA;#umbraco #ai #package&#xA;&#xA;]]></description>
                    <pubDate>Wed, 25 Mar 2026 09:50:08 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/rescope.contentdelivery</guid>
                    <title>Rescope.ContentDelivery</title>
                    <link>https://marketplace.umbraco.com/package/rescope.contentdelivery</link>
                    <description><![CDATA[Improves swagger definitions for use with typed client generators]]></description>
                    <pubDate>Wed, 25 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.updoc</guid>
                    <title>Umbraco.Community.UpDoc</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.updoc</link>
                    <description><![CDATA[Create Umbraco documents from external sources (PDF, web pages, markdown) using configurable extraction workflows with rule-based field mapping.]]></description>
                    <pubDate>Wed, 25 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/rescope.uastro</guid>
                    <title>Rescope.uAstro</title>
                    <link>https://marketplace.umbraco.com/package/rescope.uastro</link>
                    <description><![CDATA[Automatically build and serve static Astro sites within Umbraco]]></description>
                    <pubDate>Wed, 25 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/march/gitkraken-cli-beginners-guide/</guid>
                    <title>GitKraken CLI Beginner&#x27;s Guide: A Better Git CLI for Developers</title>
                    <link>https://owain.codes/blog/2026/march/gitkraken-cli-beginners-guide/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Tue, 24 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/metamateai</guid>
                    <title>MetaMateAI</title>
                    <link>https://marketplace.umbraco.com/package/metamateai</link>
                    <description><![CDATA[Umbraco plugin for generating creative meta title and meta description values for pages with missing metadata.]]></description>
                    <pubDate>Tue, 24 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.nathanielnunes.com/blog/umbraco-in-action-introduction-to-cms-for-students</guid>
                    <title>Umbraco In Action - Introduction to CMS for students</title>
                    <link>https://www.nathanielnunes.com/blog/umbraco-in-action-introduction-to-cms-for-students</link>
                    <description><![CDATA[Just put out a blog &#x2B; session recording from a talk I did with Coders Club students at Don Bosco College of Engineering, Fatorda.&#xA;&#xA;Started simple with &#x201C;what is a CMS&#x201D; before jumping into demos with Umbraco, headless setup with Next.js, and even a bit of AI.&#xA;&#xA;Good questions from the students, especially around WordPress vs Umbraco &#x1F440;&#xA;&#xA;Blog Post: https://www.nathanielnunes.com/blog/umbraco-in-action-introduction-to-cms-for-students&#xA;Video: https://youtu.be/znH8tnedIQg]]></description>
                    <pubDate>Mon, 23 Mar 2026 06:57:07 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/conzent.umbraco</guid>
                    <title>Conzent.Umbraco</title>
                    <link>https://marketplace.umbraco.com/package/conzent.umbraco</link>
                    <description><![CDATA[GDPR, CCPA &amp; ePrivacy compliant cookie consent banner for Umbraco. IAB TCF v2.3 and Google CMP Certified. Supports Conzent Cloud and self-hosted OCI.]]></description>
                    <pubDate>Mon, 23 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/modgift.umbraco.datagrid</guid>
                    <title>Modgift.Umbraco.DataGrid</title>
                    <link>https://marketplace.umbraco.com/package/modgift.umbraco.datagrid</link>
                    <description><![CDATA[A multiple column data editor property editor for Umbraco with strongly-typed DataGrid model.]]></description>
                    <pubDate>Sat, 21 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.deliveryapimodelmapper</guid>
                    <title>Umbraco.Community.DeliveryApiModelMapper</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.deliveryapimodelmapper</link>
                    <description><![CDATA[This package allows you to create custom models which will get ouput in the Delivery API response as a custom &quot;model&quot; property.]]></description>
                    <pubDate>Fri, 20 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.debasish.tech/blogs/developer-s-guide-to-creating-a-custom-umbraco-17-backoffice-dashboard/</guid>
                    <title>Developer&#x2019;s Guide to Creating a Custom Umbraco 17 Backoffice Dashboard</title>
                    <link>https://www.debasish.tech/blogs/developer-s-guide-to-creating-a-custom-umbraco-17-backoffice-dashboard/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 20 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.ai.loganalyser</guid>
                    <title>Umbraco.Community.AI.LogAnalyser</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.ai.loganalyser</link>
                    <description><![CDATA[Adds AI-powered log analysis to the Umbraco backoffice log viewer. Analyse any log entry with one click using your configured AI provider via Umbraco.AI.]]></description>
                    <pubDate>Fri, 20 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/growcreate.schemagenerator.core</guid>
                    <title>Growcreate.SchemaGenerator.Core</title>
                    <link>https://marketplace.umbraco.com/package/growcreate.schemagenerator.core</link>
                    <description><![CDATA[Schema Generator for Umbraco to create and render schema objects. Map document type properties to schema properties and allow editors to populate additional schemas.]]></description>
                    <pubDate>Fri, 20 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/growcreate.schemagenerator.deployaddon</guid>
                    <title>Growcreate.SchemaGenerator.DeployAddon</title>
                    <link>https://marketplace.umbraco.com/package/growcreate.schemagenerator.deployaddon</link>
                    <description><![CDATA[Schema Generator for Umbraco to create and render schema objects. Map document type properties to schema properties and allow editors to populate additional schemas.]]></description>
                    <pubDate>Fri, 20 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/jumoo.translationmanager.cleanup</guid>
                    <title>Jumoo.TranslationManager.Cleanup</title>
                    <link>https://marketplace.umbraco.com/package/jumoo.translationmanager.cleanup</link>
                    <description><![CDATA[Prodvides health checks to clean up archived jobs and nodes.]]></description>
                    <pubDate>Fri, 20 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/growcreate.schemagenerator.usyncaddon</guid>
                    <title>Growcreate.SchemaGenerator.uSyncAddon</title>
                    <link>https://marketplace.umbraco.com/package/growcreate.schemagenerator.usyncaddon</link>
                    <description><![CDATA[Schema Generator for Umbraco to create and render schema objects. Map document type properties to schema properties and allow editors to populate additional schemas.]]></description>
                    <pubDate>Fri, 20 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://dev.to/cultiv/setting-up-a-new-umbraco-package-dev-environment-with-umbracoai-3iac</guid>
                    <title>Setting Up a New Umbraco Package Dev Environment with Umbraco.AI</title>
                    <link>https://dev.to/cultiv/setting-up-a-new-umbraco-package-dev-environment-with-umbracoai-3iac</link>
                    <description><![CDATA[&lt;p&gt;This guide walks through setting up a new Umbraco package project called &lt;code&gt;Umbraco.Community.AI.Woowoo&lt;/code&gt; that extends &lt;a href=&quot;https://umbraco.com/marketplace/category/ai/&quot; rel=&quot;noopener noreferrer&quot;&gt;Umbraco.AI&lt;/a&gt;. Rather than starting from scratch with a blank solution, the goal is a proper package structure from day one: the right project layout, a frontend build pipeline, uSync, GitHub Actions for NuGet publishing, the works.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;That&#x27;s where &lt;a href=&quot;https://github.com/LottePitcher/opinionated-package-starter&quot; rel=&quot;noopener noreferrer&quot;&gt;Lotte&#x27;s Opinionated Package Starter Template&lt;/a&gt; comes in. Lotte has done the hard work of figuring out what a well-structured Umbraco package solution should look like, and turned it into a &lt;code&gt;dotnet new&lt;/code&gt; template. Pair that with Matt Brailsford&#x27;s &lt;a href=&quot;https://mattbrailsford.dev/umbraco-ai-kitchen-sink-install&quot; rel=&quot;noopener noreferrer&quot;&gt;Umbraco.AI Kitchen Sink install guide&lt;/a&gt;, and you have everything you need to go from zero to a fully wired-up Umbraco.AI development environment.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This post walks through the full setup, including the Linux-specific gotcha to watch out for.&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Prerequisites&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Before starting, make sure you have:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;.NET 10 SDK&lt;/strong&gt; -- Umbraco 17 targets .NET 10&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Node.js and npm&lt;/strong&gt; -- the package project uses Vite and TypeScript for its frontend&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;A GitHub account&lt;/strong&gt; -- the template wires up a GitHub remote and includes GitHub Actions for NuGet publishing&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Step 1: Install the template&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Install the package starter template from NuGet:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;dotnet new &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;Umbraco.Community.Templates.PackageStarter&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;You should see output ending with something like:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;Success: Umbraco.Community.Templates.PackageStarter::X.X.X installed the following templates:&#xA;  umbracopackagestarter&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;What does this template give you?&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;When you scaffold from it, you get a complete two-project solution:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;code&gt;src/AI.Woowoo/&lt;/code&gt; -- the package project, with Vite &#x2B; TypeScript frontend (via the &lt;code&gt;umbraco-extension&lt;/code&gt; template) and a NuGet-configured &lt;code&gt;.csproj&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;code&gt;src/AI.Woowoo.TestSite/&lt;/code&gt; -- an Umbraco 17 test site with uSync pre-configured&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;code&gt;src/AI.Woowoo.sln&lt;/code&gt; -- the solution file, with the TestSite already referencing the package project&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;code&gt;.github/workflows/release.yml&lt;/code&gt; -- a GitHub Action that publishes to NuGet when you push a version tag&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;code&gt;umbraco-marketplace.json&lt;/code&gt;, README stubs, issue templates, and an MIT &lt;code&gt;LICENSE&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;That&#x27;s a solid foundation for package development, covering all the scaffolding that would otherwise take hours to set up from scratch.&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Step 2: Scaffold the solution&#xA;&lt;/h2&gt;&#xA;&#xA;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;dotnet new umbracopackagestarter &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; AI.Woowoo &lt;span class=&quot;nt&quot;&gt;-an&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Your Name&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-gu&lt;/span&gt; YourGitHubUsername &lt;span class=&quot;nt&quot;&gt;-gr&lt;/span&gt; Umbraco.Community.AI.Woowoo &lt;span class=&quot;nt&quot;&gt;--allow-scripts&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;yes&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;What each parameter does:&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Parameter&lt;/th&gt;&#xA;&lt;th&gt;What it does&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;-n AI.Woowoo&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;The base name for the solution. The template prepends &lt;code&gt;Umbraco.Community.&lt;/code&gt;, so the NuGet package ID becomes &lt;code&gt;Umbraco.Community.AI.Woowoo&lt;/code&gt;&#xA;&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;-an &quot;Your Name&quot;&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Author name, used in the &lt;code&gt;.csproj&lt;/code&gt; and marketplace metadata&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;-gu YourGitHubUsername&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Your GitHub username, used to construct the repo URL&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;-gr Umbraco.Community.AI.Woowoo&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;The GitHub repository name&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;--allow-scripts yes&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Bypasses the security prompt for the post-creation script (&lt;code&gt;setup.cmd&lt;/code&gt;), which runs &lt;code&gt;npm install&lt;/code&gt; as part of the &lt;code&gt;umbraco-extension&lt;/code&gt; template setup&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&lt;/div&gt;&#xA;&#xA;&lt;p&gt;This will take a few minutes -- &lt;code&gt;npm install&lt;/code&gt; runs as part of the setup. Wait for the &quot;All done!&quot; message.&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Step 3: The Linux/macOS gotcha -- &lt;code&gt;setup.cmd&lt;/code&gt; won&#x27;t run&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;If you&#x27;re on Windows, you can skip this section.&lt;/strong&gt; The template&#x27;s &lt;code&gt;setup.cmd&lt;/code&gt; script will have run fine and your solution is ready. Jump straight to Step 4.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;p&gt;On Linux and macOS, the &lt;code&gt;setup.cmd&lt;/code&gt; post-creation script fails with &quot;Permission denied&quot; because it&#x27;s a Windows batch file. The template &lt;em&gt;files&lt;/em&gt; are all created correctly -- the script just doesn&#x27;t run, so the git repository, the frontend scaffolding, the solution wiring, and a few other things need to be done manually.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Here&#x27;s everything the script would have done, translated into commands you can run:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Initialise the git repository&lt;/span&gt;&#xA;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;AI.Woowoo&#xA;git init&#xA;git branch &lt;span class=&quot;nt&quot;&gt;-M&lt;/span&gt; main&#xA;git remote add origin https://github.com/YourGitHubUsername/Umbraco.Community.AI.Woowoo.git&#xA;&#xA;&lt;span class=&quot;c&quot;&gt;# Make sure you have the latest Umbraco dotnet templates&lt;/span&gt;&#xA;dotnet new &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;Umbraco.Templates &lt;span class=&quot;nt&quot;&gt;--force&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;c&quot;&gt;# Scaffold the package project inside src/&lt;/span&gt;&#xA;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;src&#xA;dotnet new umbraco-extension &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;AI.Woowoo&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--site-domain&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://localhost:44361&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--include-example&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;c&quot;&gt;# The template creates two .csproj files -- swap them so the NuGet-configured one is active&lt;/span&gt;&#xA;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;AI.Woowoo&#xA;&lt;span class=&quot;nb&quot;&gt;rm &lt;/span&gt;AI.Woowoo.csproj&#xA;&lt;span class=&quot;nb&quot;&gt;mv &lt;/span&gt;AI.Woowoo_nuget.csproj AI.Woowoo.csproj&#xA;&#xA;&lt;span class=&quot;c&quot;&gt;# Wire everything up in the solution&lt;/span&gt;&#xA;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ..&#xA;dotnet sln add &lt;span class=&quot;s2&quot;&gt;&quot;AI.Woowoo&quot;&lt;/span&gt;&#xA;dotnet add &lt;span class=&quot;s2&quot;&gt;&quot;AI.Woowoo.TestSite/AI.Woowoo.TestSite.csproj&quot;&lt;/span&gt; reference &lt;span class=&quot;s2&quot;&gt;&quot;AI.Woowoo/AI.Woowoo.csproj&quot;&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; The repo root also contains a &lt;code&gt;setup.mjs&lt;/code&gt; file -- a Node.js replacement for &lt;code&gt;setup.cmd&lt;/code&gt; that works cross-platform. If it&#x27;s present, running &lt;code&gt;node setup.mjs&lt;/code&gt; handles all the steps above.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Step 4: Build the frontend &amp;amp; verify the base site&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Before layering anything on top, confirm the scaffolded solution actually works. Build the frontend assets first:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;src/AI.Woowoo/Client&#xA;npm &lt;span class=&quot;nb&quot;&gt;install&#xA;&lt;/span&gt;npm run build&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;You should see Vite output with files written to &lt;code&gt;dist/&lt;/code&gt;. Now start the TestSite:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ../../AI.Woowoo.TestSite&#xA;dotnet run&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;The &lt;code&gt;launchSettings.json&lt;/code&gt; included by the template automatically sets &lt;code&gt;ASPNETCORE_ENVIRONMENT=Development&lt;/code&gt;, so you don&#x27;t need to set it yourself. On first run, Umbraco installs itself unattended -- watch the terminal output for the URL (typically &lt;code&gt;https://localhost:44331&lt;/code&gt; or similar).&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Log in with the pre-configured credentials from &lt;code&gt;appsettings.json&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Email:&lt;/strong&gt; &lt;code&gt;admin@example.com&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Password:&lt;/strong&gt; &lt;code&gt;1234567890&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;Check two things:&lt;/p&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Navigate to the &lt;strong&gt;Content&lt;/strong&gt; section -- an &quot;Example Dashboard&quot; should be there (this is the example added by the &lt;code&gt;--include-example&lt;/code&gt; flag in the &lt;code&gt;umbraco-extension&lt;/code&gt; template)&lt;/li&gt;&#xA;&lt;li&gt;Navigate to &lt;code&gt;/umbraco/swagger&lt;/code&gt; -- the &lt;strong&gt;Umbraco Management API&lt;/strong&gt; document should appear in the dropdown&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;p&gt;Once everything looks good, hit &lt;code&gt;Ctrl&#x2B;C&lt;/code&gt; to stop the site. You now have a clean, working base to build on.&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Step 5: Add the Umbraco.AI packages&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;All the Umbraco.AI packages go into the TestSite project, not the package project. The package project stays clean -- it will only reference &lt;code&gt;Umbraco.AI&lt;/code&gt; (or specific Umbraco.AI interfaces) when actually needed for package code. The TestSite is the development host.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Run these from the repo root (&lt;code&gt;AI.Woowoo/&lt;/code&gt;):&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# The Clean starter kit adds a demo content structure to the site&lt;/span&gt;&#xA;dotnet add &lt;span class=&quot;s2&quot;&gt;&quot;src/AI.Woowoo.TestSite&quot;&lt;/span&gt; package Clean&#xA;&#xA;&lt;span class=&quot;c&quot;&gt;# The core Umbraco.AI integration layer&lt;/span&gt;&#xA;dotnet add &lt;span class=&quot;s2&quot;&gt;&quot;src/AI.Woowoo.TestSite&quot;&lt;/span&gt; package Umbraco.AI&#xA;&#xA;&lt;span class=&quot;c&quot;&gt;# Addons&lt;/span&gt;&#xA;dotnet add &lt;span class=&quot;s2&quot;&gt;&quot;src/AI.Woowoo.TestSite&quot;&lt;/span&gt; package Umbraco.AI.Prompt&#xA;dotnet add &lt;span class=&quot;s2&quot;&gt;&quot;src/AI.Woowoo.TestSite&quot;&lt;/span&gt; package Umbraco.AI.Agent&#xA;dotnet add &lt;span class=&quot;s2&quot;&gt;&quot;src/AI.Woowoo.TestSite&quot;&lt;/span&gt; package Umbraco.AI.Agent.Copilot &lt;span class=&quot;nt&quot;&gt;--prerelease&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;c&quot;&gt;# AI providers&lt;/span&gt;&#xA;dotnet add &lt;span class=&quot;s2&quot;&gt;&quot;src/AI.Woowoo.TestSite&quot;&lt;/span&gt; package Umbraco.AI.Amazon&#xA;dotnet add &lt;span class=&quot;s2&quot;&gt;&quot;src/AI.Woowoo.TestSite&quot;&lt;/span&gt; package Umbraco.AI.Anthropic&#xA;dotnet add &lt;span class=&quot;s2&quot;&gt;&quot;src/AI.Woowoo.TestSite&quot;&lt;/span&gt; package Umbraco.AI.Google&#xA;dotnet add &lt;span class=&quot;s2&quot;&gt;&quot;src/AI.Woowoo.TestSite&quot;&lt;/span&gt; package Umbraco.AI.MicrosoftFoundry&#xA;dotnet add &lt;span class=&quot;s2&quot;&gt;&quot;src/AI.Woowoo.TestSite&quot;&lt;/span&gt; package Umbraco.AI.OpenAI&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;A couple of notes:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;code&gt;Umbraco.AI.Agent.Copilot&lt;/code&gt; requires &lt;code&gt;--prerelease&lt;/code&gt; because it&#x27;s still in alpha. The other packages are stable.&lt;/li&gt;&#xA;&lt;li&gt;All five provider packages (Amazon Bedrock, Anthropic, Google, Microsoft Foundry, OpenAI) are installed so the environment is ready for any AI provider you or contributors want to test against. The seed data in the next step only activates the OpenAI connection, but the others are configured and waiting.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;Check &lt;a href=&quot;https://mattbrailsford.dev/umbraco-ai-kitchen-sink-install&quot; rel=&quot;noopener noreferrer&quot;&gt;Matt&#x27;s install guide&lt;/a&gt; if you&#x27;re following along later -- version numbers may have moved on. The &lt;a href=&quot;https://github.com/umbraco/Umbraco.AI/tree/main/docs/public&quot; rel=&quot;noopener noreferrer&quot;&gt;Umbraco.AI documentation&lt;/a&gt; covers all the extensibility points in detail if you want to go further.&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Step 6: Add the seed demo data&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Matt has a helpful GitHub Gist that seeds a full Umbraco.AI demo configuration: a connection, profile, context, prompts, and agents. It&#x27;s a self-registering C# file -- drop it in the project and it registers itself via Umbraco&#x27;s component system and seeds the data on first startup. It&#x27;s also idempotent, so safe to leave in place.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; src/AI.Woowoo.TestSite/UmbracoAISeedData.cs &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&#xA;  &lt;span class=&quot;s2&quot;&gt;&quot;https://gist.githubusercontent.com/mattbrailsford/199d0b45e926ffb122fa96467039bd90/raw/UmbracoAISeedData.cs?v=2&quot;&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  API key (optional)&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;The seed data installs an OpenAI connection with a dummy key. The site runs fine without a real key -- all the AI configuration gets seeded into the backoffice, the connection just won&#x27;t be functional. Replace the key later through the Umbraco.AI section in the backoffice once everything is up and running.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Don&#x27;t have an OpenAI key? Google hands out free Gemini API keys via &lt;a href=&quot;https://aistudio.google.com/app/apikey&quot; rel=&quot;noopener noreferrer&quot;&gt;Google AI Studio&lt;/a&gt; -- no credit card required. Hit &quot;Create API key&quot; in the top right, or &quot;Get API key&quot; in the left sidebar. The free tier is generous enough for development. If you go this route, use the &lt;code&gt;Umbraco.AI.Google&lt;/code&gt; provider and configure the connection in the backoffice accordingly.&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Step 7: Run and verify&#xA;&lt;/h2&gt;&#xA;&#xA;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;src/AI.Woowoo.TestSite&#xA;dotnet run&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Once it&#x27;s running, log in (&lt;code&gt;admin@example.com&lt;/code&gt; / &lt;code&gt;1234567890&lt;/code&gt;) and navigate to the &lt;strong&gt;Umbraco.AI&lt;/strong&gt; section in the backoffice. You should see:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A seeded OpenAI connection&lt;/li&gt;&#xA;&lt;li&gt;A profile&lt;/li&gt;&#xA;&lt;li&gt;A context&lt;/li&gt;&#xA;&lt;li&gt;Several prompts&lt;/li&gt;&#xA;&lt;li&gt;Several agents&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;If you added a real API key, try running a prompt or agent to confirm the connection is live.&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Step 8: Make the initial commit&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Before staging everything, do a quick sanity check: open &lt;code&gt;UmbracoAISeedData.cs&lt;/code&gt; and confirm there&#x27;s no real API key in there.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;git add &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;&#xA;git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;chore: initial scaffold from Lotte&#x27;s Opinionated Package Starter Template&quot;&lt;/span&gt;&#xA;git push &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; origin main&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;Prerequisite:&lt;/strong&gt; before pushing, go to GitHub and create a new empty repository named &lt;code&gt;Umbraco.Community.AI.Woowoo&lt;/code&gt; (skip the readme, license, and gitignore options -- the template already created those locally). The template already configured the remote, so &lt;code&gt;git push&lt;/code&gt; goes straight to the right place.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  What&#x27;s next&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The environment is now ready:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;code&gt;src/AI.Woowoo/&lt;/code&gt; -- the package project, clean and ready for package code&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;code&gt;src/AI.Woowoo.TestSite/&lt;/code&gt; -- a full Umbraco 17 &#x2B; Umbraco.AI host to develop and test against, with demo data seeded&lt;/li&gt;&#xA;&lt;li&gt;GitHub Actions configured for NuGet publishing on version tags&lt;/li&gt;&#xA;&lt;li&gt;All five AI providers installed and ready to configure&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;When it comes to implementing the package itself, the first thing to add to &lt;code&gt;src/AI.Woowoo/AI.Woowoo.csproj&lt;/code&gt; is a reference to &lt;code&gt;Umbraco.AI.Core&lt;/code&gt; -- the package that contains all the extension points (custom tools, middleware, guardrail evaluators, etc.):&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;dotnet add src/AI.Woowoo package Umbraco.AI.Core &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt; 1.6.0&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Note that &lt;code&gt;Umbraco.AI.Core&lt;/code&gt; 1.6.0 requires Umbraco.Cms 17.1.0 or higher. The template scaffolds the package project against 17.0.0, so bump the four Umbraco.Cms references in the same file to 17.1.0 when you add this.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The next step is implementing the &lt;code&gt;Umbraco.Community.AI.Woowoo&lt;/code&gt; package itself -- but that&#x27;s a story for another post.&lt;/p&gt;]]></description>
                    <pubDate>Thu, 19 Mar 2026 09:30:57 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.ai.propertyvalidation</guid>
                    <title>Umbraco.Community.AI.PropertyValidation</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.ai.propertyvalidation</link>
                    <description><![CDATA[AI-powered property validation for Umbraco CMS using the Umbraco.AI infrastructure.]]></description>
                    <pubDate>Thu, 19 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/growcreate.schemagenerator</guid>
                    <title>Growcreate.SchemaGenerator</title>
                    <link>https://marketplace.umbraco.com/package/growcreate.schemagenerator</link>
                    <description><![CDATA[Schema Generator for Umbraco to create and render schema objects. Map document type properties to schema properties and allow editors to populate additional schemas.]]></description>
                    <pubDate>Thu, 19 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/kraftvaerk.umbraco.alchemy</guid>
                    <title>Kraftvaerk.Umbraco.Alchemy</title>
                    <link>https://marketplace.umbraco.com/package/kraftvaerk.umbraco.alchemy</link>
                    <description><![CDATA[AI-powered developer assistant for the Umbraco backoffice &#x2014; generates property descriptions, document type descriptions, UFM block labels, and content type icons.]]></description>
                    <pubDate>Thu, 19 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/march/ocpowersort-package/</guid>
                    <title>OC.PowerSort package</title>
                    <link>https://owain.codes/blog/2026/march/ocpowersort-package/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 18 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/oc.powersort</guid>
                    <title>OC.PowerSort</title>
                    <link>https://marketplace.umbraco.com/package/oc.powersort</link>
                    <description><![CDATA[A powerful sorting extension for Umbraco CMS that provides enhanced sorting capabilities for content nodes in the backoffice.]]></description>
                    <pubDate>Wed, 18 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbracoa11y/116246055536313833</guid>
                    <title>The Call for Speakers for UMBRAAD 2026 is open!</title>
                    <link>https://umbracocommunity.social/@umbracoa11y/116246055536313833</link>
                    <description><![CDATA[&#x1F680; The Call for Speakers for UMBRAAD 2026 is open! Take to the virtual stage and present your insights on digital accessibility to the Umbraco community during Global Accessibility Awareness Day. Whether you&#x27;re an experienced presenter or simply passionate about enhancing the web, your contribution is welcome! Key Details:&#x1F5D3;&#xFE0F;  Date: 21st May 2026&#x1F4A1;  Topics: Neurodiversity,  AI &amp; Accessibility, Inclusive UX, Accessibility Fatigue, and more!Submit your session idea: https://sessionize.com/umbraad-2026/]]></description>
                    <pubDate>Tue, 17 Mar 2026 19:27:22 Z</pubDate>
                        <category>community</category>
                        <category>mastodon</category>
                        <category>social</category>
                </item>
                <item>
                    <guid>https://www.nevitech.co.uk/blog/getting-started-with-umbraco-ai/</guid>
                    <title>Getting Started with Umbraco AI</title>
                    <link>https://www.nevitech.co.uk/blog/getting-started-with-umbraco-ai/</link>
                    <description><![CDATA[At last night&#x27;s Umbraco Kent Meetup, I gave a live demo on the new AI integrations in the Umbraco back office. If you missed it - or just want a recap - I&#x27;ve put together a blog post covering everything.&#xA;&#xA;www.nevitech.co.uk/blog/getting...&#xA;&#xA;#umbraco #ai #umbracoai @umb.fyi&#xA;&#xA;]]></description>
                    <pubDate>Tue, 17 Mar 2026 11:56:09 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/march/ocufmfallbacks-package/</guid>
                    <title>OC.UFMFallbacks Package</title>
                    <link>https://owain.codes/blog/2026/march/ocufmfallbacks-package/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Tue, 17 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/umbraco-s-spring-2026-g2-highlights-strong-usability-wins-across-headless-dxp-cms-and-webops/</guid>
                    <title>Umbraco Recognized as a G2 Leader Across CMS and Headless in the Spring 2026 Reports</title>
                    <link>https://umbraco.com/blog/umbraco-s-spring-2026-g2-highlights-strong-usability-wins-across-headless-dxp-cms-and-webops/</link>
                    <description><![CDATA[See Umbraco&#x2019;s Winter 2026 G2 results across CMS, Headless, DXP, and WebOps, including key badges, usability gains, and implementation highlights.]]></description>
                    <pubDate>Tue, 17 Mar 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.jobsjobsjobs</guid>
                    <title>Umbraco.Community.JobsJobsJobs</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.jobsjobsjobs</link>
                    <description><![CDATA[Backoffice dashboard for recurring Umbraco background jobs with status, manual triggering, persisted run history, cooperative stop support, and opt-in CRON scheduling.]]></description>
                    <pubDate>Tue, 17 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/oc.ufmfallbacks</guid>
                    <title>OC.UFMFallbacks</title>
                    <link>https://marketplace.umbraco.com/package/oc.ufmfallbacks</link>
                    <description><![CDATA[An Umbraco package that extends Umbraco Flavored Markdown (UFM) with a {fbk:} component, giving you property fallbacks and text filters directly inside block labels and other UFM contexts.]]></description>
                    <pubDate>Tue, 17 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=Vn881L24YZU</guid>
                    <title>The Umbraco Playground &#x2014; Experiment, build, and share 1</title>
                    <link>https://www.youtube.com/watch?v=Vn881L24YZU</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 16 Mar 2026 10:04:35 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://richardsoeteman.net/blog/automatically-filter-content-delivery-api-content/</guid>
                    <title>Automatically Filter Content Delivery API Content</title>
                    <link>https://richardsoeteman.net/blog/automatically-filter-content-delivery-api-content/</link>
                    <description><![CDATA[Just Blogged:&#xA;Automatically Filter Content Delivery API Content without applying a filter in querystring parameters..&#xA;https://richardsoeteman.net/blog/automatically-filter-content-delivery-api-content/]]></description>
                    <pubDate>Mon, 16 Mar 2026 09:37:18 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://dev.to/matthewwise/a-practical-guide-to-svgs-in-umbraco-1gm6</guid>
                    <title>A Practical Guide to SVGs in Umbraco</title>
                    <link>https://dev.to/matthewwise/a-practical-guide-to-svgs-in-umbraco-1gm6</link>
                    <description><![CDATA[&lt;p&gt;If you&#x27;ve ever tried to use SVGs properly in Umbraco, you&#x27;ll know it&#x27;s not quite plug-and-play. Icons, logos, illustrations - SVGs are everywhere on the modern web.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Out of the box Umbraco will let you upload SVGs. It even has a dedicated &lt;code&gt;Vector Graphics (SVG)&lt;/code&gt; media type. But there are two things I wanted to improve.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The Two Problems&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Inlining for CSS control.&lt;/strong&gt; &lt;/p&gt;&#xA;&#xA;&lt;p&gt;If you serve an SVG as an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag, it works - but you lose most of what makes SVGs useful. You can&#x27;t style it with CSS, you can&#x27;t use &lt;code&gt;currentColor&lt;/code&gt; to inherit text colour, you can&#x27;t target individual paths for hover states or animations. To get that level of control you need the SVG markup inlined directly into your HTML.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;But inlining creates its own issues. An &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag sandboxes its content - scripts inside the SVG won&#x27;t execute. Inline that same SVG into the page and any &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags or &lt;code&gt;javascript:&lt;/code&gt; handlers will run. An editor could unknowingly upload an SVG containing an XSS attack, and you&#x27;d be serving it straight into the DOM. SVGs from design tools also come with hard-coded &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes that fight your CSS when inlined - you want a &lt;code&gt;viewBox&lt;/code&gt; instead.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Duplicate requests on &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags.&lt;/strong&gt; &lt;br&gt;&#xA;Not every SVG needs to be inlined. But when you call &lt;code&gt;GetCropUrl()&lt;/code&gt; on a media item, Umbraco adds crop and resize parameters to the URL. So &lt;code&gt;GetCropUrl(200)&lt;/code&gt; produces &lt;code&gt;example.svg?width=200&lt;/code&gt;, and &lt;code&gt;GetCropUrl(48)&lt;/code&gt; produces &lt;code&gt;example.svg?width=48&lt;/code&gt;. The browser treats those as different URLs - meaning if you use the same SVG at multiple sizes, it gets downloaded multiple times instead of once. For a vector image that scales to any size, those parameters are pointless and the duplicate requests are pure waste.&lt;/p&gt;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Securing SVG Uploads&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Since we&#x27;re inlining SVGs into the page, we need to make sure they&#x27;re safe before they get anywhere near the DOM.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Umbraco has an &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/reference/security/server-side-file-validation#ifilestreamsecurityanalyzer&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;IFileStreamSecurityAnalyzer&lt;/code&gt;&lt;/a&gt; interface that gets called when media is uploaded. Umbraco doesn&#x27;t ship with an SVG implementation, but the docs include an example. My version makes two changes to that example: it drops the &lt;code&gt;xmlns&lt;/code&gt; check (since not all SVGs include it) and adds a check for &lt;code&gt;javascript:&lt;/code&gt; protocol handlers:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SvgXssSecurityAnalyzer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IFileStreamSecurityAnalyzer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ShouldHandle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;c1&quot;&gt;// reduce memory footprint by partially reading the file&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startBuffer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;endBuffer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;fileStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ReadExactly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;fileStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Seek&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SeekOrigin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;fileStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Seek&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;endBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SeekOrigin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;fileStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ReadExactly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startString&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UTF8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;endString&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UTF8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&amp;lt;svg&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;               &lt;span class=&quot;p&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;endString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/svg&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IsConsideredSafe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;c1&quot;&gt;// do not use a using as this will dispose of the underlying stream&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;streamReader&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;StreamReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileContent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;streamReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ReadToEnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&amp;lt;script&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;                &lt;span class=&quot;p&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/script&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;                &lt;span class=&quot;p&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;javascript:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Registration is a single line in DI:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddSingleton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IFileStreamSecurityAnalyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SvgXssSecurityAnalyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Storing SVG Content for Inline Rendering&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;To inline SVGs in your templates, you need the actual SVG markup available at render time. You could read the file on every request, but that&#x27;s expensive. Storing the markup as a property on the media item means it gets served from Umbraco&#x27;s cache instead of hitting IO on every render.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Add a custom property called &lt;code&gt;svgContent&lt;/code&gt; to the &lt;code&gt;Vector Graphics (SVG)&lt;/code&gt; media type in Umbraco, then create a notification handler that populates it automatically whenever an SVG is saved.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The property type matters here. A &lt;code&gt;Label (string)&lt;/code&gt; won&#x27;t work - SVG markup easily exceeds 512 characters. If you&#x27;re on Umbraco 17.3.0&#x2B; the &lt;code&gt;Label (long string)&lt;/code&gt; type stores as &lt;code&gt;Text&lt;/code&gt; in the database, but on earlier 17.x versions there&#x27;s a &lt;a href=&quot;https://github.com/umbraco/Umbraco-CMS/issues/21853&quot; rel=&quot;noopener noreferrer&quot;&gt;known issue&lt;/a&gt; where it&#x27;s capped at 512 characters. If that affects you, you&#x27;ll need a custom data type to store the content.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;//Umbraco extension manifest:&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;manifests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;UmbExtensionManifest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;propertyEditorUi&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Website.PropertyEditorUi.LongLabel&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Website Long label&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;elementName&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;umb-property-editor-ui-label&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Long Label&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;icon-list&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;common&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;propertyEditorSchemaAlias&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Umbraco.Plain.Json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//Means we get IHtmlEncodedString in c#&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Using a &lt;code&gt;MediaSavingNotification&lt;/code&gt; handler to read the file content, clean up the markup, and stores it in &lt;code&gt;svgContent&lt;/code&gt; whenever an SVG is saved. For each SVG node it generates a &lt;code&gt;viewBox&lt;/code&gt; from existing dimensions if one doesn&#x27;t exist, strips &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes, and removes the &lt;code&gt;xmlns&lt;/code&gt; declaration. The &lt;code&gt;viewBox&lt;/code&gt; logic here is based on the approach used in &lt;a href=&quot;https://github.com/umbraco-community/Our-Umbraco-TagHelpers&quot; rel=&quot;noopener noreferrer&quot;&gt;Our.Umbraco.TagHelpers&lt;/a&gt; - well worth a look if you haven&#x27;t already:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;HtmlDocument&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;HtmlDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;&lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LoadHtml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;svgs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DocumentNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SelectNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;//svg&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;svgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;width&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;height&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;viewbox&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Decimal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TryParse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetAttributeValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;width&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&#xA;                &lt;span class=&quot;k&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Decimal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TryParse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetAttributeValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;height&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&#xA;                &lt;span class=&quot;k&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetAttributeValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;viewbox&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;                &lt;span class=&quot;s&quot;&gt;$&quot;0 0 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;width&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;height&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;xmlns&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;This all happens once at upload time. Editors don&#x27;t need to think about it. The full handler with error handling is in the complete example at the end of the post.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The handler is registered on the Umbraco builder:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddNotificationAsyncHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MediaSavingNotification&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StoreSvgContentMediaSavingNotificationHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Cleaning Up the Image Pipeline for SVGs&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Remember that issue with adding width and height to SVG output. here&#x27;s how to fix that&lt;/p&gt;&#xA;&#xA;&lt;p&gt;what about something along this line?&lt;br&gt;&#xA;The &lt;code&gt;DontCropSvgsImageUrlGenerator&lt;/code&gt; wraps the default generator. If the image is an SVG, it creates a new &lt;code&gt;ImageUrlGenerationOptions&lt;/code&gt; with only the URL - stripping all crop and resize parameters. Everything else passes through normally:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetImageUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ImageUrlGenerationOptions&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ImageUrl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ImageUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;EndsWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.svg&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_imageGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetImageUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ImageUrlGenerationOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ImageUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_imageGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetImageUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;The registration replaces Umbraco&#x27;s default &lt;code&gt;IImageUrlGenerator&lt;/code&gt;, wrapping the original &lt;code&gt;ImageSharpImageUrlGenerator&lt;/code&gt; inside the decorator:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RemoveAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IImageUrlGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//Umbraco only has one by default&lt;/span&gt;&#xA;&lt;span class=&quot;n&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddSingleton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IImageUrlGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DontCropSvgsImageUrlGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;generator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ImageSharpImageUrlGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetRequiredService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SixLabors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ImageSharp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(),&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RequestAuthorizationUtilities&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(),&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetRequiredService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ImageSharpMiddlewareOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;());&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;DontCropSvgsImageUrlGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Rendering the SVG Content&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;With all of this in place, using SVGs in Razor views is straightforward. An extension method on &lt;code&gt;MediaWithCrops&lt;/code&gt; surfaces the stored SVG content (using the &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-14#extension-members&quot; rel=&quot;noopener noreferrer&quot;&gt;C# 14 extension members&lt;/a&gt; syntax on .NET 10):&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;nf&quot;&gt;extension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MediaWithCrops&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IHtmlEncodedString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SvgContent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Content&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UmbracoMediaVectorGraphics&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;svg&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;svg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SvgContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;svg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SvgContent&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Then in a component, render the SVG inline if available, falling back to an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag otherwise:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight html&quot;&gt;&lt;code&gt;@if (Model.Icon.SvgContent is not null)&#xA;{&#xA;    @Model.Icon.SvgContent&#xA;}&#xA;else&#xA;{&#xA;    &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;@Model.Icon.GetCropUrl(48, 48)&quot;&lt;/span&gt;&#xA;         &lt;span class=&quot;na&quot;&gt;alt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;@Model.Icon.GetAltText()&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;loading=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;lazy&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;An alternative here would be to create a custom tag helper in a similar way to Our.Umbraco.TagHelpers.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Wrapping Up&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Together it gives you a solid SVG story in Umbraco: editors upload SVGs as normal, the code secures them, fixes the sizing, and serves them from a single URL or inline with full CSS control as the developer and site need.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The Full Handler&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Here&#x27;s the complete &lt;code&gt;StoreSvgContentMediaSavingNotificationHandler&lt;/code&gt; ready to copy-paste:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StoreSvgContentMediaSavingNotificationHandler&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INotificationAsyncHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MediaSavingNotification&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SvgContentPropertyAlias&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;svgContent&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MediaFileManager&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_mediaFileManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ILogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StoreSvgContentMediaSavingNotificationHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;StoreSvgContentMediaSavingNotificationHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;MediaFileManager&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mediaFileManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;ILogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StoreSvgContentMediaSavingNotificationHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;_mediaFileManager&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mediaFileManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;_logger&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;HandleAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;MediaSavingNotification&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;notification&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;CancellationToken&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;svg&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;notification&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SavedEntities&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ContentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Alias&lt;/span&gt;&#xA;                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;InvariantEquals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UmbConstants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Conventions&lt;/span&gt;&#xA;                    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MediaTypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;VectorGraphicsAlias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;svg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;HasProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SvgContentPropertyAlias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_mediaFileManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;svg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;                &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;StreamReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;                &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileContents&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&#xA;                    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ReadToEndAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;                &lt;span class=&quot;n&quot;&gt;HtmlDocument&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;HtmlDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LoadHtml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;                &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;svgs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DocumentNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SelectNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;//svg&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;                &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;svgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;                &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;width&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;                        &lt;span class=&quot;p&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;height&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&#xA;                    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;viewbox&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&#xA;                        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Decimal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TryParse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;                                &lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetAttributeValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;width&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&#xA;                                &lt;span class=&quot;k&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;                            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Decimal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TryParse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;                                &lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetAttributeValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;height&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&#xA;                                &lt;span class=&quot;k&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;                            &lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetAttributeValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;viewbox&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;                                &lt;span class=&quot;s&quot;&gt;$&quot;0 0 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;                        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;                        &lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;width&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;                        &lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;height&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;                    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;                    &lt;span class=&quot;n&quot;&gt;svgNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;xmlns&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;                &lt;span class=&quot;n&quot;&gt;fileContents&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DocumentNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OuterHtml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;svg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SvgContentPropertyAlias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IOException&lt;/span&gt;&#xA;                &lt;span class=&quot;p&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FileNotFoundException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LogError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;                    &lt;span class=&quot;s&quot;&gt;&quot;Unable to read file to set SVG content &quot;&lt;/span&gt;&#xA;                    &lt;span class=&quot;p&quot;&gt;&#x2B;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;for media item with ID {MediaId}.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;                    &lt;span class=&quot;n&quot;&gt;svg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  References&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/reference/security/server-side-file-validation#ifilestreamsecurityanalyzer&quot; rel=&quot;noopener noreferrer&quot;&gt;Server-side file validation | Umbraco Documentation&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&quot;https://github.com/umbraco-community/Our-Umbraco-TagHelpers&quot; rel=&quot;noopener noreferrer&quot;&gt;Our.Umbraco.TagHelpers&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;]]></description>
                    <pubDate>Mon, 16 Mar 2026 09:22:37 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/march/ocufmmemberslookup-package/</guid>
                    <title>OC.UFMMembersLookup package</title>
                    <link>https://owain.codes/blog/2026/march/ocufmmemberslookup-package/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 16 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/the-agent-ready-cms-introducing-agent-skills-umbraco-backoffice-extension/</guid>
                    <title>The Agent-Ready CMS:  Introducing Agent Skills: Umbraco Backoffice Extension</title>
                    <link>https://umbraco.com/blog/the-agent-ready-cms-introducing-agent-skills-umbraco-backoffice-extension/</link>
                    <description><![CDATA[From turning rough ideas into working wireframes to building complex backoffice extensions without hallucinations, discover how we&#x2019;re making AI a practical tool for Umbraco development.]]></description>
                    <pubDate>Mon, 16 Mar 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.urestore</guid>
                    <title>Umbraco.Community.uRestore</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.urestore</link>
                    <description><![CDATA[Extends the Umbraco backoffice with a Property Restore workspace tab, allowing editors to compare any saved content version against the current draft and selectively restore individual property values without affecting the rest of the content.]]></description>
                    <pubDate>Mon, 16 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/pulseforumbraco</guid>
                    <title>PulseForUmbraco</title>
                    <link>https://marketplace.umbraco.com/package/pulseforumbraco</link>
                    <description><![CDATA[Your Umbraco site&#x27;s operational health monitor. Pulse scans your content, configuration, performance, and security &#x2014; giving you an actionable health score and one-click remediation from inside the backoffice.]]></description>
                    <pubDate>Mon, 16 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://cornehoskam.com/posts/why-implicit-scoring-isnt-always-enough-for-personalization/</guid>
                    <title>Why Implicit Scoring Isn&#x27;t Always Enough for Personalization</title>
                    <link>https://cornehoskam.com/posts/why-implicit-scoring-isnt-always-enough-for-personalization/</link>
                    <description><![CDATA[Implicit scoring works great for most visitors, but what happens when the system gets it wrong? Let&#x27;s take a look at how Explicit Scoring in Umbraco Engage gives marketers the confidence to stop guessing.]]></description>
                    <pubDate>Mon, 16 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/march/ocufmmemberlookup-package/</guid>
                    <title>OC.UFMMemberLookup Package</title>
                    <link>https://owain.codes/blog/2026/march/ocufmmemberlookup-package/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 16 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/oc.ufmmemberlookup</guid>
                    <title>OC.UFMMemberLookup</title>
                    <link>https://marketplace.umbraco.com/package/oc.ufmmemberlookup</link>
                    <description><![CDATA[An Umbraco Flavoured Markdown extension to allow for searching Member data]]></description>
                    <pubDate>Mon, 16 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://github.com/limbo-works/Limbo.Umbraco.Separator/releases/tag/v17.0.0</guid>
                    <title>Limbo.Umbraco.Separator 17.0.0</title>
                    <link>https://github.com/limbo-works/Limbo.Umbraco.Separator/releases/tag/v17.0.0</link>
                    <description><![CDATA[Limbo.Separator is a small package for Umbraco that adds a property editor serving as a separator to give a better overview of properties within your Umbraco content types.]]></description>
                    <pubDate>Sun, 15 Mar 2026 20:58:37 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://www.enkelmedia.se/blogg/2026/3/15/programmatically-create-umbraco-members-and-set-password?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=rss</guid>
                    <title>Programmatically create Umbraco Members and set Password</title>
                    <link>https://www.enkelmedia.se/blogg/2026/3/15/programmatically-create-umbraco-members-and-set-password?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=rss</link>
                    <description><![CDATA[&lt;p&gt;Over the last months, I&#x27;ve been working on moving websites from Umbraco 13 up to Umbraco 17. I had a really hard time to find good documentation on how to work with Members so I figured I&#x27;ll write a short blog post to fill some of the &quot;gaps&quot; I experienced in the documentation.&lt;/p&gt;&#xA;&lt;h2&gt;What is Member in Umbraco?&lt;/h2&gt;&#xA;&lt;p&gt;A &lt;strong&gt;Member&lt;/strong&gt; in Umbraco is an external or frontend user. In other words, this is the kind of account you would use for things like a customer area, intranet login, gated content, forums, and similar functionality on the public-facing site.&lt;/p&gt;&#xA;&lt;h2&gt;Working with Members programmatically&lt;/h2&gt;&#xA;&lt;p&gt;When working with Umbraco Members programmatically you need to familiarize your self with the &lt;em&gt;IMemberService &lt;/em&gt;and the &lt;em&gt;IMemberManager&lt;/em&gt;.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;IMemberService is used to work with the IMember object, set username, email and update custom properties.&lt;/li&gt;&#xA;&lt;li&gt;IMemberManager is used to perform login, get current member and set password.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Here is a code sample that will create a member programmatically and set the password programmatically.&lt;/p&gt;&#xA;&lt;div&gt;&#xD;&#xA;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public class MemberRegistrationService&#xA;{&#xA;    private readonly IMemberService _memberService;&#xA;    private readonly IMemberManager _memberManager;&#xA;    private readonly IPasswordHasher _passwordHasher;&#xA;&#xA;    public MemberRegistrationService(&#xA;        IMemberService memberService,&#xA;        IMemberManager memberManager,&#xA;        IPasswordHasher passwordHasher&#xA;        )&#xA;    {&#xA;        _memberService = memberService;&#xA;        _memberManager = memberManager;&#xA;        _passwordHasher = passwordHasher;&#xA;    }&#xA;&#xA;    public async Task&amp;lt;IMember&amp;gt; CreateMemberAsync(string email, string password, string name)&#xA;    {&#xA;        var member = _memberService.CreateMember(&#xA;            email,&#xA;            email,&#xA;            name,&#xA;            &amp;quot;Member&amp;quot;); // or Member.ModelTypeAlias with ModelsBuilder&#xA;        &#xA;        member.IsApproved = true;&#xA;&#xA;        _memberService.Save(member);&#xA;&#xA;        // Optionally add to a role&#xA;        _memberService.AssignRole(member.Id, &amp;quot;Member&amp;quot;); &#xA;&#xA;        // Set password&#xA;        var memberIdentity = await _memberManager.FindByIdAsync(member.Id.ToString());&#xA;        var passwordResult = await _memberManager.AddPasswordAsync(memberIdentity!, password);&#xA;&#xA;        // Alternative way of setting password&#xA;        member.RawPasswordValue = _passwordHasher.HashPassword(password);&#xA;&#xA;        return member;&#xA;    }&#xA;}&lt;/code&gt;&lt;/pre&gt;&#xD;&#xA;&lt;/div&gt;&#xD;&#xA;&#xD;&#xA;&#xA;&lt;p&gt;&#xA0;&lt;/p&gt;&#xA;&lt;p&gt;..&lt;/p&gt;&#xA;&lt;p&gt;&#xA0;&lt;/p&gt;&#xA;&lt;p&gt;&#xA0;&lt;/p&gt;]]></description>
                    <pubDate>Sun, 15 Mar 2026 14:19:20 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://dev.to/d_inventor/im-learning-python-with-ai-and-tdd-40aa</guid>
                    <title>I&#x27;m learning python with AI and TDD</title>
                    <link>https://dev.to/d_inventor/im-learning-python-with-ai-and-tdd-40aa</link>
                    <description><![CDATA[&lt;p&gt;I decided to make my next hobby project in python. I used this project to learn python, but also to become familiar with AI-assisted coding. In this article I document my experiences with AI as a pair programming buddy, doing Test-Driven Development together.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  About TDD, the project and me&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Test-Driven Development is about writing tests before writing your code. This is often done in the Red, Green, Refactor cycle: Write a failing test, specifying the behaviour that the code should exhibit, make all tests pass with as few changes as possible and finally make your code (and your tests) nice. It&#x27;s a design tool that helps make your code easier to understand and maintain.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The project is a self-hosted information database that connects &lt;a href=&quot;https://animalcrossing.nintendo.com/amiibo/#welcome&quot; rel=&quot;noopener noreferrer&quot;&gt;Animal Crossing Amiibos&lt;/a&gt; to information on &lt;a href=&quot;https://nookipedia.com/wiki/Main_Page&quot; rel=&quot;noopener noreferrer&quot;&gt;Nookipedia&lt;/a&gt;. An API exposes the data so that an app can scan an amiibo and direct the user straight to the character&#x27;s page on the Nookipedia. The project, besides providing desired functionality, is also an excuse for me to try out some enterprise software patterns that I wish to learn more about.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&lt;div class=&quot;ltag-github-readme-tag&quot;&gt;&#xA;  &lt;div class=&quot;readme-overview&quot;&gt;&#xA;    &lt;h2&gt;&#xA;      &lt;img src=&quot;https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg&quot; alt=&quot;GitHub logo&quot;&gt;&#xA;      &lt;a href=&quot;https://github.com/D-Inventor&quot; rel=&quot;noopener noreferrer&quot;&gt;&#xA;        D-Inventor&#xA;      &lt;/a&gt; / &lt;a href=&quot;https://github.com/D-Inventor/my-animal-crossing-app&quot; rel=&quot;noopener noreferrer&quot;&gt;&#xA;        my-animal-crossing-app&#xA;      &lt;/a&gt;&#xA;    &lt;/h2&gt;&#xA;    &lt;h3&gt;&#xA;      This is a hobby project. It is a combination of an app for android and a python-based server API. The server supplies information about Animal Crossing villagers. The app lets me scan Amiibo cards and then I can see basic information about the villager.&#xA;    &lt;/h3&gt;&#xA;  &lt;/div&gt;&#xA;  &lt;div class=&quot;ltag-github-body&quot;&gt;&#xA;    &#xA;&lt;div id=&quot;readme&quot; class=&quot;md&quot;&gt;&#xA;&lt;p&gt;This is a hobby project.&#xA;I wanted to get easy access to basic villager information from my Amiibo card collection.&lt;/p&gt;&#xA;&lt;p&gt;This project combines an android app with a python-based API so that I can scan the NFC chip of an amiibo card and then fetch the information. That&#x27;s all.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;/div&gt;&#xA;&lt;br&gt;&#xA;  &lt;div class=&quot;gh-btn-container&quot;&gt;&lt;a class=&quot;gh-btn&quot; href=&quot;https://github.com/D-Inventor/my-animal-crossing-app&quot; rel=&quot;noopener noreferrer&quot;&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;&#xA;&lt;br&gt;&#xA;&lt;/div&gt;&#xA;&lt;br&gt;&#xA;&#xA;&#xA;&lt;p&gt;I am a dotnet developer with very little python experience. Python has a special place in my heart, because it&#x27;s the first language that I earned some money with. That was more than 10 years ago and I haven&#x27;t touched python that much since then.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  AI as a pair programming buddy&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Most of the code in this project has been written by AI. Overall, the results were mostly good, sometimes very frustrating, but sometimes also very impressive.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Scaffolding a project baseline&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Yes, AI got me started very quickly and effectively. I knew what I wanted: multiple python projects in a monorepo with some shared modules. I know what python code looks like, but actually setting up a project like this is quite a lot. Setting up testing with pytest, multiple independent modules with a shared pyproject.toml. Module imports are very confusing in python and if you don&#x27;t know what you&#x27;re doing, they&#x27;re difficult to get right sometimes. I asked the AI to do it for me with working examples of unit tests and shared modules. It did all of it, the code ran, the tests worked and the code looked acceptable. Big win &#x1F4AA;&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  So many comments, so much &quot;documentation&quot;&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;It was really my own fault and it was quickly fixed. The AI was writing excessive comments. Every generated function filled with comments and &quot;documentation&quot;, detailing exactly what the code does. That&#x27;s not what I need comments for. I can read the code to see what it does. The thing here is that I let the AI generate its own instruction file and the instruction file literally instructed the AI to do this. I simply updated the instruction file and instructed the AI to never write comments.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Stop! Wait! Not so fast! Not so much!&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Some people may find it wonderful: just tell the AI what you want to make and it&#x27;ll happily build the whole thing for you. Or try to at least... Although it&#x27;s magnificent, I think it&#x27;s also incredibly irresponsible to let AI generate large amounts of code at once. Especially in a professional environment, I would be held personally responsible for bugs and mistakes and saying &quot;it&#x27;s the fault of the AI&quot; simply will not fly. It&#x27;s essential that I can review the code that the AI generates and I can only do this if I develop in small steps.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Test-Driven Development has been very helpful to put a leash on the AI. AI is very eager to write code and will simply sprint to the finish line if you let it. By strictly following the Red, Green, Refactor cycle, I was able to stay more in control of what the AI does and how it does it. It took a bit of trial-and-error, but the following instructions seemed to be very helpful:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Follow strict TDD practice with Red, Green and Refactor phases&lt;/li&gt;&#xA;&lt;li&gt;Always run the test in the Red phase to verify that the test fails in the way that we expect&lt;/li&gt;&#xA;&lt;li&gt;Prefer runtime failures over compile-time failures at all times&lt;/li&gt;&#xA;&lt;li&gt;Prefer failures on assertions over failures in code under test whenever this is reasonable&lt;/li&gt;&#xA;&lt;li&gt;Make sure in the green phase to write as little code as possible to make the test pass&lt;/li&gt;&#xA;&lt;li&gt;Always ask for verification from the user after each phase before proceeding to the next&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;Additionally, it seemed helpful when I start each session with &quot;We are pair programming buddies and we are going to do Test Driven Development&quot;. Nevertheless, the AI would still occasionally do more than I asked for, especially the green phase was difficult at times.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Please give me an example in the form of an automated test&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;In this project I needed a handful of slightly more advanced concepts, including:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Messaging&lt;/li&gt;&#xA;&lt;li&gt;HTTP API calls&lt;/li&gt;&#xA;&lt;li&gt;Database querying&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;Though the concepts are familiar, I had never done them in python specifically. I know approximately what good integrations look like, but I simply needed some examples in python specifically. AI has been an excellent tool for learning and it helped me to understand python frameworks, tools and syntax. By asking about it in the shape of an automated test, I could also immediately apply the concepts I learned with Test Driven Development. This was a massive win! I would like to share a particular experience that really blew my mind.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;I needed to build an integration with an external HTTP API. Coincidentally, I recently also had to do this for work in dotnet, so I had a good idea what a good integration looks like and also how a good unit test looks for such an integration. It had taken me about 5 hours to build in dotnet. I asked the AI to generate me an example of a unit test that demonstrates an http request and response in python. the unit test was quite bloated and unreadable, but it did work. I told the AI as much and I gave it an example of what I expected the test to look like, based on a test that I wrote in dotnet. I asked to refactor the test to make it as close as possible to the example that I gave. In just a few minutes it generated exactly the testing utility that I had spent several hours on earlier! This was shocking and incredibly impressive.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Thoughts overall&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;In general, I find the workflow decent. Although I did get much further with AI in a shorter amount of time than I would have without, I don&#x27;t believe (yet) that AI is a massive time-saver overall. That sounds like a contradiction, but you must see that it was my lack of understanding of the python ecosystem that held me back and not the speed by which I type code. Although the AI can create code much faster than me, the code is often not up to standards and at times I have had to throw away work of the past 10 minutes, because prompting for corrections was only making things worse.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;An important thing, in my opinion, is that AI may replace your typing, but shouldn&#x27;t replace your brain. The skills that I&#x27;ve developed as a professional developer are still required to judge the quality of the output and are still essential to prioritize long-term success over short-term gains.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;So yeah, if you haven&#x27;t tried it yet, perhaps you could also turn your AI into your TDD pair programming buddy. Thank you for reading and maybe I&#x27;ll see you in my next blog! &#x1F60A;&lt;/p&gt;]]></description>
                    <pubDate>Sun, 15 Mar 2026 08:57:27 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/digitalwonderlab.accessibilitytoolkit</guid>
                    <title>DigitalWonderlab.AccessibilityToolkit</title>
                    <link>https://marketplace.umbraco.com/package/digitalwonderlab.accessibilitytoolkit</link>
                    <description><![CDATA[Comprehensive WCAG 2.1 accessibility auditing for Umbraco backoffice. 37 checks across Level A, AA, and AAA with scored results, scan history, site-wide audits, printable reports, and CSV export. Lightweight with no external dependencies &#x2014; works on Umbraco Cloud and all hosting environments out of the box.]]></description>
                    <pubDate>Sat, 14 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/uprofile-march-2026-debasish-gracias/</guid>
                    <title>uProfile March 2026 - Debasish Gracias</title>
                    <link>https://umbraco.com/blog/uprofile-march-2026-debasish-gracias/</link>
                    <description><![CDATA[On a mission to inspire, connect, and bring together the global Umbraco community]]></description>
                    <pubDate>Fri, 13 Mar 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.uaccessible</guid>
                    <title>Umbraco.Community.uAccessible</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.uaccessible</link>
                    <description><![CDATA[Accessibility audit reports for your Umbraco content pages, directly in the backoffice.]]></description>
                    <pubDate>Fri, 13 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://dev.to/jemayn/a-first-look-at-load-balancing-the-umbraco-backoffice-1ihm</guid>
                    <title>A first look at load balancing the Umbraco backoffice</title>
                    <link>https://dev.to/jemayn/a-first-look-at-load-balancing-the-umbraco-backoffice-1ihm</link>
                    <description><![CDATA[&lt;p&gt;When Umbraco 17 released there was a lot of focus on it being the first LTS version of Umbraco using the new web component based backoffice, and for a lot of people that was important enough in itself.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;I must admit the only other feature I paid attention to is that dates now consistently have a timezone on them making it much easier to work with them.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;However, one thing I somehow managed to miss completely was that as of Umbraco 17 you can now load balance the backoffice of Umbraco.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Isn&#x27;t load balancing Umbraco an old feature?&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Load balancing Umbraco sites has been around for longer than I have used Umbraco - so at least since v7!&lt;/p&gt;&#xA;&#xA;&lt;p&gt;It used to work a certain way as shown in this diagram based on the official documentation:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkahi3hzslz6mjahtzlen.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkahi3hzslz6mjahtzlen.png&quot; alt=&quot;Traditional Umbraco load balancing architecture&quot; width=&quot;502&quot; height=&quot;719&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/load-balancing#how-umbraco-load-balancing-works&quot; rel=&quot;noopener noreferrer&quot;&gt;Source: Umbraco documentation&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Which basically meant that what most people doing load balancing would do is spin up 2 Azure Web Apps, deploy the same code to both of them but have some settings that would designate one web app as the frontend app and one as the backend app.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Both apps would use the same database, and with some specific settings added you could allow the frontend app to scale out - for example by setting some rules that determines what amount of load the frontend should be under before it starts additional instances to automatically scale out.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This works pretty well, but also means that the minimal amount of infrastructure was 2 web apps - and if you had a lot of editors then there was no way to scale out the backend to accommodate extra load there.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Load balancing the backoffice&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;So the new thing in Umbraco 17 is that you can now load balance everything. One immediate effect that could have is that you now just need a single web app for a basic scale out site, something like this:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1o0plpamgcszwjnc54pn.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1o0plpamgcszwjnc54pn.png&quot; alt=&quot;New Umbraco load balancing architecture&quot; width=&quot;742&quot; height=&quot;615&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&#xA;&lt;div class=&quot;crayons-card c-embed&quot;&gt;&#xA;&#xA;  &lt;br&gt;&#xA;Shout out &lt;a href=&quot;https://mermaid.js.org/&quot; rel=&quot;noopener noreferrer&quot;&gt;MermaidJS charts&lt;/a&gt;. AI agents are very good at translating described flows into charts, and it makes it so much easier to create visuals!&lt;br&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&lt;p&gt;This setup could theoretically make it cheaper, and it&#x27;s also easier to have a regular site running just 1 instance with the option of scaling out for big peaks in load without a bunch of extra setup! &lt;/p&gt;&#xA;&#xA;&lt;p&gt;So first you have to decide between the &quot;old&quot; way of load balancing with separate backend and frontend webapps and the &quot;new&quot; way of having a single scaleable app for both.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Secondly if choosing the &quot;new&quot; way of scaling a single app there is also a choice of whether the backoffice should use sticky sessions or be stateless.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;There are a lot of articles about pros and cons for both:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&quot;https://www.linode.com/docs/guides/configuring-load-balancer-sticky-session/&quot; rel=&quot;noopener noreferrer&quot;&gt;https://www.linode.com/docs/guides/configuring-load-balancer-sticky-session/&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&quot;https://www.imperva.com/learn/availability/sticky-session-persistence-and-cookies/&quot; rel=&quot;noopener noreferrer&quot;&gt;https://www.imperva.com/learn/availability/sticky-session-persistence-and-cookies/&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/azure/load-balancer/load-balancer-best-practices#check-your-distribution-mode&quot; rel=&quot;noopener noreferrer&quot;&gt;https://learn.microsoft.com/en-us/azure/load-balancer/load-balancer-best-practices#check-your-distribution-mode&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;But in short the difference is how traffic is distributed:&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Sticky sessions&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Once a request hits the load balancer it is assigned to an instance and a cookie is returned on the response that has a reference to that instance. &lt;/li&gt;&#xA;&lt;li&gt;Future requests pass the cookie along to the load balancer, and it ensures that the new request hits the same instance.&lt;/li&gt;&#xA;&lt;li&gt;If x amount of users cause the server resources to spike to the point that more instances are added based on the load balancing rules, you can end up having a lot of users &quot;stick&quot; to the initial instance due to their cookies.&lt;/li&gt;&#xA;&lt;li&gt;If the instance a user is &quot;stuck&quot; to gets removed during a scale-down, the load balancer assigns them to a new instance - which can cause problems (more on that below).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Stateless&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Once a request hits the load balancer it is assigned to the instance with the least load&lt;/li&gt;&#xA;&lt;li&gt;This ensures a much more equal distribution between instances&lt;/li&gt;&#xA;&lt;li&gt;This also makes things like sessions or SignalR connections a lot more complicated to manage&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Setting up a backoffice load balanced site&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The following setup applies to both sticky sessions and stateless, with the exception of SignalR which differs between the two and is covered separately at the end.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The assumption here is that the load balanced site will be hosted on Azure as a web app. &lt;br&gt;&#xA;The current documentation will always be the most relevant resource: &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/load-balancing/load-balancing-backoffice&quot; rel=&quot;noopener noreferrer&quot;&gt;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/load-balancing/load-balancing-backoffice&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;As of writing this for Umbraco 17, there are some settings that should be set no matter if it is a sticky session or stateless setup:&lt;/p&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Set &lt;code&gt;Umbraco:Cms:Examine:LuceneDirectoryFactory&lt;/code&gt; to &lt;code&gt;TempFileSystemDirectoryFactory&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Set &lt;code&gt;Umbraco:Cms:Hosting:LocalTempStorageLocation&lt;/code&gt; to &lt;code&gt;EnvironmentTemp&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Set the &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/load-balancing/load-balancing-backoffice#server-role-accessor&quot; rel=&quot;noopener noreferrer&quot;&gt;Server role accessor&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/load-balancing/load-balancing-backoffice#load-balancing-repository-caches&quot; rel=&quot;noopener noreferrer&quot;&gt;IsolatedCaches&lt;/a&gt;:&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LoadBalancingComposer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComposer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;    &#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Compose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IUmbracoBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;        &#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LoadBalanceIsolatedCaches&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetServerRegistrar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;StaticServerAccessor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StaticServerAccessor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IServerRoleAccessor&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ServerRole&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CurrentServerRole&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ServerRole&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SchedulingPublisher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Note: In the traditional setup you&#x27;d have one SchedulingPublisher and multiple Subscribers. With the new backoffice load balancing, check the &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/load-balancing/load-balancing-backoffice#server-role-accessor&quot; rel=&quot;noopener noreferrer&quot;&gt;current documentation&lt;/a&gt; for how server roles should be assigned, as this may differ from what you&#x27;re used to.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Session management&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;If you use sticky sessions then it may seem like nothing is needed for managing sessions as you &quot;stick&quot; to one instance and that instance will handle your session just like on a non-loadbalanced site.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;However, if you consider this scenario:&lt;/p&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;You run a webshop with automatic scaling set up &amp;amp; sticky sessions&lt;/li&gt;&#xA;&lt;li&gt;You have a big sale, and the site scales up from 1 to 4 instances&lt;/li&gt;&#xA;&lt;li&gt;A user is assigned to the 4th instance and starts adding things to their basket (which is stored as a session)&lt;/li&gt;&#xA;&lt;li&gt;While that user is browsing traffic lowers, and the automatic scaling scales down to 3 instances&lt;/li&gt;&#xA;&lt;li&gt;The user tries to add a new item to their basket - but the API controller request now hits the load balancer with a sticky session cookie to an instance that has been removed. &lt;/li&gt;&#xA;&lt;li&gt;The load balancer assigns them to a new instance, which has no knowledge of their previous session. Their basket now only contains the item they just added - everything else is gone.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;p&gt;The same thing would happen for auth cookies as they use &lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/introduction?view=aspnetcore-10.0&quot; rel=&quot;noopener noreferrer&quot;&gt;Data Protection&lt;/a&gt; - by default each instance generates its own encryption keys, meaning cookies encrypted on one instance can&#x27;t be decrypted by another. So similarly to the example above, users may need to log in again each time they are moved to a new instance.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Dependent on your site this may not be a big problem, but if you use anything with sessions / auth cookies then it is very bad user experience.&lt;/p&gt;&#xA;&lt;h4&gt;&#xA;  &#xA;  &#xA;  Setting up out of process sessions and data protection&#xA;&lt;/h4&gt;&#xA;&#xA;&lt;p&gt;The solution to both the session and auth cookie problem is to move them out of the individual instances and into a shared store.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This is needed regardless of whether you use sticky sessions or stateless load balancing:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;With &lt;strong&gt;sticky sessions&lt;/strong&gt;, users are normally pinned to one instance - but as shown in the scenario above, scaling events can force them onto a different instance. Without shared sessions and data protection, that means lost session data and forced re-authentication.&lt;/li&gt;&#xA;&lt;li&gt;With &lt;strong&gt;stateless&lt;/strong&gt; load balancing, every single request can land on a different instance, making shared sessions and data protection essential for even basic functionality.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;In this example we&#x27;ll use Redis, but any &lt;code&gt;IDistributedCache&lt;/code&gt; implementation would work.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;You&#x27;ll need the following NuGet packages:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&quot;https://www.nuget.org/packages/Microsoft.Extensions.Caching.StackExchangeRedis&quot; rel=&quot;noopener noreferrer&quot;&gt;Microsoft.Extensions.Caching.StackExchangeRedis&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&quot;https://www.nuget.org/packages/Microsoft.AspNetCore.DataProtection.StackExchangeRedis&quot; rel=&quot;noopener noreferrer&quot;&gt;Microsoft.AspNetCore.DataProtection.StackExchangeRedis&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;There are three things we need to set up:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;1. A shared distributed cache&lt;/strong&gt;&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddStackExchangeRedisCache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Configuration&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redisConnectionString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InstanceName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;my-site-&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;This registers Redis as the &lt;code&gt;IDistributedCache&lt;/code&gt; implementation. By default, ASP.NET Core uses an in-memory implementation which is exactly what causes the problem - each instance has its own cache. By pointing this at a shared Redis instance, all app instances share the same cache.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The &lt;code&gt;InstanceName&lt;/code&gt; is used as a key prefix in Redis, which is useful if you share a Redis instance across multiple applications.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;As a bonus, Umbraco&#x27;s content and media cache is built on Microsoft&#x27;s &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/reference/configuration/cache-settings&quot; rel=&quot;noopener noreferrer&quot;&gt;HybridCache&lt;/a&gt; - which automatically uses any registered &lt;code&gt;IDistributedCache&lt;/code&gt; as a second-level cache. So by registering Redis here, Umbraco will also use it to share its content and media cache across instances.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;2. Session configuration&lt;/strong&gt;&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IdleTimeout&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeSpan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FromMinutes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HttpOnly&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IsEssential&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SecurePolicy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CookieSecurePolicy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Always&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;ASP.NET Core sessions use whatever &lt;code&gt;IDistributedCache&lt;/code&gt; is registered - so because we registered Redis above, sessions are now automatically stored in Redis instead of in-memory.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The cookie settings are worth noting:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;code&gt;HttpOnly&lt;/code&gt; prevents JavaScript from accessing the session cookie&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;code&gt;IsEssential&lt;/code&gt; ensures the cookie is set even if the user hasn&#x27;t consented to non-essential cookies&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;code&gt;SecurePolicy = Always&lt;/code&gt; ensures the cookie is only sent over HTTPS&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;3. Shared Data Protection keys&lt;/strong&gt;&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redisConnection&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ConnectionMultiplexer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;redisConnectionString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddDataProtection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetApplicationName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my-umbraco-site&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;PersistKeysToStackExchangeRedis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;redisConnection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;DataProtection-Keys&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;This is what solves the auth cookie problem. By default, each instance generates its own Data Protection keys - meaning a cookie encrypted on instance 1 can&#x27;t be decrypted by instance 2.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;By persisting the keys to Redis and setting a shared &lt;code&gt;ApplicationName&lt;/code&gt;, all instances use the same encryption keys. The &lt;code&gt;ApplicationName&lt;/code&gt; is important - instances must share the same application name to be able to decrypt each other&#x27;s cookies.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  SignalR&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;This is the final piece of the puzzle, and the only one where the setup actually differs depending on whether you&#x27;re using sticky sessions or stateless.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Umbraco uses &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/load-balancing/signalr-in-backoffice-load-balanced-environment&quot; rel=&quot;noopener noreferrer&quot;&gt;SignalR&lt;/a&gt; in the backoffice for real-time client-to-server communication outside of standard HTTP requests - for example for preview functionality. In a load balanced setup, SignalR needs a way to send messages across all instances, not just the one the user is connected to. This is called a backplane.&lt;/p&gt;&#xA;&#xA;&lt;h4&gt;&#xA;  &#xA;  &#xA;  Sticky sessions&#xA;&lt;/h4&gt;&#xA;&#xA;&lt;p&gt;With sticky sessions, client-side SignalR connections work as normal - the user has a persistent connection to one instance, just like on a single-server site. The only thing needed is a backplane so that server-side messages (like &quot;this content was just published&quot;) can reach all instances.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Redis works well for this:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Requires: Microsoft.AspNetCore.SignalR.StackExchangeRedis&lt;/span&gt;&#xA;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddSignalR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddStackExchangeRedis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;redisConnectionString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h4&gt;&#xA;  &#xA;  &#xA;  Stateless&#xA;&lt;/h4&gt;&#xA;&#xA;&lt;p&gt;With stateless load balancing, each request can land on a different instance. SignalR relies on a persistent connection between client and server - and that connection can&#x27;t just &quot;jump&quot; to a new instance on every request. So a Redis backplane alone isn&#x27;t enough here.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The solution is to use a managed SignalR service like Azure SignalR Service, which handles both the backplane and the client-side connections externally:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Requires: Microsoft.Azure.SignalR&lt;/span&gt;&#xA;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddSignalR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddAzureSignalR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;azureSignalRConnectionString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;This replaces the need for the Redis backplane entirely for SignalR - Azure SignalR Service handles everything. Note that you still need Redis for the distributed cache, sessions, and data protection as set up above.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Wrapping up&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The stateless approach does give a smoother distribution of load across instances, but Azure SignalR Service adds a significant cost on top of the Redis you already need for everything else.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;In most cases I would go with the sticky session setup - the lower cost and the simplicity of having everything managed through a single Redis instance makes it easy to set up and maintain. And once sessions and data protection are out of process, sticky sessions handle instance swaps gracefully anyway.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;That said, I haven&#x27;t done any load testing to compare the two approaches. If they scale differently under real-world traffic, that could easily be the biggest factor in choosing one over the other. This post is really just meant to highlight the differences and walk through the setup - not to declare a winner. Try both if you can, and pick what fits your situation.&lt;/p&gt;]]></description>
                    <pubDate>Thu, 12 Mar 2026 21:06:17 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://dev.to/luukpeters/upgrade-umbraco-13-to-17-property-editors-property-value-converters-22kb</guid>
                    <title>Upgrade Umbraco 13 to 17: Property Editors &#x2B; Property Value Converters</title>
                    <link>https://dev.to/luukpeters/upgrade-umbraco-13-to-17-property-editors-property-value-converters-22kb</link>
                    <description><![CDATA[&lt;p&gt;This is part five in a series about common tasks you&#x27;ll encounter when upgrading Umbraco 13 to 17. In this part, we&#x2019;ll look at updating Property Editors and Property Value Converters.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;When upgrading several packages, one area that caused confusion was Property Editors. In Umbraco 17 there is a much clearer separation between the UI in the backoffice and the data handling and validation on the backend (C#).&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Because of this change, Umbraco introduced migrations that convert existing Data Types (which are essentially instances of a Property Editor) to the new format. In Umbraco 13 a Data Type only referenced a single editor alias, but in Umbraco 17 it contains two: an &lt;strong&gt;editor alias&lt;/strong&gt; (backend) and an &lt;strong&gt;editor UI alias&lt;/strong&gt; (frontend). This makes it possible, for example, to use multiple interchangeable UIs that work with the same underlying data.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Why won&#x27;t my property editor work anymore?&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;After upgrading my database to Umbraco 17 I ran into a couple of issues:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;How does Umbraco know that it should use my newly created Property Editor UI for existing properties?&lt;/li&gt;&#xA;&lt;li&gt;Why does Models Builder suddenly return a &lt;code&gt;JsonDocument&lt;/code&gt; instead of my custom &lt;code&gt;VideoPlayerValueConverterModel&lt;/code&gt;?&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;The answer lies in understanding what the migration from Umbraco 13 to 14&#x2B; actually does and what you need to do with the result. This post walks through that process.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This blog explains how you can update your Property Editors to work in Umbraco 17 without having to create a custom migration. It also helps to read the &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/customizing/property-editors/composition&quot; rel=&quot;noopener noreferrer&quot;&gt;Umbraco documentation on Property Editor composition&lt;/a&gt;. That documentation explains the different pieces that make up a Property Editor in Umbraco 17 and provides useful context for what follows.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The starting point before the migration&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;There are two different starting points for Property Editors in Umbraco 13, and each leads to a slightly different outcome during the migration to Umbraco 14&#x2B;. The difference depends on whether the Property Editor is defined in a &lt;strong&gt;package.manifest&lt;/strong&gt; file or in &lt;strong&gt;C# code&lt;/strong&gt;.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Starting point 1: manifest-only Property Editor&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;In Umbraco 13 a Property Editor can be defined purely in a &lt;code&gt;package.manifest&lt;/code&gt;, for example:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;propertyEditors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;alias&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;proudnerds.videoplayer.editor&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Video player&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;icon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;icon-play&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;group&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Proud Nerds&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;editor&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;view&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;~/App_Plugins/ProudNerds.Umbraco.VideoPlayer/umbraco.videoplayer.html&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;This is enough to create a simple data editor. The value is stored as a string in the database and there is no server-side validation. Anything can be stored as long as it fits into a string.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;If needed, you can still transform that value later using a Property Value Converter before it ends up in the cache.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Starting point 2: Property Editor defined in code&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;You can also &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/13.latest/tutorials/creating-a-property-editor#setting-up-a-property-editor-with-csharp&quot; rel=&quot;noopener noreferrer&quot;&gt;define a Property Editor in C#&lt;/a&gt;, for example:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Umbraco.Cms.Core.PropertyEditors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;YourProjectName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DataEditor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Suggestions editor&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Suggestions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/App_Plugins/Suggestions/suggestion.html&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;Group&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Common&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;Icon&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;icon-list&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Suggestions&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DataEditor&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Suggestions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IDataValueEditorFactory&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataValueEditorFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dataValueEditorFactory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;            &#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Defining a Property Editor in code gives you more control over validation and how the data is stored.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  The resulting database records&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;When you create a Data Type in Umbraco 13 that uses a Property Editor, the resulting database record is almost identical for both approaches. Each Data Type simply stores a property editor alias and configuration in the &lt;code&gt;umbracoDataType&lt;/code&gt; table.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuicwlvzwi8diylzqvd6h.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuicwlvzwi8diylzqvd6h.png&quot; alt=&quot; &quot; width=&quot;631&quot; height=&quot;167&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;If you register the editor in C#, the &lt;code&gt;dbType&lt;/code&gt; may differ, but that detail is not important for this discussion.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The data migration (13 &#x2192; 14&#x2B;)&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The difference between the two approaches becomes visible during migration.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;In one of the later Umbraco 13 versions a &lt;strong&gt;pre-migration&lt;/strong&gt; was introduced that prepares Property Editors for upgrading to Umbraco 14&#x2B;. During this step, a record is written to the &lt;code&gt;umbracoKeyValue&lt;/code&gt; table describing how each Data Type should be migrated.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;For a manifest-only Property Editor, the record looks like this:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;DataTypeId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1055&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;EditorUiAlias&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;proudnerds.videoplayer.editor&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;EditorAlias&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Umbraco.Plain.String&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;However, if the editor was defined in C#, both aliases will be the same:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;DataTypeId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1055&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;EditorUiAlias&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;proudnerds.videoplayer.editor&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;EditorAlias&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;proudnerds.videoplayer.editor&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;After the database upgrade to Umbraco 17, this information is used to populate the new &lt;code&gt;propertyEditorAlias&lt;/code&gt; and &lt;code&gt;propertyEditorUiAlias&lt;/code&gt; columns in the &lt;code&gt;umbracoDataType&lt;/code&gt; table.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;For the video player editor, the result of the migration looks like this:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F58t3d0gffuy81n6oww8m.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F58t3d0gffuy81n6oww8m.png&quot; alt=&quot; &quot; width=&quot;772&quot; height=&quot;148&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Updating the code&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Once you understand what the migration produced in the database, updating the code becomes much clearer.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Creating and registering the Property Editor UI&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;With the new backoffice introduced in Umbraco 14&#x2B;, the UI part of your Property Editor needs to be recreated because AngularJS is no longer supported.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;After creating the UI, you need to register it. I won&#x27;t go into the details of building a Property Editor UI here (the &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/customizing/property-editors/composition/property-editor-ui&quot; rel=&quot;noopener noreferrer&quot;&gt;documentation&lt;/a&gt; covers that), but the aliases you use during registration are important.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Based on the migration result:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;code&gt;alias&lt;/code&gt; should match &lt;strong&gt;PropertyEditorUiAlias&lt;/strong&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;code&gt;propertyEditorSchemaAlias&lt;/code&gt; should match &lt;strong&gt;PropertyEditorAlias&lt;/strong&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;For example:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;manifests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;UmbExtensionManifest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;propertyEditorUi&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;proudnerds.videoplayer.editor&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Proud Nerds video player property editor&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;js&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./proud-nerds-video-property-editor-ui.element&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;na&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Video player&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;        &lt;span class=&quot;na&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;icon-play&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;        &lt;span class=&quot;na&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Proud Nerds&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;        &lt;span class=&quot;na&quot;&gt;propertyEditorSchemaAlias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Umbraco.Plain.Json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;        &lt;span class=&quot;na&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;na&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;                &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Updating the DataEditor (if it already exists)&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;If your editor already had a &lt;code&gt;DataEditor&lt;/code&gt; implementation, you can continue using it, but it needs to be updated for Umbraco 17.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Most of the implementation remains similar to Umbraco 13. The main difference is that several parameters have been removed from the &lt;code&gt;DataEditor&lt;/code&gt; attribute because of the clearer separation between UI and backend logic.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Umbraco 13&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DataEditor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;proudnerds.videoplayer.editor&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Video Player&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/App_Plugins/VideoPlayer/videoplayer.html&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;Group&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Proud Nerds&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;Icon&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;icon-play&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VideoPlayerEditor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DataEditor&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;c1&quot;&gt;// Umbraco 17&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DataEditor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;proudnerds.videoplayer.editor&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VideoPlayerEditor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DataEditor&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Updating the Property Value Converter (if needed)&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;If you used the manifest-only approach in Umbraco 13, there is a good chance your Property Value Converter no longer works.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;During migration, the &lt;code&gt;EditorAlias&lt;/code&gt; for the video editor changed from:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;proudnerds.videoplayer.editor&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;to:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;Umbraco.Plain.Json&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;So if your Property Value Converter checks the editor alias, it will no longer match:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IsConverter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IPublishedPropertyType&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;propertyType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;&lt;span class=&quot;n&quot;&gt;propertyType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EditorAlias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;proudnerds.videoplayer.editor&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;The simplest fix is to check the &lt;strong&gt;EditorUiAlias&lt;/strong&gt; instead:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IsConverter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IPublishedPropertyType&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;propertyType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;&lt;span class=&quot;n&quot;&gt;propertyType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EditorUiAlias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;proudnerds.videoplayer.editor&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;This is not entirely semantically correct, but it is often the easiest solution without introducing additional migrations. After this, your Property Editor will work as expected again and the models builder will use your custom model instead of the generic JsonDocument.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Done&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Once you understand how the Property Editor migration works, it becomes much easier to determine which aliases to use in &lt;code&gt;umbraco-package.json&lt;/code&gt; and what code changes are required after upgrading.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The concepts themselves are straightforward, but the migration can be confusing the first time you encounter it. Hopefully this overview helps clarify what is happening behind the scenes.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  EditorUiAlias or not?&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Earlier I mentioned that checking &lt;code&gt;EditorUiAlias&lt;/code&gt; inside the &lt;code&gt;IsConverter&lt;/code&gt; method of a Property Value Converter is not entirely correct from a semantic point of view.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;A Property Value Converter operates on the data stored in the database and converts that to something else to put in the cache. A Property Editor UI is only the interface used to edit that data. In fact, multiple UIs could theoretically exist for the same underlying editor.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Because of that, checking &lt;code&gt;EditorUiAlias&lt;/code&gt; introduces some risk. If a different UI were introduced for the same editor, your converter might no longer match the correct data. Checking &lt;code&gt;EditorAlias&lt;/code&gt; is the safest way to guarantee you are handling the expected data structure.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;That said, in many real-world scenarios a Property Editor has exactly one UI and one DataEditor that always belong together. If you fully control the implementation, checking &lt;code&gt;EditorUiAlias&lt;/code&gt; can be a pragmatic and perfectly workable solution that avoids writing additional migrations.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Opinions on this tend to differ. Some developers strongly prefer to always check &lt;code&gt;EditorAlias&lt;/code&gt; for correctness, while others consider &lt;code&gt;EditorUiAlias&lt;/code&gt; acceptable when the editor and UI are tightly coupled. In the end, the choice depends on how strictly you want to follow the separation between UI and data.&lt;/p&gt;]]></description>
                    <pubDate>Thu, 12 Mar 2026 13:30:20 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=_RUYI1xNzdE</guid>
                    <title>DevRel Deep Dive: Exploring Umbraco.AI with Matt Brailsford</title>
                    <link>https://www.youtube.com/watch?v=_RUYI1xNzdE</link>
                    <description><![CDATA[This week Sebastiaan and Lotte are joined by Matt Brailsford, Staff Engineer at Umbraco, to show Umbraco.AI in action. Umbraco.AI is Umbraco&#x2019;s free and open source AI foundation and integration add-on for the CMS. It&#x2019;s provider-agnostic, with NuGet packages for OpenAI, Anthropic and more. They also look at the other two main packages that Umbraco HQ has developed: Umbraco.AI.Prompt and Umbraco.AI.Agent. Watch, learn, and then try them for yourself!&#xA;&#xA;&#x1F4D6; Matt&#x2019;s &quot;kitchen sink&quot; getting started blog post: https://mattbrailsford.dev/umbraco-ai-kitchen-sink-install&#xA;&#x1F440; Umbraco.AI source code on GitHub: https://github.com/umbraco/Umbraco.AI&#xA;&#xA;--------&#xA;&#x2753; Looking for help with your Umbraco projects? Visit the Forum&#xA; https://forum.umbraco.com&#xA; &#xA;&#x1F4AC; Want to chat with the friendly Umbraco Community? Join our Discord server&#xA; https://discord.umbraco.com&#xA; &#xA;&#x2709;&#xFE0F; Got a question (or topic suggestion) for the HQ Developer Relations team?&#xA; https://umbra.co/contact-devrel, or the &#x2018;contact-devrel&#x2019; channel on Discord&#xA; &#xA;#Umbraco]]></description>
                    <pubDate>Thu, 12 Mar 2026 10:24:56 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://medium.com/@glenstark883/boost-your-website-with-expert-umbraco-development-services-3ca0c166f387?source=rss------umbraco-5</guid>
                    <title>Boost Your Website with Expert Umbraco Development Services</title>
                    <link>https://medium.com/@glenstark883/boost-your-website-with-expert-umbraco-development-services-3ca0c166f387?source=rss------umbraco-5</link>
                    <description><![CDATA[&lt;div class=&quot;medium-feed-item&quot;&gt;&lt;p class=&quot;medium-feed-image&quot;&gt;&lt;a href=&quot;https://medium.com/@glenstark883/boost-your-website-with-expert-umbraco-development-services-3ca0c166f387?source=rss------umbraco-5&quot;&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1536/1*zGapSohko4R6HMLCG_1Vqw.png&quot; width=&quot;1536&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;medium-feed-snippet&quot;&gt;In today&amp;#x2019;s competitive digital landscape, businesses need websites that are fast, scalable, and easy to manage.&lt;/p&gt;&lt;p class=&quot;medium-feed-link&quot;&gt;&lt;a href=&quot;https://medium.com/@glenstark883/boost-your-website-with-expert-umbraco-development-services-3ca0c166f387?source=rss------umbraco-5&quot;&gt;Continue reading on Medium &#xBB;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;]]></description>
                    <pubDate>Thu, 12 Mar 2026 07:55:23 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=1vCk_13FGsQ</guid>
                    <title>AI in Umbraco: Feature demo</title>
                    <link>https://www.youtube.com/watch?v=1vCk_13FGsQ</link>
                    <description><![CDATA[AI in Umbraco: &#xA;Bolette Kern (CMS Product Manager) and Matt Brailsford (Staff Engineer) provide a deep dive into the rapid evolution of AI in Umbraco following the 2026 Winter Keynote. This update showcases how AI has transitioned from a nested setting to a core, dedicated section of the Umbraco back office, offering better organization and granular permission control for developers and content editors.&#xA;&#xA;The session covers significant functional upgrades to AI prompts and agents, including the ability to generate multiple content variations and the introduction of &quot;Auto Agents&quot; that intelligently select the best tool for your specific request. You will also get an exclusive first look at the upcoming Evaluation and Testing dashboard, designed to help organizations benchmark AI performance, accuracy, and cost.&#xA;&#xA;This video is for Umbraco developers, architects, and content strategists looking to leverage AI within their CMS workflows. Whether you are building custom AI integrations or using HQ packages, these updates provide the foundation for secure, scalable, and context-aware AI implementations.&#xA;&#xA;Video Chapters:&#xA;00:00 Introduction with Bolette Kern and Matt Brailsford&#xA;00:55 The New Dedicated AI Back Office Section&#xA;02:14 Enhanced Prompts: Generating Multiple Options&#xA;03:25 AI Agents vs. Prompts: Key Differences&#xA;04:05 Security: Permissions, Scopes, and User Group Overrides&#xA;05:30 Context Awareness and Location-Based Agents&#xA;06:35 The Auto Agent: Intelligent Prompt Routing&#xA;07:58 Preview: The AI Testing and Evaluation Dashboard&#xA;12:56 Developer Updates: Deploy, Notifications, and Field Validation&#xA;14:37 Future Outlook and Community Hackathons&#xA;&#xA;Key Takeaways:&#xA;- Dedicated AI Workspace: AI now resides in its own back office section, improving discoverability and allowing for specific user permissions independent of the settings section.&#xA;&#xA;- Iterative Content Generation: Prompts can now return up to five different options simultaneously, allowing editors to compare and select the best result.&#xA;&#xA;- Granular Security: The new Scopes system allows administrators to group AI tools and manage access at the user group level for fine-grained control.&#xA;&#xA;- Intelligent Routing: The Auto Agent feature analyzes user intent to automatically trigger the most relevant specialist, such as a Legal Assistant or a Content Creator.&#xA;&#xA;- Quality Assurance: The upcoming Testing section allows for &quot;mock data&quot; evaluations and &quot;graders&quot; to ensure AI responses remain consistent as models evolve.&#xA;&#xA;Resources and Links: &#xA;Umbraco AI Product Page: https://umbraco.com/ai/&#xA;&#xA;Umbraco Winter Keynote (Reference): https://youtu.be/GK-eGhzZYpw&#xA;&#xA;Latest Release Blog Post: https://umbraco.com/blog/the-agent-ready-cms-what-are-agent-skills/&#xA;&#xA;Umbraco Marketplace: https://marketplace.umbraco.com/package/umbraco.ai&#xA;&#xA;Developer Events and Hackathons: https://www.meetup.com/pro/umbraco/]]></description>
                    <pubDate>Thu, 12 Mar 2026 07:16:58 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/modgift.umbraco.imageupload</guid>
                    <title>Modgift.Umbraco.ImageUpload</title>
                    <link>https://marketplace.umbraco.com/package/modgift.umbraco.imageupload</link>
                    <description><![CDATA[Automatically resizes and converts images uploaded to Umbraco CMS 17 media library.]]></description>
                    <pubDate>Thu, 12 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/umbraco-product-update-q1-2026/</guid>
                    <title>Umbraco Product Update - Q1 2026</title>
                    <link>https://umbraco.com/blog/umbraco-product-update-q1-2026/</link>
                    <description><![CDATA[Explore this update featuring the launch of Umbraco Compose, a new AI strategy, enhanced security in Umbraco Cloud, and a new era for Search.]]></description>
                    <pubDate>Thu, 12 Mar 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/march/auto-updating-your-github-readme-with-your-latest-blog-posts/</guid>
                    <title>Auto-Updating Your GitHub README with Your Latest Blog Posts</title>
                    <link>https://owain.codes/blog/2026/march/auto-updating-your-github-readme-with-your-latest-blog-posts/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Tue, 10 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/umbraco-cms-security-advisory-march-10-2026-security-patches-are-now-available/</guid>
                    <title>Umbraco CMS Security Advisory, March 10, 2026</title>
                    <link>https://umbraco.com/blog/umbraco-cms-security-advisory-march-10-2026-security-patches-are-now-available/</link>
                    <description><![CDATA[Security patches are available for Umbraco versions 16 and 17 to fix three moderate-to-high vulnerabilities. Upgrade now to secure your CMS. Projects on Umbraco Cloud will automatically receive the fixes.]]></description>
                    <pubDate>Tue, 10 Mar 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.uschema</guid>
                    <title>Umbraco.Community.uSchema</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.uschema</link>
                    <description><![CDATA[Validates JSON-LD structured data on published Umbraco content pages via a workspace tab in the backoffice.]]></description>
                    <pubDate>Tue, 10 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/backofficethemes</guid>
                    <title>BackofficeThemes</title>
                    <link>https://marketplace.umbraco.com/package/backofficethemes</link>
                    <description><![CDATA[Extra themes for the Umbraco backoffice &#x2014; including Christmas (theme plus snow, lights, tree, Santa hat) and popular editor-style themes: Neon, Cyberpunk, Dracula, Monokai, VS Blue, VS Cool Breeze, and VS Icy Mint.]]></description>
                    <pubDate>Mon, 09 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbraco/116182281314587750</guid>
                    <title>One week left to submit your Umbraco Awards 2026 entry!</title>
                    <link>https://umbracocommunity.social/@umbraco/116182281314587750</link>
                    <description><![CDATA[One week left to submit your Umbraco Awards 2026 entry! &#x1F570;&#xFE0F; No video needed - just the facts. Partners can turn entries into https://umbraco.com case studies for extra exposure. Streamlined form, minimal effort. Deadline: March 13. Submit: https://umbra.co/4l7zW42 #Umbraco]]></description>
                    <pubDate>Fri, 06 Mar 2026 15:32:53 Z</pubDate>
                        <category>social</category>
                        <category>mastodon</category>
                        <category>hq</category>
                </item>
                <item>
                    <guid>https://discord.com/channels/869656431308189746/882981290662580264/1479418096111583373</guid>
                    <title>ValidationAttributes package now under the Umbraco Community GitHub account</title>
                    <link>https://discord.com/channels/869656431308189746/882981290662580264/1479418096111583373</link>
                    <description><![CDATA[With blessings from the original author we have taken the ValidationAttributes package for Umbraco and forked it into a repo under the Umbraco Community GitHub account.&#xA;&#xA;I have released a stable for V17 that can be download now!&#xA;&#xA;https://marketplace.umbraco.com/package/umbraco.community.validationattributes&#xA;&#xA;#umbraco #community]]></description>
                    <pubDate>Fri, 06 Mar 2026 09:59:31 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>discord</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbracospark/116176456661920079</guid>
                    <title>The Umbraco Spark 2026 programme is now live</title>
                    <link>https://umbracocommunity.social/@umbracospark/116176456661920079</link>
                    <description><![CDATA[The Umbraco Spark 2026 programme is now live &#x1F389;Take a look at all the talks and timings for the day and start planning your day!It&#x2019;s going to be a great one &#x2728;&#x1F449; https://umbracospark.com/ #Umbraco #UmbracoSpark #WebCommunity]]></description>
                    <pubDate>Thu, 05 Mar 2026 14:53:09 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://www.nathanielnunes.com/blog/securing-umbraco-images-with-hmac</guid>
                    <title>Securing Umbraco Images with HMAC</title>
                    <link>https://www.nathanielnunes.com/blog/securing-umbraco-images-with-hmac</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Thu, 05 Mar 2026 08:45:58 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://kjac.dev/posts/indexing-media-values-for-documents/</guid>
                    <title>Indexing media values for documents</title>
                    <link>https://kjac.dev/posts/indexing-media-values-for-documents/</link>
                    <description><![CDATA[Leveraging the Umbraco Search extension model to index media ALT texts for their referenced documents.]]></description>
                    <pubDate>Thu, 05 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/how-to-audit-umbraco-content-for-ai-references-aeo-geo-readiness/</guid>
                    <title>How to Audit Umbraco Content for AI References (AEO / GEO Readiness)</title>
                    <link>https://umbraco.com/blog/how-to-audit-umbraco-content-for-ai-references-aeo-geo-readiness/</link>
                    <description><![CDATA[A practical Umbraco guide to AEO/GEO: how to structure content so AI systems can find, extract, and reference the right sections.]]></description>
                    <pubDate>Thu, 05 Mar 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.validationattributes</guid>
                    <title>Umbraco.Community.ValidationAttributes</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.validationattributes</link>
                    <description><![CDATA[[Umbraco v17&#x2B;] Contains validation attributes to decorate your classes, but using Umbraco Dictionary as the resource.]]></description>
                    <pubDate>Thu, 05 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbracospark/116170806922855214</guid>
                    <title>Join Candid Contributions LIVE at Umbraco Spark</title>
                    <link>https://umbracocommunity.social/@umbracospark/116170806922855214</link>
                    <description><![CDATA[&#x1F399;&#xFE0F; LIVE at Umbraco Spark!During lunch time, join us for a live session with Candid Contributions featuring special guests and open, honest conversations from the community.Grab your lunch, bring your thoughts and join the discussion.Details &#x1F449; https://umbracospark.com/ #UmbracoSpark #OpenSource #CandidContributions]]></description>
                    <pubDate>Wed, 04 Mar 2026 12:04:31 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://mattbrailsford.dev/umbraco-ai-kitchen-sink-install</guid>
                    <title>The Umbraco AI Kitchen Sink Install</title>
                    <link>https://mattbrailsford.dev/umbraco-ai-kitchen-sink-install</link>
                    <description><![CDATA[Since we released Umbraco AI, one of the most common bits of feedback I&#x2019;ve heard is: &#x201C;I want to try it, but I&#x2019;m not sure which packages to...]]></description>
                    <pubDate>Wed, 04 Mar 2026 11:19:26 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/af.umbraco.redis.connector</guid>
                    <title>AF.Umbraco.Redis.Connector</title>
                    <link>https://marketplace.umbraco.com/package/af.umbraco.redis.connector</link>
                    <description><![CDATA[Redis connector for Umbraco 15/16/17 (.NET 9/10). Auto-composes StackExchange.Redis distributed cache, persists ASP.NET Core Data Protection keys to Redis (default key: AF.Umbraco.Redis.Connector:_DataProtectionKeys), performs startup fail-fast connectivity validation, and includes optional smoke endpoints.]]></description>
                    <pubDate>Wed, 04 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://joe.gl/ombek/blog/umbracian-bristol-guide/</guid>
                    <title>The Umbracian&#x27;s Guide to Bristol (2026)</title>
                    <link>https://joe.gl/ombek/blog/umbracian-bristol-guide/</link>
                    <description><![CDATA[Are you heading to Umbraco Spark and hoping to explore Bristol while you&#x27;re here? I live near Bristol and now consider myself a Spark veteran, so thought I&#x27;d share my insights!]]></description>
                    <pubDate>Tue, 03 Mar 2026 09:44:22 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://skrift.io/issues/#125</guid>
                    <title>Skrift Issue #125</title>
                    <link>https://skrift.io/issues/#125</link>
                    <description><![CDATA[Featuring guest posts by Nathaniel Grantham-Knight on &quot;Building An Umbraco Property Editor With Vite&quot; and Tim Payne on &quot;Web Development and Ultrarunning Have More in Common Than You Might Think&quot;]]></description>
                    <pubDate>Tue, 03 Mar 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                        <category>skrift</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbraco/116164694359696472</guid>
                    <title>Umbraco MVP nominations deadline near</title>
                    <link>https://umbracocommunity.social/@umbraco/116164694359696472</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Tue, 03 Mar 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/the-agent-ready-cms-what-are-agent-skills/</guid>
                    <title>The Agent-Ready CMS: What are Agent Skills?</title>
                    <link>https://umbraco.com/blog/the-agent-ready-cms-what-are-agent-skills/</link>
                    <description><![CDATA[Discover how Agent Skills and MCP are transforming Umbraco into an Agent-Ready CMS. Learn to power intelligent actions and future-proof your agency&#x27;s workflow.]]></description>
                    <pubDate>Tue, 03 Mar 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://github.com/skybrud/Skybrud.Umbraco.Redirects/releases/tag/v17.0.3</guid>
                    <title>Skybrud.Umbraco.Redirects 17.0.3</title>
                    <link>https://github.com/skybrud/Skybrud.Umbraco.Redirects/releases/tag/v17.0.3</link>
                    <description><![CDATA[Award winning redirects manager for Umbraco.]]></description>
                    <pubDate>Mon, 02 Mar 2026 23:13:30 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbraco/116159361781744592</guid>
                    <title>Umbraco Codegarden 2026 program is live</title>
                    <link>https://umbracocommunity.social/@umbraco/116159361781744592</link>
                    <description><![CDATA[&#x201C;Should we just&#x2026; put the program live?&#x201D;&#x201C;Yes.&#x201D;&#x201C;Like&#x2026; now?&#x201D;&#x201C;Yes.&#x201D;&#x201C;Should our CEO hold a sign?&#x201D;&#x201C;Obviously.&#x201D;So here we are.Codegarden 2026 program = LIVE &#x1FAA7;&#x1F499;Two full days.45&#x2B; sessions.60&#x2B; speakers.3 podcasts.4 workshops. Tech and business - all in one place.We&#x2019;ll be there. Will you?Explore the full program and secure your spot &#x1F447;https://codegarden.umbraco.com/program/ #Umbraco]]></description>
                    <pubDate>Mon, 02 Mar 2026 13:07:15 Z</pubDate>
                        <category>mastodon</category>
                        <category>social</category>
                        <category>hq</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/koola.parentdropdown</guid>
                    <title>Koola.ParentDropDown</title>
                    <link>https://marketplace.umbraco.com/package/koola.parentdropdown</link>
                    <description><![CDATA[Umbraco 17 property editor that resolves options from a parent-defined root picker and supports checkbox, radio, and dropdown selection modes.]]></description>
                    <pubDate>Sat, 28 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://joe.gl/ombek/blog/act/</guid>
                    <title>Running GitHub Actions .NET and Azure workflows locally with Act</title>
                    <link>https://joe.gl/ombek/blog/act/</link>
                    <description><![CDATA[Act is a fantastic tool for testing GitHub actions locally instead of pushing that 10th commit in a row called Testing GitHub Actions (again) but configuring it to work correctly can be a balancing act, so here are some tips for getting Act working with your .NET CI/CD flows.]]></description>
                    <pubDate>Fri, 27 Feb 2026 11:29:14 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://jcdc.dev/blog/introducing-new-package-documentation</guid>
                    <title>Introducing docs.jcdc.dev</title>
                    <link>https://jcdc.dev/blog/introducing-new-package-documentation</link>
                    <description><![CDATA[Explore the new documentation website for all jcdcdev Umbraco packages. Built with Astro and Starlight for high performance and low carbon impact, featuring automated synchronisation across GitHub and the Umbraco Content Delivery API.]]></description>
                    <pubDate>Fri, 27 Feb 2026 11:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://dev.to/kevinjump/battle-scarred-developers-guide-to-umbraco-v17-workspaces-l63</guid>
                    <title>Battle scarred developer&#x27;s guide to Umbraco v17 -Workspaces</title>
                    <link>https://dev.to/kevinjump/battle-scarred-developers-guide-to-umbraco-v17-workspaces-l63</link>
                    <description><![CDATA[&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;em&gt;All the code for this series of posts is available in the &lt;a href=&quot;https://github.com/KevinJump/DoStuffWithUmbraco/tree/v17/main&quot; rel=&quot;noopener noreferrer&quot;&gt;DoStuffWithUmbraco Repository on GitHub&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;p&gt;In the last article we got to the point where we had our own custom section, with a side menu (or &quot;sidebarApp&quot;) and a basic menu item. &lt;br&gt;&#xA;but for now clicking on that menu item just shows us some loading dots &#x1F61E;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiupotg4rkjyddxm8vv07.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiupotg4rkjyddxm8vv07.png&quot; alt=&quot;Empty section&quot; width=&quot;800&quot; height=&quot;524&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;What we need to do know is define a workspace. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;So what are workspaces ? well to lift the &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/customizing/workspaces&quot; rel=&quot;noopener noreferrer&quot;&gt;description directly from the umbraco docs&lt;/a&gt; : &lt;/p&gt;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;em&gt;Workspaces provide dedicated editing environments for specific entity types in Umbraco. They create isolated areas where users can edit content, media, members, or other entities with specialized interfaces and functionality.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;p&gt;basically menu items are assigned an &#x27;entity type&#x27; and when you click on them Umbraco looks for the workspace that renders that entity type. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;entity types are really just Identifiers at this point, usually you might have in two entity types a &#x27;root&#x27; and and &#x27;item&#x27; - the root is as you might expect the one at the root, and the item is an item in your tree (if you have one.&lt;/p&gt;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Item workspace&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;For our &quot;simple&quot; time item, we only have a single &quot;do-stuff-time-item&quot; entity type, and that&#x27;s the one we need to build a workspace for to show information to the user. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;Workspaces at their most basic have two things, a workspace context and a workspace element. &lt;/p&gt;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Workspace Context&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Your workspace context is the code that controls the state and data for your workspace. here you have all your data and ways to fetch and save it. &lt;/p&gt;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;em&gt;To be clear, you don&#x27;t need to do this in a context, you can just fetch , store and manipulate data in the element, but as you will see in a bit, that is probably going to lead to duplication and a more complex bunch of code&lt;/em&gt;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;p&gt;So without being to complicated a workspace will look something like this:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MySampleWorkspaceContext&lt;/span&gt; &#xA;  &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UmbEditableWorkspaceContextBase&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TimeSettings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&#xA;  &lt;span class=&quot;k&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UmbSubmittableWorkspaceContext&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;  &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;settingsRepository&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DoStuffTimeSettingsRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;  &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;unique&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Observable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;workspaceAlias&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DOSTUFF_WORKSPACE_ALIAS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;  &lt;span class=&quot;nf&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UmbControllerHost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DOSTUFF_WORKSPACE_ALIAS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;provideContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;DOSTUFF_WORKSPACE_CONTEXT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;  &lt;span class=&quot;nf&quot;&gt;getUnique&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;  &lt;span class=&quot;nf&quot;&gt;getData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;timeSettings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;  &lt;span class=&quot;nf&quot;&gt;getEntityType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DOSTUFF_TIME_ITEM_ALIAS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;  &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;settings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;timeSettings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;settingsRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;saveTimeSettings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Workspaces can even be simpler than this, but here we are implementing a &lt;code&gt;UmbSubmittableWorkspaceContext&lt;/code&gt; because we want to be able to save things that we update on our context, if you don&#x27;t want to tie into other things like workspace actions, you don&#x27;t need to do this, but its a relatively simple implementation, so in my opinion it&#x27;s worth it. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;There are few things we are going to pick out in the context : &lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  ProvideContext&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;You can see that inside the constructor for the context we are calling &lt;code&gt;this.provideContext&lt;/code&gt; . this tells the rest of the app, that we are responsible for the &lt;code&gt;DOSTUFF_WORKSPACE_CONTEXT&lt;/code&gt; so if anything wants to interact with this context they can. by asking for it in their own constructor. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;For example - a view might ask for the context like this.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;consumeContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;DOSTUFF_WORKSPACE_CONTEXT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;  &lt;span class=&quot;c1&quot;&gt;// do stuff with the context here.&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Workspace contexts have a scope, they will only exist while you are in the workspace, you can&#x27;t call a workspace context from somewhere else or another section - if you need to do that you might need a global context, which work in a similar way they are just defined slightly differently&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Repositories&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Another thing you might have noticed about this context is we randomly just call save in a &lt;code&gt;#settingsRepository&lt;/code&gt; and we&#x27;ve haven&#x27;t told you what one of them is yet - we will get to them in a bit. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;But for now, that&#x27;s just the place where the actual calls to API end points and the like are stored - it means our context doesn&#x27;t need to know the inner workings of the API it can just say go get this or save that.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Views&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;So now we have registered our workspace and we have a workspace context, you will notice, we still have nothing to show to our user! So now its time to fix that, and present them with something. You define what things show in a workspace via &lt;code&gt;workspaceView&lt;/code&gt; elements. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;again we define these in a manifest.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;   &lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;workspaceView&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;nx&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff.DefaultWorkspaceView&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff Default Workspace View&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;nx&quot;&gt;js&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./default-workspace-view.element.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&#xA;    &lt;span class=&quot;nx&quot;&gt;weight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;nx&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;      &lt;span class=&quot;nl&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;#doStuff_defaultWorkspaceViewName&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;      &lt;span class=&quot;nx&quot;&gt;pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;      &lt;span class=&quot;nx&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;icon-alarm-clock&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;    &lt;span class=&quot;nx&quot;&gt;conditions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Umb.Condition.WorkspaceAlias&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;        &lt;span class=&quot;na&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DOSTUFF_WORKSPACE_ALIAS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;So the things to note : &lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;the &lt;code&gt;js&lt;/code&gt; entry points the file that will render the element&lt;/li&gt;&#xA;&lt;li&gt;the &lt;code&gt;meta&lt;/code&gt; data defines the name and icon for the view&lt;/li&gt;&#xA;&lt;li&gt;the &lt;code&gt;conditions&lt;/code&gt; make sure our view only shows up on our workspace.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  View element&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;The view element is a &lt;code&gt;UmbLitElement&lt;/code&gt; that renders what you want to show the user&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;customElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;do-stuff-default-workspace-view-element&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DoStuffDefaultWorkspaceViewElement&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UmbLitElement&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;&#xA;  &lt;span class=&quot;nx&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&amp;lt;umb-body-layout&amp;gt;&#xA;      &amp;lt;div class=&quot;layout&quot;&amp;gt;&#xA;        &amp;lt;uui-box&#xA;          .headline=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;localize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;doStuff_defaultWorkspaceTitle&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&#xA;        &amp;gt;&#xA;          &amp;lt;h1&amp;gt;Hello Time&amp;lt;/h1&amp;gt;&#xA;        &amp;lt;/uui-box&amp;gt;&#xA;      &amp;lt;/div&amp;gt;&#xA;    &amp;lt;/umb-body-layout&amp;gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;With this in place we get something to show the user ! &lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqp9kqy3c3n5xulhq78jc.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqp9kqy3c3n5xulhq78jc.png&quot; alt=&quot;Single workspace view&quot; width=&quot;800&quot; height=&quot;547&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Multiple views, and icons.&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;So we defined that icon, and name, but it&#x27;s not anywhere on the screen, what&#x27;s up with that?.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Well the icon and name are used when we have multiple views in a workspace. so if we add another &lt;code&gt;workspaceView&lt;/code&gt; manifest to the workspace&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;  &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;workspaceView&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;nx&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff.SettingsWorkspaceView&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff Settings Workspace View&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;nx&quot;&gt;js&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./settings-workspace-view.element.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&#xA;  &lt;span class=&quot;nx&quot;&gt;weight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;nx&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;nl&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;#doStuff_settingsWorkspaceViewName&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;nx&quot;&gt;pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;nx&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;icon-settings&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;  &lt;span class=&quot;nx&quot;&gt;conditions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;      &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Umb.Condition.WorkspaceAlias&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;      &lt;span class=&quot;na&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DOSTUFF_WORKSPACE_ALIAS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;We get our &#x27;tabs&#x27;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnwn8csctdp2dsckkj7b.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnwn8csctdp2dsckkj7b.png&quot; alt=&quot;Tabs&quot; width=&quot;800&quot; height=&quot;166&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Summarry&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;This gets us the skeleton of our workspace up and showing something to the user - there is much more to workspaces , and we will go into them in some later posts, but for now, we have a section, a menu and some workspaces. so &#x1F389;&lt;/p&gt;]]></description>
                    <pubDate>Fri, 27 Feb 2026 09:50:36 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/february/how-i-used-umbracoai-for-free/</guid>
                    <title>How I used Umbraco.AI for free</title>
                    <link>https://owain.codes/blog/2026/february/how-i-used-umbracoai-for-free/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 27 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/february/how-i-used-umbracoai-for-free/</guid>
                    <title>How I used Umbraco.AI for free</title>
                    <link>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/february/how-i-used-umbracoai-for-free/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 27 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://dev.to/d_inventor/umbraco-testing-examples-now-also-for-umbraco-17-3d5k</guid>
                    <title>Umbraco testing examples now also for Umbraco 17</title>
                    <link>https://dev.to/d_inventor/umbraco-testing-examples-now-also-for-umbraco-17-3d5k</link>
                    <description><![CDATA[&lt;p&gt;I updated my testing examples repository to the latest Umbraco version.&lt;/p&gt;&#xA;&#xA;&#xA;&lt;div class=&quot;ltag-github-readme-tag&quot;&gt;&#xA;  &lt;div class=&quot;readme-overview&quot;&gt;&#xA;    &lt;h2&gt;&#xA;      &lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg&quot; alt=&quot;GitHub logo&quot;&gt;&#xA;      &lt;a href=&quot;https://github.com/D-Inventor&quot; rel=&quot;noopener noreferrer&quot;&gt;&#xA;        D-Inventor&#xA;      &lt;/a&gt; / &lt;a href=&quot;https://github.com/D-Inventor/automated-testing-in-umbraco&quot; rel=&quot;noopener noreferrer&quot;&gt;&#xA;        automated-testing-in-umbraco&#xA;      &lt;/a&gt;&#xA;    &lt;/h2&gt;&#xA;    &lt;h3&gt;&#xA;      A working example of integration- and unittests with Umbraco. A demonstration of various concepts for testing your Umbraco website&#xA;    &lt;/h3&gt;&#xA;  &lt;/div&gt;&#xA;  &lt;div class=&quot;ltag-github-body&quot;&gt;&#xA;    &#xA;&lt;div id=&quot;readme&quot; class=&quot;md&quot;&gt;&#xA;&lt;div class=&quot;markdown-heading&quot;&gt;&#xA;&lt;h1 class=&quot;heading-element&quot;&gt;Umbraco 17 automated testing setup&lt;/h1&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;This project is a fully functioning setup for automated testing with Umbraco 17. You can use this project as a reference or starting point to get started with testing on your Umbraco website. The tests are set up with Test Driven Development (TDD) in mind.&lt;/p&gt;&#xA;&lt;div class=&quot;markdown-heading&quot;&gt;&#xA;&lt;h2 class=&quot;heading-element&quot;&gt;Tools&lt;/h2&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;The most important tools that are used in the automated tests are as follows:&lt;/p&gt;&#xA;&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Name&lt;/th&gt;&#xA;&lt;th&gt;Description&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;a href=&quot;https://xunit.net/?tabs=cs&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;xUnit v3&lt;/a&gt;&lt;/td&gt;&#xA;&lt;td&gt;The testing framework. You can use any testing framework that you like though&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;a href=&quot;https://nsubstitute.github.io/&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;NSubstitute&lt;/a&gt;&lt;/td&gt;&#xA;&lt;td&gt;Library for mocking. Any mocking library will work. This project doesn&#x27;t do extensive mocking, but for example &lt;code&gt;IPublishedValueFallback&lt;/code&gt; is a mandatory parameter for any published content item, even if you don&#x27;t actually use it. It&#x27;s just convenient to insert a mock.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;a href=&quot;https://testcontainers.com/&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Test Containers&lt;/a&gt;&lt;/td&gt;&#xA;&lt;td&gt;Automatically creates docker containers while running tests. It is used to create an empty SQL Server database that is automatically cleaned up after testing.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&lt;/div&gt;&#x2026;&lt;/div&gt;&#xA;  &lt;/div&gt;&#xA;  &lt;div class=&quot;gh-btn-container&quot;&gt;&lt;a class=&quot;gh-btn&quot; href=&quot;https://github.com/D-Inventor/automated-testing-in-umbraco&quot; rel=&quot;noopener noreferrer&quot;&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&lt;p&gt;Though not much has changed, here are the most notable differences compared to the Umbraco 16 version&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Database initialization&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The &lt;code&gt;SqlServerDatabase&lt;/code&gt; resource no longer creates a second database inside the SqlServer test container. While Umbraco 16 would happily create a new database on boot if it didn&#x27;t exist yet, Umbraco 17 does not and will throw connection errors.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;For your regular use of Umbraco, this change makes no significant difference. If you also use EF Core, you may need to pay some extra attention here!&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  A base URL for integration tests&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The &lt;code&gt;WebsiteFixture&lt;/code&gt; will now set a fixed base URL when creating a backoffice httpclient. If you need to use a different domain, this base URL can be adapted, but what is important is that the URL uses &lt;strong&gt;https&lt;/strong&gt; protocol. Compared to Umbraco 16, Umbraco 17 requires https to backoffice endpoints by default and requests using http are rejected by default. That&#x27;s at least what the error would indicate.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;If you want to see all the changes, you can check out this commit:&lt;br&gt;&#xA;&lt;a href=&quot;https://github.com/D-Inventor/automated-testing-in-umbraco/commit/573ef96a155c390ba3d4383bf555f9ff5723b3b4&quot; rel=&quot;noopener noreferrer&quot;&gt;https://github.com/D-Inventor/automated-testing-in-umbraco/commit/573ef96a155c390ba3d4383bf555f9ff5723b3b4&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  An additional note&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;I have given some attention to the example website under test in this repository. The homepage at least has a slightly more fancy template, but it&#x27;s all static content. I haven&#x27;t yet taken the time to really tie it all together, and I wanted to do so using Test Driven Development, which is the main focus of this example repository.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;I noticed that the version of playwright for C# doesn&#x27;t actually let you compare screenshots!? This was a mild surprise and disappointment, because that means I can&#x27;t actually use snapshot testing to ensure my template doesn&#x27;t accidentally change when I implement the logic. The Javascript version of playwright does seem to support it, so I guess for better end-to-end testing, we&#x27;d need to create an equivalent management API client and scenario builder. Oof!&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  That&#x27;s all&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;that&#x27;s all I wanted to share! Hope you check out the repository, give it a star and let me know if the testing examples have been helpful to you or not! Thank you for reading &#x1F60A;&lt;/p&gt;]]></description>
                    <pubDate>Wed, 25 Feb 2026 17:48:29 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://dev.to/kevinjump/battle-scarred-developers-guide-to-umbraco-v17-sections-5ha2</guid>
                    <title>Battle scarred developer&#x27;s guide to Umbraco v17 - Sections</title>
                    <link>https://dev.to/kevinjump/battle-scarred-developers-guide-to-umbraco-v17-sections-5ha2</link>
                    <description><![CDATA[&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;em&gt;So now, we are getting into the code! as with all the bits in this series all the code is available on the &lt;a href=&quot;https://github.com/KevinJump/DoStuffWithUmbraco/blob/v17/main&quot; rel=&quot;noopener noreferrer&quot;&gt;DoStuffWithUmbraco repo&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  1. Sections&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;&lt;em&gt;(see &lt;a href=&quot;https://github.com/KevinJump/DoStuffWithUmbraco/tree/v17/main/src/DoStuff.Client/DoStuff-Client/src/section&quot; rel=&quot;noopener noreferrer&quot;&gt;DoStuffWithUmbracoRepo : Sections&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;A section in umbraco is something accessed from the top bar navigation menu. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2suol9gjit4yqc3g7hqo.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2suol9gjit4yqc3g7hqo.png&quot; alt=&quot;Umbraco top navigation&quot; width=&quot;800&quot; height=&quot;55&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Its quite simple to add a new section - all you need is the manifest.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sectionManifest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UmbExtensionManifest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;section&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DOSTUFF_SECTION_ALIAS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff Section&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;weight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;#doStuff_sectionName&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;do-stuff&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;Constants&lt;/strong&gt;&lt;br&gt;&#xA;&lt;em&gt;Here we have used a constant for the alias, because its often true you will need to reference the section alias in other places on your site.&lt;/em&gt; &lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;em&gt;The alias is defined in another file.&lt;/em&gt;&lt;/p&gt;&#xA;&#xA;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DOSTUFF_SECTION_ALIAS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff.Section&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&#xA;&lt;p&gt;&lt;em&gt;and this replaces the string value in the manifest.&lt;/em&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Localization&lt;/strong&gt;&lt;br&gt;&#xA;&lt;em&gt;You might also notice that the &lt;code&gt;label&lt;/code&gt; value starts with a &#x27;#&#x27;, this tells umbraco that we want to use a localize value for the label. we will cover them a bit later, but for now just to so you know you can just put a string in for the label value if you want&lt;/em&gt;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  2. Dashboard&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;&lt;em&gt;(see &lt;a href=&quot;https://github.com/KevinJump/DoStuffWithUmbraco/tree/v17/main/src/DoStuff.Client/DoStuff-Client/src/dashboard&quot; rel=&quot;noopener noreferrer&quot;&gt;DoStuffWithUmbraco repo : Dashboards&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;At this point your section is quite empty, but you can add a dashboard quite easily to get some content in there. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;Dashboards are pages that sit at the top level of a section, almost all the sections in umbraco already have dashboards (Content has news, and redirect, settings has, examine, health checks and profiling to name a few).&lt;/p&gt;&#xA;&#xA;&lt;p&gt;you can add your own dashboard to your own sections or existing sections as you choose.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dashboardManifest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UmbExtensionManifest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;dashboard&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff.Dashboard&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff Dashboard&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;js&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./dashboard.element.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;#DoStuff_DashboardName&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;do-stuff-dashboard&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;conditions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;      &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Umb.Condition.SectionAlias&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;      &lt;span class=&quot;na&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DOSTUFF_SECTION_ALIAS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Here we define the alias and element we want to use for our dashboard, and the &lt;code&gt;condition&lt;/code&gt; determines where it lives.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;there are all sorts of conditions in umbraco, but here we are saying if the section alias is that of our custom section then we are happy. &lt;strong&gt;If we didn&#x27;t have a condition the dashboard would appear in all sections&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;em&gt;Again note the use of a constant for the section alias&lt;/em&gt;_&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;p&gt;Dashboards are WebComponents, they are probibly the simplest ones in umbraco you don&#x27;t have to inherit anything (if you don&#x27;t want to) - there are no contexts, or stores or tree&#x27;s required, you element can just render some HTML.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;customElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;do-stuff-dashboard-element&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DoStuffDashboardElement&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UmbLitElement&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;  &lt;span class=&quot;nx&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&amp;lt;umb-body-layout&#xA;      .headline=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;localize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;doStuff_dashboardTitle&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&#xA;    &amp;gt;&#xA;      &amp;lt;uui-box&amp;gt;&#xA;        &amp;lt;umb-localize key=&quot;doStuff_dashboardIntro&quot;&amp;gt;&amp;lt;/umb-localize&amp;gt;&#xA;      &amp;lt;/uui-box&amp;gt;&#xA;    &amp;lt;/umb-body-layout&amp;gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DoStuffDashboardElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;em&gt;Note&lt;/em&gt; : We do inherit from UmbLitElement as opposed to LitElement, this gives you access to the localization helpers amongst other things, so it&#x27;s worth doing, even though you don&#x27;t have to.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljvyc4cfr40ef26i2uip.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljvyc4cfr40ef26i2uip.png&quot; alt=&quot;DoStuff Dashboard.&quot; width=&quot;680&quot; height=&quot;274&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  3. Sidebar App.&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;You have probibly notices that almost all existing sections in umbraco have some form of menu or tree down the left hand side. In Umbraco speak this is a &quot;SidebarApp&quot; and it can contain almost anything! - but usually its menu items and trees. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;A sidebar is registered in a manifest file.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sidebarManifest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UmbExtensionManifest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sectionSidebarApp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;menu&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff.SectionSidebarApp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff Section Sidebar App&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;#doStuff_sidebarStaticAppName&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;menu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff.Static.Menu&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;conditions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;      &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Umb.Condition.SectionAlias&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;      &lt;span class=&quot;na&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DOSTUFF_SECTION_ALIAS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;On its own a sidebar app is quite empty. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfe8xed7udau3menu0uo.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfe8xed7udau3menu0uo.png&quot; alt=&quot;Empty sidebar&quot; width=&quot;800&quot; height=&quot;562&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;So we need to add some menus and items.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  4. Menus&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Within a standard sidebar you can have a number of &#x27;menus&#x27; these are the sections you see in the settings section, &quot;Structure&quot;, &quot;Templating&quot; and &quot;Advanced&quot; are Menus&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhfm92ljoqovw88oqqnsq.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhfm92ljoqovw88oqqnsq.png&quot; alt=&quot;Umbraco settings section&quot; width=&quot;800&quot; height=&quot;562&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;to add your own, we have a manifest.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;menuManifest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UmbExtensionManifest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;menu&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff.Static.Menu&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff Static Menu&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;but with out any menu items you won&#x27;t see much , so lets add a menu item.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;timeItemManifest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UmbExtensionManifest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;menuItem&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff.TimeItem&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff Time Item&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;weight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;na&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;#doStuff_timeItemName&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;icon-time&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;entityType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DOSTUFF_TIME_ITEM_ALIAS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;menus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff.Static.Menu&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;You can see how we assign the menu item to the menu, and the menu is actually assigned in the section definition. &lt;/p&gt;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;em&gt;Don&#x27;t worry to much about the &lt;code&gt;entityType&lt;/code&gt; just yet, its going to get funky when we talk about workspaces. but for now lets just bask in the menu glory.&lt;/em&gt; &lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Freh0g9n1v5h16lxr3yoi.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Freh0g9n1v5h16lxr3yoi.png&quot; alt=&quot;Custom section, dashboard, and menu item&quot; width=&quot;800&quot; height=&quot;562&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;em&gt;All the client code in this article is available in the &lt;a href=&quot;https://github.com/KevinJump/DoStuffWithUmbraco/tree/v17/main/src/DoStuff.Client/DoStuff-Client/src&quot; rel=&quot;noopener noreferrer&quot;&gt;DoStuffWithUmbraco Client repo&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;]]></description>
                    <pubDate>Wed, 25 Feb 2026 17:21:17 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://dev.to/kevinjump/battle-scarred-developers-guide-to-umbraco-v17-entry-points-2ke4</guid>
                    <title>Battle scarred developer&#x27;s guide to Umbraco v17 - Entry Points</title>
                    <link>https://dev.to/kevinjump/battle-scarred-developers-guide-to-umbraco-v17-entry-points-2ke4</link>
                    <description><![CDATA[&lt;p&gt;So now that bundles have replaced &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-types/backoffice-entry-point&quot; rel=&quot;noopener noreferrer&quot;&gt;entry points&lt;/a&gt; as the place to integrate your Umbraco extension, do we still need entry points?&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Yes, i most cases you will still need an entry point, to initialize things like the authentication for your client to talk to the server. or if you are feeling really mischievous to unload other entries from the umbraco registry ! &lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Register your entry point via a manifest.&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;&lt;em&gt;all the extension template will do this one for you, but to show the process&lt;/em&gt;&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;manifests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;UmbExtensionManifest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Do Stuff Client Entrypoint&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DoStuff.Client.Entrypoint&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;backofficeEntryPoint&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;js&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./entrypoint.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;this is then imported and registered via your &lt;a href=&quot;https://github.com/KevinJump/DoStuffWithUmbraco/blob/v17/main/src/DoStuff.Client/DoStuff-Client/src/bundle.manifests.ts&quot; rel=&quot;noopener noreferrer&quot;&gt;bundle.manifest.ts&lt;/a&gt; file. &lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Auth.&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The examples that you get with the templates contain most of the code you will need here for authentication.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt; &lt;span class=&quot;nx&quot;&gt;_host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;consumeContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;UMB_AUTH_CONTEXT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;authContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;// Get the token info from Umbraco&lt;/span&gt;&#xA;    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;authContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getOpenApiConfiguration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&#xA;      &lt;span class=&quot;na&quot;&gt;auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;      &lt;span class=&quot;na&quot;&gt;baseUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;      &lt;span class=&quot;na&quot;&gt;credentials&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;credentials&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;same-origin&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;As we&#x27;ve said in another post we like to add a bit - which keeps the token fresh for each request.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;    &lt;span class=&quot;c1&quot;&gt;// client interceptor will get the latest token for the auth&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;// context for a request, so if the token has been refreshed&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;// since we first got it, we&#x27;ll still have a valid token.&lt;/span&gt;&#xA;    &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;interceptors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;authContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getLatestToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;      &lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Authorization&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`Bearer &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;em&gt;honesty - i am not 100% sure this extra bit is in fact needed - it&#x27;s something we might revisit.&lt;/em&gt;&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Unregistering things!&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;So your &lt;code&gt;onInit&lt;/code&gt; method runs when your extension is loaded, and you can if you want start to manipulate Umbraco&#x27;s register, you could for example remove the welcome dashboard this way.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;extensionRegistry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;unregister&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Umb.Dashboard.UmbracoNews&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Be carefull! removing things from the register might well make bits of the umbraco backoffice unstable. &lt;/p&gt;&#xA;&lt;/blockquote&gt;]]></description>
                    <pubDate>Wed, 25 Feb 2026 17:21:02 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://dev.to/kevinjump/battle-scarred-developers-guide-to-umbraco-v17-bundles-100g</guid>
                    <title>Battle scarred developer&#x27;s guide to Umbraco v17 - Bundles</title>
                    <link>https://dev.to/kevinjump/battle-scarred-developers-guide-to-umbraco-v17-bundles-100g</link>
                    <description><![CDATA[&lt;p&gt;With the Early adopters guide we talked about Entry points as the start of your front end code journey, but now with a few tweaks since v14 bundles are where it&#x27;s at. &lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  What&#x27;s a bundle.&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;A &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-types/bundle&quot; rel=&quot;noopener noreferrer&quot;&gt;bundle&lt;/a&gt; is an extension point in Umbraco&#x27;s Backoffice that lets you load JavaScript files and register manifests inside Umbraco&#x27;s system so your code is loaded as part of the Backoffice. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;Put simply it&#x27;s the loader of your extension.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;typically your entry point javascript file will only import manifest from around your project and return them for umbraco to ingest.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;manifests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;UmbExtensionManifest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;entrypoints&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sectionManifests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dashboardManifests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;localizationManifests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;menuManifests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;workspaceManifests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;editorManifests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;modalManifests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;As your project grows so will this list, to keep it simple and organised i would recommend that at each level you have manifest that might also import from child folders, before finally having everything brought into the bundle file. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;For example in the &lt;a href=&quot;https://github.com/KevinJump/DoStuffWithUmbraco/tree/v17/main/src/DoStuff.Client/DoStuff-Client&quot; rel=&quot;noopener noreferrer&quot;&gt;DoStuffWithUmbraco&lt;/a&gt; repository. we might have a /workspaces/views/manfiest.ts file, that is then imported into the /workspace/manifest.ts file which is the one we import into our bundle file.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;&#x2B;-- src&#xA;  - bundle.manifest.ts&#xA;  &#x2B;-- workspaces&#xA;    - manifest.ts&#xA;    &#x2B;-- views&#xA;      - manifest.ts  &#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;This means everything needed for the workspace is in /workspace/manifest.ts and we can if need be move it about knowing it&#x27;s all there. It also means any one manifest definition file doesn&#x27;t contain two much information.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  What about manifests in umbraco-package.json&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;There is &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-registry/register-extensions#umbraco-package.json&quot; rel=&quot;noopener noreferrer&quot;&gt;quite a bit in the umbraco docs&lt;/a&gt; about how you can define your manifests inside the &lt;code&gt;umbraco-package.json&lt;/code&gt; file, and you can, but once you go beyond something very very basic (e.g. not just adding localization). you will want to do it via a bundle. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;Adding all the manifests via the bundle gives you better typescript &amp;amp; checking support in your project, its neater and it catches the errors quicker. &lt;/p&gt;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Adding via the umbraco-package.json also requires that the site be restarted for the packages to be loaded (these files are read in by the Backoffice code on start-up). using a bundle as the entry point you can add new things build the scripts and it all appears. &lt;/p&gt;&#xA;&lt;/blockquote&gt;]]></description>
                    <pubDate>Wed, 25 Feb 2026 17:20:52 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://dev.to/kevinjump/battle-scarred-developers-guide-to-umbraco-v17-setup-2998</guid>
                    <title>Battle scarred developer&#x27;s guide to Umbraco v17 - Setup</title>
                    <link>https://dev.to/kevinjump/battle-scarred-developers-guide-to-umbraco-v17-setup-2998</link>
                    <description><![CDATA[&lt;p&gt;In our previous post we&#x27;ve gotten our basic structure for our umbraco extension, but before we dive into code. there are a couple things i like to tweak.&lt;/p&gt;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;em&gt;You can choose to ignore this post!, these are my personal preferences for some of the more obscure bits of the setup, they are not required but they can make things a bit easier later on.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  PackageManifestReader vs umbraco-package.json&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  umbraco-package.json&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;When you create a new umbraco extension you will get a &lt;code&gt;umbraco-package.json&lt;/code&gt; file created in your &lt;code&gt;client/public&lt;/code&gt; folder. &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/customizing/umbraco-package&quot; rel=&quot;noopener noreferrer&quot;&gt;this file defines the entry point for Umbraco to fetch and initialize your package&lt;/a&gt;&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;MySuperPackage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;MySuperPackage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;allowTelemetry&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;extensions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;My Super Package Bundle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;alias&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;MySuperPackage.Bundle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bundle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/App_Plugins/MySuperPackage/my-super-package.js&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;and this works fine - but it has one or two issues. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;1. the version number is just sitting there in a json file.&lt;/strong&gt;&lt;br&gt;&#xA;This can be a pain, because what happens when you release a new version  ?well you either have to change this value or run some form of build script to change it for you. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;2. the JavaScript file never changes and might be cached between releases&lt;/strong&gt;&lt;br&gt;&#xA;Because the main JavaScript file is in this file it doesn&#x27;t change between releases, this means if someone updates your package to a new version this file URL is still the same and their browser might not fetch the newer version from the server.&lt;/p&gt;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  IPackageManaifestReader&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Another alternative is to use a &lt;code&gt;IPackageManifestReader&lt;/code&gt; (&lt;a href=&quot;https://dev.to/skttl/server-side-registering-of-package-manifest-in-umbraco-14-49go&quot;&gt;https://dev.to/skttl/server-side-registering-of-package-manifest-in-umbraco-14-49go&lt;/a&gt; by &lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/skttl&quot;&gt;@skttl&lt;/a&gt;) which allows you to register your package via your backend code (see &lt;a href=&quot;https://github.com/KevinJump/DoStuffWithUmbraco/blob/v17/main/src/DoStuff.Client/Composers/DoStuffPackageManifestReader.cs&quot; rel=&quot;noopener noreferrer&quot;&gt;DoStuffPackageManifestReader.cs&lt;/a&gt;&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IEnumerable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PackageManifest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ReadPackageManifestsAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;  &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Assembly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetAssembly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DoStuffPackageManifestReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))?&lt;/span&gt;&#xA;   &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&#xA;   &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FromResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IEnumerable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PackageManifest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PackageManifest&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;      &lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;DoStuff.Client&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;      &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;DoStuff with Umbraco client&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;      &lt;span class=&quot;n&quot;&gt;AllowTelemetry&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;      &lt;span class=&quot;n&quot;&gt;Version&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;      &lt;span class=&quot;n&quot;&gt;Extensions&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;          &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;DoStuff Client Bundle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;          &lt;span class=&quot;k&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;DoStuff.Client.Bundle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;          &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;bundle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;          &lt;span class=&quot;n&quot;&gt;js&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/App_Plugins/DoStuffClient/do-stuff-client.js?v=&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&#x2B;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;     &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&#xA;   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;You can see there is a little bit more code here but the basic information is the same as the &lt;code&gt;umbraco-package.json&lt;/code&gt; file. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;The key difference is we can fetch the version from the running assembly(dll).&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;When you build your NuGet packages of your extension the version will be stamped on the dll&#x27;s in the package by NuGet&#x27;s &lt;code&gt;pack&lt;/code&gt; process. and once its there the code in your &lt;code&gt;IPackageManifestReader&lt;/code&gt; will use that version value to update your package version and add it to the end of the JavaScript file&#x27;s URL. meaning for each new version the browser will fetch the file again.&lt;/p&gt;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;You need to remember to register your package manifest in a composer&lt;/p&gt;&#xA;&#xA;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&#xA;  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddSingleton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IPackageManifestReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DoStuffPackageManifestReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Entry points Auth.&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Another change that we will go into more detail in, when we talk about entry points and APIs is the code for setting up the authentication between sites. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;if you use the opinionated starter kit (or the umbraco-extension with the `-ex&#x27; flag) you will get the skeleton of the code for communicating with the server from your font end code. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;code&gt;&lt;/code&gt;`ts&lt;br&gt;&#xA;_host.consumeContext(UMB_AUTH_CONTEXT, async (authContext) =&amp;gt; {&lt;br&gt;&#xA;  // Get the token info from Umbraco&lt;br&gt;&#xA;  const config = authContext?.getOpenApiConfiguration();&lt;/p&gt;&#xA;&#xA;&lt;p&gt;client.setConfig({&lt;br&gt;&#xA;    auth: config?.token ?? undefined,&lt;br&gt;&#xA;    baseUrl: config?.base ?? &quot;&quot;,&lt;br&gt;&#xA;    credentials: config?.credentials ?? &quot;same-origin&quot;,&lt;br&gt;&#xA;  });&lt;br&gt;&#xA;});&lt;br&gt;&#xA;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This is fine and it works - but from a bit of experience there is another bit you can add, that helps to keep things fresh should you have the browser open all day&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;ts&lt;br&gt;&#xA;// client interceptor will get the latest token for the auth&lt;br&gt;&#xA;// context for a request, so if the token has been refreshed&lt;br&gt;&#xA;// since we first got it, we&#x27;ll still have a valid token.&lt;br&gt;&#xA; client.interceptors.request.use(async (request, _options) =&amp;gt; {&lt;br&gt;&#xA;  const token = await authContext?.getLatestToken();&lt;br&gt;&#xA;  request.headers.set(&quot;Authorization&quot;,&lt;/code&gt;Bearer ${token}&lt;code&gt;);&lt;br&gt;&#xA;  return request;&lt;br&gt;&#xA;});&lt;br&gt;&#xA;&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;br&gt;&#xA;A client interceptor will run when the requests are fired and just make sure you have the latest token from the user send over as part of the request. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;Again this isn&#x27;t something you have to do, everything works fine in the examples, this just smooths the odd edge I have seen during development.&lt;/p&gt;]]></description>
                    <pubDate>Wed, 25 Feb 2026 17:20:43 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://dev.to/kevinjump/battle-scarred-developers-guide-to-umbraco-v17-getting-started-hge</guid>
                    <title>Battle scarred developer&#x27;s guide to Umbraco v17 - Getting Started</title>
                    <link>https://dev.to/kevinjump/battle-scarred-developers-guide-to-umbraco-v17-getting-started-hge</link>
                    <description><![CDATA[&lt;h2&gt;&#xA;  &#xA;  &#xA;  umbraco-extensions&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;If you are starting out on a new umbraco extension or package you will probably want to start with the umbraco-extension template that comes as part of the Umbraco templates. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;So if you haven&#x27;t already you will want the Umbraco templates&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;dotnet new install Umbraco.Templates@17.*&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;and once you have these templates installed you &#x27;could&#x27; just run the umbraco extension.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;dotnet new umbraco-extension -n MySuperNewUmbracoPackage&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;and this will crate you a new package to pay about with, but at this point you won&#x27;t have an Umbraco site just an extension, so you will probably want to think about that. &lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Opinionated starter kit template.&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;if you actually want to have a site and a bit more structure around your development then you might want to consider &lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/lottepitcher&quot;&gt;@lottepitcher&lt;/a&gt;&#x27;s &lt;a href=&quot;https://github.com/LottePitcher/opinionated-package-starter&quot; rel=&quot;noopener noreferrer&quot;&gt;Opinionated starter kit template&lt;/a&gt;, this adds stuff around the edges of the standard umbraco-extension, such as a test site, GitHub scripts and umbraco-marketplace files which will help when you come to release your super package. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;You can install the templates for the Opinonated starter kit like so:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;dotnet new install Umbraco.Community.Templates.PackageStarter&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;you can then start a new project&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;dotnet new umbracopackagestarter -n MySuperPackage&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;after this you get your extension and a test site, and scripts all nicely laid out for you. &lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Project Structure&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;For the &lt;a href=&quot;https://github.com/KevinJump/DoStuffWithUmbraco/tree/v17/main&quot; rel=&quot;noopener noreferrer&quot;&gt;DoStuffWithUmbraco repository&lt;/a&gt; that we are using as a reference for these blog posts you will notice there are a few slight differences with both the umbraco-extensions and the opinionated starter kit. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;These changes are not major, and for the most part you can ignore them, but for information we have laid the project out like so.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;&#x2B;-- src&#xA;  &#x2B;-- DoStuff&#xA;  &#x2B;-- DoStuff.Client&#xA;  &#x2B;-- DoStuff.Core&#xA;&#x2B;-- demo&#xA;  &#x2B;-- DoStuff.Website&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  DoStuff.Client&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Client contains all the &quot;front end&quot; code and API controllers for the extension to render inside Umbraco. There is no real &#x27;business logic&#x27; inside this layer, it&#x27;s the UI and the c# code required to get data to the UI.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  DoStuff.Core&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;The core project contains the backend logic for the application - this is where services, repositories, data layers etc all live. we sperate this out from the client, because then well it&#x27;s separate and we can in theory use the core logic of our code without the front end, or on a different front end should it ever change &#x1F627; &lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  DoStuff&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;The parent to all of these projects is the &#x27;DoStuff&#x27; library - no really this has no code it in, but it would be the library that became the NuGet package that people would install (if we made the library a package). &lt;/p&gt;&#xA;&#xA;&lt;p&gt;The &quot;DoStuff&quot; has dependencies on the .Client and .Core projects so when someone would install the &quot;DoStuff&quot; NuGet package that would also fetch the client and the core. &lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  DoStuff.Website&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Our website is off in a &#x27;demo&#x27; folder, just so we can have it separate from our project. If this wasn&#x27;t a reference library we would probably exclude the &#x27;demo&#x27; folder from the source repository, then the site is independent of our package&#x27;s code. &lt;/p&gt;]]></description>
                    <pubDate>Wed, 25 Feb 2026 17:20:29 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://dev.to/kevinjump/battle-scarred-developers-guide-to-umbraco-v17-intro-39ke</guid>
                    <title>Battle scarred developer&#x27;s guide to Umbraco v17 - Intro</title>
                    <link>https://dev.to/kevinjump/battle-scarred-developers-guide-to-umbraco-v17-intro-39ke</link>
                    <description><![CDATA[&lt;h2&gt;&#xA;  &#xA;  &#xA;  Introduction&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;It&#x27;s almost two years now since I wrote a &lt;a href=&quot;https://dev.to/kevinjump/series/26221&quot;&gt;quite large series of blog posts about the then very new umbraco Backoffice&lt;/a&gt;. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;The early adopters&#x27; guide to the Umbraco Backoffice was really just a way for me to write down my thoughts and discoveries as I started the process of moving our packages to the brave new world.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;As it turned out quite a few people found those posts useful, and they are still being referenced by people today (the &lt;a href=&quot;https://github.com/umbraco/Umbraco-CMS-Backoffice-Skills&quot; rel=&quot;noopener noreferrer&quot;&gt;Umbraco.AI Skills&lt;/a&gt; even use them), but you can learn a lot in two years and Umbraco has gone from v14 to v17, and there has been loads of refinements and tweaks. as such the early adopters guide series are good, but they could be a lot better. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;So - now that we&#x27;ve come out of the other side of two years of upgrading and developing packages for the &quot;new&quot; Umbraco back office, I thought it was time to dust off the code and re-visit the guides. &lt;/p&gt;&#xA;&#xA;&lt;p&gt;So today, we are starting the &quot;Battle scarred developer&#x27;s guide to Umbraco v17&quot; - this is a series of blog posts aimed at package and extension developers - giving them a leg up for a quick start, and tips and tricks on how to do things &#x27;right&#x27;&lt;/p&gt;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;It&#x27;s also worth noting the Umbraco documentation has also improved greatly since we did the first round of posts - so you should check out &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/customizing/overview&quot; rel=&quot;noopener noreferrer&quot;&gt;https://docs.umbraco.com/umbraco-cms/customizing/overview&lt;/a&gt; it may already tell you what you need to know. &lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;All of the code referenced in these blogs is available via GitHub: &lt;br&gt;&#xA;&lt;a href=&quot;https://github.com/KevinJump/DoStuffWithUmbraco/tree/v17/main&quot; rel=&quot;noopener noreferrer&quot;&gt;https://github.com/KevinJump/DoStuffWithUmbraco/tree/v17/main&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;]]></description>
                    <pubDate>Wed, 25 Feb 2026 17:20:19 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=wX5uvDOfLUc</guid>
                    <title>umbraCoffee - Compose Yourself</title>
                    <link>https://www.youtube.com/watch?v=wX5uvDOfLUc</link>
                    <description><![CDATA[Welcome to your monthly dose of #umbraCoffee&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;! Your hosts - Marcin and Callum - together with their guest(s) will drive through all of the community news and happenings in the Umbraco world. So... grab a cuppa, join us LIVE and enjoy!&#xA;&#xA;This time we&#x27;re joined by Umbraco CTO Filip Bech-Larsen, and Head of Orchestration Jordan McFarlane, to talk all things Umbraco Compose...&#xA;&#xA;See ya?!&#xA;&#xA;---&#xA;&#x2615; Wanna buy us a coffee/pizza/donuts?&#xA;https://www.buymeacoffee.com/umbracoffee&#xA;---&#xA;&#xA;Notes:&#xA;&#xA;// TODO]]></description>
                    <pubDate>Wed, 25 Feb 2026 13:10:06 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://dev.to/phil-whittaker/mcp-vs-agent-skills-why-theyre-different-not-competing-2bc1</guid>
                    <title>MCP vs Agent Skills: Why They&#x27;re Different, Not Competing</title>
                    <link>https://dev.to/phil-whittaker/mcp-vs-agent-skills-why-theyre-different-not-competing-2bc1</link>
                    <description><![CDATA[&lt;h2&gt;&#xA;  &#xA;  &#xA;  Introduction&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;When Agent Skills launched in October 2025, they sparked immediate debate in the AI tooling community. Some prominent voices, including developer Simon Willison, suggested Skills might be &quot;a bigger deal than MCP,&quot; noting his waning interest in MCPs due to their token consumption issues(&lt;a href=&quot;https://simonwillison.net/2025/Oct/16/claude-skills/&quot; rel=&quot;noopener noreferrer&quot;&gt;Claude Skills are awesome, maybe a bigger deal than MCP&lt;/a&gt;). The timing seemed damning for MCP&#x2014;barely a year after Anthropic introduced the Model Context Protocol in November 2024, a lighter-weight alternative emerged that appeared to solve MCP&#x27;s biggest problem: context window exhaustion.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;I&#x27;ve heard plenty of people discount MCP now, thinking we should all just be using Skills instead. But here&#x27;s what we&#x27;ve learned after using both technologies side by side: Skills and MCPs aren&#x27;t competing solutions to the same problem. They&#x27;re fundamentally different architectures serving different purposes.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Skills excel at information delivery and adaptive context management, functioning as ephemeral clouds of knowledge that LLMs can pull from as needed. MCPs provide structured tool integration, giving LLMs deterministic ways to speak to the outside world through well-defined protocols. Rather than replacement, they serve complementary roles. And with MCP&#x27;s recent adoption of progressive discovery in January 2026, the original context efficiency advantage that Skills held has disappeared(&lt;a href=&quot;https://www.atcyrus.com/stories/mcp-tool-search-claude-code-context-pollution-guide&quot; rel=&quot;noopener noreferrer&quot;&gt;What is MCP Tool Search? The Claude Code Feature&lt;/a&gt;).&lt;/p&gt;&#xA;&#xA;&lt;p&gt;What remains are two distinct approaches to two distinct challenges in LLM integration. Think of it like a painter&#x27;s easel&#x2014;different brushes for different strokes, different tools for different purposes. This article explains why Skills aren&#x27;t a replacement for MCP, and why both technologies matter for building the future of AI integration.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  What is MCP and Why It Mattered&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;When Anthropic launched the Model Context Protocol in November 2024, it was genuinely revolutionary(&lt;a href=&quot;https://www.ajeetraina.com/one-year-of-model-context-protocol-from-experiment-to-industry-standard/&quot; rel=&quot;noopener noreferrer&quot;&gt;One Year of Model Context Protocol: From Experiment to Industry Standard&lt;/a&gt;). The protocol simplified the entire process of connecting LLMs to the outside world. Before MCP, tool calling was difficult, non-standardized, and inconsistent across platforms. MCP made it dramatically easier and enabled people to build integrations that actually worked.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The impact was immediate. Within months, thousands of MCPs were created and deployed&#x2014;tens of thousands, even hundreds of thousands. The protocol shipped with SDKs in Python, TypeScript, C#, and Java, making it accessible across the ecosystem. Major platforms adopted it quickly: ChatGPT, Claude, Cursor, Gemini, Microsoft Copilot, and Visual Studio Code all added first-class MCP support(&lt;a href=&quot;https://www.ajeetraina.com/one-year-of-model-context-protocol-from-experiment-to-industry-standard/&quot; rel=&quot;noopener noreferrer&quot;&gt;One Year of Model Context Protocol: From Experiment to Industry Standard&lt;/a&gt;). By early 2026, MCP was seeing over 97 million monthly SDK downloads with more than 10,000 active servers deployed.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;MCP genuinely revolutionized how we connect LLMs to external systems. That&#x27;s what MCPs are&#x2014;and they&#x27;re brilliant at it.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The Original Context Window Problem&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;But people quickly realized there were some serious downsides to MCP, especially as more developers got used to how LLMs actually work. The problem? Your context window&#x2014;that finite space where you can influence what the LLM will output&#x2014;is precious real estate. It&#x27;s critical that you manage it carefully and only put things in there that you need, because otherwise you&#x27;ll get hallucinations and unreliable outputs.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;When MCP first launched, it put everything into the context window upfront. Every tool&#x27;s name, description, output schema, input schema&#x2014;everything loaded immediately. That was extraordinarily wasteful. A single tool could consume 500 to 900 tokens before you&#x27;d even started any actual work.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;With only a handful of tools, you could easily end up with no context available to do anything useful.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This became particularly painful for us at Umbraco when we looked at composing tools together to create magic&#x2014;MCPs where tools could combine to make impossible things happen. That led to a lot of tools. The Umbraco MCP currently has around 345 tools(&lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/reference/developer-mcp/available-tools&quot; rel=&quot;noopener noreferrer&quot;&gt;Available Tools - Umbraco Documentation&lt;/a&gt;). When you compose all those together, you end up consuming around 30,000 tokens just for tool definitions. That&#x27;s more than most entire context windows.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This was definitely seen as a critical design flaw that limited MCP usability and scalability.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The Rise of Skills and Progressive Discovery&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Skills were introduced in October 2025, almost a year after MCP was created(&lt;a href=&quot;https://claude.com/blog/equipping-agents-for-the-real-world-with-agent-skills&quot; rel=&quot;noopener noreferrer&quot;&gt;Equipping agents for the real world with Agent Skills&lt;/a&gt;). They launched to considerable acclaim and gained traction incredibly quickly. And the reason Skills caught fire so fast? They had a clever trick up their sleeve.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Core Innovation: Progressive Discovery&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Skills introduced progressive discovery. The idea: start with the smallest amount of information possible and put only that into the context window. It&#x27;s remarkably context-efficient.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;At the start, the only information in context about a particular skill is the name and a very short description. That might take up between 20 and 50 tokens out of 200,000. Incredibly efficient. Then when the LLM decides it wants to use a particular skill, it pulls in the skill markdown file and the rest of the instructions linked to it. Brilliant!&lt;/p&gt;&#xA;&#xA;&lt;p&gt;In that skill markdown file, you can link to other files within the skill. The LLM only loads those if it decides it needs more information. There might be links in there, and it might decide to go out to the internet. This progressive discovery that Skills have as a key advantage made real waves.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Skills were released as an open standard by Anthropic on December 18, 2025, with enterprise partnerships including Canva, Notion, Figma, and Atlassian providing prebuilt skills(&lt;a href=&quot;https://claude.com/blog/equipping-agents-for-the-real-world-with-agent-skills&quot; rel=&quot;noopener noreferrer&quot;&gt;Equipping agents for the real world with Agent Skills&lt;/a&gt;). The approach quickly gained traction across agentic tools and platforms. Most agentic tools out there now support Skills.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;When Skills first came out, Simon Willison said they could be a bigger deal than MCPs. He expected thousands upon thousands of Skills just like when MCP first launched, making a real impact on software engineering and development(&lt;a href=&quot;https://simonwillison.net/2025/Oct/16/claude-skills/&quot; rel=&quot;noopener noreferrer&quot;&gt;Claude Skills are awesome, maybe a bigger deal than MCP&lt;/a&gt;). I think that&#x27;s probably going to happen&#x2014;we&#x27;ve seen momentum building, and people are discovering how useful they can be.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;But I very much disagree that they&#x27;re a replacement for MCP. I don&#x27;t think that&#x27;s the case at all.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  MCP&#x27;s Recent Catch-Up: Progressive Discovery Arrives&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;In January 2026&#x2014;just last month&#x2014;Claude Code introduced something I&#x27;d been genuinely waiting for ever since Skills launched(&lt;a href=&quot;https://www.atcyrus.com/stories/mcp-tool-search-claude-code-context-pollution-guide&quot; rel=&quot;noopener noreferrer&quot;&gt;What is MCP Tool Search? The Claude Code Feature&lt;/a&gt;). Anthropic took the same progressive discovery trick that made Skills so context-efficient and applied it directly to MCP.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;So when you load an MCP now, you get the name and description of each tool&#x2014;really small and compact, taking up around 20 to 50 tokens each. Exactly the same as Skills. Absolutely incredible.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Then if the LLM decides it wants to use a particular tool for the task at hand, it loads in the input schema, output schema, full description, and everything around it. That means you can host many more MCP tools, and it won&#x27;t decimate your context window. It makes your conversations far more efficient and practical.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The impact was immediate and measurable. Token overhead dropped by 85%&#x2014;from around 77,000 tokens to just 8,700 tokens for setups with 50&#x2B; tools(&lt;a href=&quot;https://www.atcyrus.com/stories/mcp-tool-search-claude-code-context-pollution-guide&quot; rel=&quot;noopener noreferrer&quot;&gt;What is MCP Tool Search? The Claude Code Feature&lt;/a&gt;). Tool calling accuracy improved significantly as well: Claude Opus 4 jumped from 49% to 74% accuracy, while Opus 4.5 went from 79.5% to 88.1%.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;For me, this means that initial problem with MCP&#x2014;the concern that haunted it from launch&#x2014;has actually been solved. I think MCP has some catching up to do in terms of perception. But that context window problem? It&#x27;s gone.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Active Context Management: The Real Game-Changer&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;This trick that Skills and now MCPs both use is something I call active context management. Last year, the phrase was &quot;context engineering&quot;&#x2014;ensuring your context window only includes what it needs for a given task. That&#x27;s genuinely hard work to make work well, and it&#x27;s time-consuming to curate exactly what you want into the context window to support the tasks you have.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Active context management is something different&#x2014;a step forward. This is what Skills and MCP tools now do: they allow you to put a small amount of information into context, and then if it needs to be used, the rest gets pulled in afterward.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The challenge is a bit of a chicken-and-egg situation. How much information do you put into the context window to make it obvious for the LLM when to trigger it and progressively load the rest? That&#x27;s really tricky to get right, and that&#x27;s the real benefit of active context management&#x2014;nailing that balance.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This active approach enables LLMs to work with dozens or hundreds of tools while minimizing context exhaustion. It&#x27;s the key innovation that makes modern LLM integration practical at scale.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  This Is Where They Diverge&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;I firmly believe there&#x27;s a real divergence between Skills and MCPs. It&#x27;s important to recognize that there are things MCPs are better at doing than Skills, and vice versa. There are areas where you&#x27;d choose one over the other. This is where the boundary between determinism and non-determinism becomes the key differentiator.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Skills Are Ephemeral Information Clouds&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Skills, by their very nature, are extraordinarily easy to set up. It&#x27;s literally just a directory with a file in it&#x2014;that&#x27;s the minimum you need. They&#x27;re trivial to build and start using.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;But this also means that Skills can be quite ephemeral. They have an element of non-determinism in them, which makes them absolutely amazing&#x2014;but at the same time, it makes them a little unstructured.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;What we&#x27;re finding is that Skills work best as information clouds. They&#x27;re things that exist to provide information. They&#x27;re really about automated context management&#x2014;bringing in the right context at the right time to improve the LLM&#x27;s ability to make good decisions across a whole range of tasks.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Skills support progressive discovery beautifully. You start with a single piece of information, and from there, it can link out to related context, code examples, and deeper guidance as needed. The LLM can reach into, pulling out as much or as little as it needs for the task at hand, following the most direct path to exactly the right context at the right time. It&#x27;s about information efficiency for the LLM, and it&#x27;s crucial to understand that&#x27;s one of the most important things about Skills.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Their advantage is their flexibility&#x2014;their ability to adapt and change, to be used as much or as little as needed. That&#x27;s really the essence of what Skills are and why they matter.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Skills excel at:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Supporting diverse, exploratory LLM tasks&lt;/li&gt;&#xA;&lt;li&gt;Providing knowledge libraries and best practices&lt;/li&gt;&#xA;&lt;li&gt;Delivering automated context management&lt;/li&gt;&#xA;&lt;li&gt;Offering information guidance that adapts to the conversation&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;But they&#x27;re fundamentally different from what an MCP is.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  MCPs Are Defined, Structured Tools&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;MCP is really about tools. It&#x27;s about structure. It&#x27;s about defined, stable architecture. It&#x27;s about giving an LLM a deterministic way to connect to things.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;With Skills, you have that boundary and ability to move between non-determinism and determinism. With MCP, you don&#x27;t really have that&#x2014;and that can actually be a really good thing. When you trigger a tool, you know you&#x27;re triggering it. It&#x27;s much easier to get tools that compose together to complete agentic flows. Whereas with Skills, that&#x27;s trickier and less predictable because triggering Skills can be somewhat uncertain.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;With MCP, because it&#x27;s a well-defined and structured architecture, you have SDKs for it. You can build proper structures with testing, helpers, core systems, shared code, and all the infrastructure that comes with mature software development. That&#x27;s something you really can&#x27;t do with Skills in the same way. They look similar, but they&#x27;re actually very different.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;You can have MCPs that chain into other MCPs for hierarchical composition. You have MCPs that are hosted on the internet with persistent connections. You can do dynamic tool loading with infrastructure designed for it. You can&#x27;t do any of that with Skills.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;So it may look like Skills are a basic thing&#x2014;and they&#x27;re not. Whereas MCP may be seen as enterprise or more grown-up&#x2014;and that&#x27;s not what it&#x27;s about at all. It&#x27;s about structure. MCPs are structured. They&#x27;re precise. They work in well-defined ways. They have hard edges. Whereas Skills don&#x27;t. Skills are there to provide information, and maybe provide a little bit of deterministic information as well.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;MCPs provide the technical capabilities that enable:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Enterprise integrations where reliability matters&lt;/li&gt;&#xA;&lt;li&gt;Complex multi-step processes with predictable workflows&lt;/li&gt;&#xA;&lt;li&gt;Agentic systems that compose tools together reliably&lt;/li&gt;&#xA;&lt;li&gt;Infrastructure with shared code, testing, and helpers&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;The key strength of MCPs is structure and composability.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Where They Converge: Scripts and Code Execution&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;But there is a similarity&#x2014;something that confuses people about Skills and maybe led people to think Skills could replace MCPs. That&#x27;s the way you can put scripts into Skills and have script files run in the sandboxed environment. On first pass, it looks like these things could replace MCPs.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;But it&#x27;s not really the case.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Scripts in Skills are quite basic. I wouldn&#x27;t want to create full structures behind them that the skill can trigger, and it&#x27;s very difficult to share scripts between Skills or fit them into a stable architecture. Skills scripts are really there to allow a level of determinism&#x2014;to use them for things like reports.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Getting an LLM to create a report on something is difficult because it will give you a different answer every time. But when you need something deterministic, you can run a skill that will return the same data every time it makes that call, and then the LLM can use it with much less likelihood of hallucination.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Dynamic Code Execution: A False Equivalence&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;With MCP, there&#x27;s this thing called code execution that emerged in November 2025(&lt;a href=&quot;https://www.anthropic.com/engineering/code-execution-with-mcp&quot; rel=&quot;noopener noreferrer&quot;&gt;Code execution with MCP: building more efficient AI agents&lt;/a&gt;). The idea is that the LLM generates code on the fly&#x2014;writing raw API calls, scripts, or queries at runtime rather than invoking pre-built tool endpoints. Instead of calling a well-defined MCP tool like &lt;code&gt;createContent(title, body)&lt;/code&gt;, the LLM dynamically writes a fetch call or script to hit an API endpoint directly.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Skills are very good at that pattern too&#x2014;their sandboxed script environment can run LLM-generated code in a similar way. And the problem is, with code execution, you&#x27;re ignoring all the benefits of systemizing and the difference between an API endpoint and what the LLM is most efficient for.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;You lose the optimization of well-defined tool schemas: parameter validation, consistent output formats, and composability between tools. You&#x27;re ignoring the work of manipulating and shaping API structures specifically to make them LLM-friendly. Raw API calls are often verbose, poorly documented for LLM consumption, and inconsistent.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Both Skills scripts and MCP code execution become less effective when used this way&#x2014;you trade reliability and composability for flexibility you rarely need.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This is the problem. Skills are brilliant, but they&#x27;re brilliant at what they do. It&#x27;s the lack of structure that makes them unsuitable for providing tools that need to be well-defined and highly structured. That&#x27;s where the difference lies, because MCP is there to provide structure. It exists within a framework, within a collection of tools that are all similar, all there to support the same set of functionality. It&#x27;s also much easier to compose tools to bring the magic out.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The better approach: Use scripts for deterministic outputs where consistency matters, and use properly structured MCP tools for integration and action. Don&#x27;t treat dynamic code generation as a substitute for purpose-built tool architecture.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Where Umbraco Uses Skills&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;We&#x27;ve thought long and hard about this. Given what we&#x27;ve said here, we see Skills as ephemeral, like a cloud of information that the LLM can call on. It can pull as much or as little as it needs to extract the information.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;We use Skills for information delivery&#x2014;functioning as libraries of knowledge and best practices. That information might include code examples. It might include scripts that make small calls somewhere. But it&#x27;s in no way structured in the way MCPs are.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Structured Skill Sets Aligned With Extension Points&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The Skills we have may be structured. There may be lots&#x2014;like the back office skills we&#x27;ve got. We have a structure of Skills defined to match the extension points in the back office. But there&#x27;s no shared code between them, and they&#x27;re really seen as a library of information.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;We include real-world code examples in Skills&#x2014;runnable samples that developers and LLMs can use directly. These aren&#x27;t just snippets; they&#x27;re practical, executable examples of proper setup and implementation patterns. This grounds the LLM&#x27;s output in tested, working code rather than generated approximations, significantly reducing hallucination.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;We also provide direct links to Umbraco source code and the UUI (Umbraco UI) component library as authoritative references. Skills point the LLM to actual source repositories and component libraries, grounding responses in the ultimate source of truth rather than potentially outdated or hallucinated documentation. This ensures best practices come directly from Umbraco&#x27;s own codebase and UI patterns, not from the LLM&#x27;s general training data.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;That&#x27;s where I see Skills going&#x2014;there to provide information to the LLM and help manage the context it has given the task at hand.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Where Umbraco Uses MCPs&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;I don&#x27;t think anything&#x27;s going to change in our strategy around MCP now that Skills are part of the agentic world. We&#x27;re going to continue using MCP to provide tools into Umbraco, to open up Umbraco so you can use an LLM to talk to it, manipulate it, compose it, and use it in amazing and interesting ways.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The Umbraco Developer MCP currently exposes over 330 tools spanning 36 endpoint groups, providing near-complete parity with the Umbraco Management API(&lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/reference/developer-mcp/available-tools&quot; rel=&quot;noopener noreferrer&quot;&gt;Available Tools - Umbraco Documentation&lt;/a&gt;). An LLM with access to this MCP can create document types, manage media, configure members, set up cultures, define data types&#x2014;essentially all the operations you&#x27;d normally perform through the back office interface or API calls.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;We&#x27;re continuing to build MCPs based on our add-on products and to create MCPs around different use cases. I don&#x27;t see that changing at all because of Skills.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;From our perspective, I see them as quite different things with quite different use cases, and that&#x27;s definitely going to be apparent in how we use these two separate technologies at Umbraco with LLMs.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Can They Work Together?&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;I see MCP and Skills both being used at Umbraco and both being leveraged heavily to make using LLMs with Umbraco as easy and fulfilling as possible. I don&#x27;t see any problem with using them together either.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;We have plans to create content modeling Agent Skills to help you develop your content structures and provide information, expertise, and best practices on how to set up and generate your own Umbraco sites.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The Powerful Combination&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;What you&#x27;ll have is the skill providing all the knowledge, best practices, and information on how to do it right, and then the MCP actually doing the action. The skill is the brain&#x2014;it knows what to do, what to create, how to update things, and how to create good structures for content in Umbraco. The MCP is the muscle that actually implements it.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;That&#x27;s where I see things going&#x2014;an example of collaboration between the two. I see that as genuinely important.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Conclusion&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Skills and MCPs are very different things&#x2014;and both are critically important for the future of how LLMs integrate with and enhance Umbraco.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Skills function as information clouds with flexible context management, excelling at knowledge delivery and adaptive context enrichment. MCPs provide structured tools with reliable composition and integration, excelling at deterministic workflows and system integration.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Claims that Skills replace MCPs misunderstand these architectural differences. Skills adoption doesn&#x27;t diminish MCP value&#x2014;they solve different problems. Now that both support progressive discovery, the context efficiency question is settled. What remains are the real differences: structure versus flexibility, determinism versus adaptation, tools versus knowledge.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The future belongs to thoughtful use of both. Neither technology is universally better. Architecture should drive the choice, not hype or convenience. When Skills and MCPs work together, each playing to its strengths, you get the most powerful LLM integration possible.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;So when evaluating these technologies for your use case, don&#x27;t ask &quot;Which one is better?&quot; Ask &quot;Do I need information delivery or tool execution?&quot; The answer to that question will point you in the right direction.&lt;/p&gt;]]></description>
                    <pubDate>Tue, 24 Feb 2026 13:01:29 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbracospark/116125633721526211</guid>
                    <title>Get your Umbraco Spark ticket before midnight on 28th Feb</title>
                    <link>https://umbracocommunity.social/@umbracospark/116125633721526211</link>
                    <description><![CDATA[&#x23F3; 4 days to go! Get your Umbraco Spark ticket before midnight on 28th Feb to secure ALL perks and goodies.After midnight, perks won&#x2019;t be included &#x2014; don&#x2019;t miss out! &#x1F39F;&#xFE0F;https://www.tickettailor.com/events/umbukfdn/1896581#UmbracoSpark #Umbraco #Countdown #LastChance]]></description>
                    <pubDate>Tue, 24 Feb 2026 12:36:14 Z</pubDate>
                        <category>community</category>
                        <category>mastodon</category>
                        <category>social</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/digitalwonderlab.mediafinder</guid>
                    <title>DigitalWonderlab.MediaFinder</title>
                    <link>https://marketplace.umbraco.com/package/digitalwonderlab.mediafinder</link>
                    <description><![CDATA[An Umbraco backoffice dashboard that lets you search for media items by name, size, or type.]]></description>
                    <pubDate>Mon, 23 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/digitalwonderlab.backofficeannouncement</guid>
                    <title>DigitalWonderlab.BackofficeAnnouncement</title>
                    <link>https://marketplace.umbraco.com/package/digitalwonderlab.backofficeannouncement</link>
                    <description><![CDATA[A backoffice announcement bar for Umbraco. Toggle on/off a simple text announcement visible to all backoffice users.]]></description>
                    <pubDate>Mon, 23 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://github.com/skybrud/Skybrud.Umbraco.Redirects/releases/tag/v17.0.2</guid>
                    <title>Skybrud.Umbraco.Redirects 17.0.2</title>
                    <link>https://github.com/skybrud/Skybrud.Umbraco.Redirects/releases/tag/v17.0.2</link>
                    <description><![CDATA[Award winning redirects manager for Umbraco.]]></description>
                    <pubDate>Sun, 22 Feb 2026 18:39:58 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://github.com/skybrud/Skybrud.Umbraco.Redirects/releases/tag/v16.0.3</guid>
                    <title>Skybrud.Umbraco.Redirects 16.0.3</title>
                    <link>https://github.com/skybrud/Skybrud.Umbraco.Redirects/releases/tag/v16.0.3</link>
                    <description><![CDATA[Award winning redirects manager for Umbraco.]]></description>
                    <pubDate>Sun, 22 Feb 2026 18:32:06 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://github.com/skybrud/Skybrud.Umbraco.Redirects/releases/tag/v13.0.9</guid>
                    <title>Skybrud.Umbraco.Redirects 13.0.9</title>
                    <link>https://github.com/skybrud/Skybrud.Umbraco.Redirects/releases/tag/v13.0.9</link>
                    <description><![CDATA[Award winning redirects manager for Umbraco.]]></description>
                    <pubDate>Sun, 22 Feb 2026 18:21:20 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/usupport.usync</guid>
                    <title>uSupport.uSync</title>
                    <link>https://marketplace.umbraco.com/package/usupport.usync</link>
                    <description><![CDATA[uSupport is an feature rich ticketing system designed specifically for the Umbraco. It is a complete ticketing solution that enables users to create, manage, and view tickets and their associated comments. With uSupport, you can quickly and easily create and manage tickets. uSupport is highly customizable, allowing users to set up their own ticket types and define ticket statuses.]]></description>
                    <pubDate>Sun, 22 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/sbd.contentinsights</guid>
                    <title>SBD.ContentInsights</title>
                    <link>https://marketplace.umbraco.com/package/sbd.contentinsights</link>
                    <description><![CDATA[This package for Umbraco aims to provide insights into the content, specifically the created documents and document types, using Chart.js.]]></description>
                    <pubDate>Sun, 22 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.wearecogworks.com/innerworks/articles/umbraco-mvp-story</guid>
                    <title>What Being an Umbraco MVP Really Means</title>
                    <link>https://www.wearecogworks.com/innerworks/articles/umbraco-mvp-story</link>
                    <description><![CDATA[Journey to MVP | Ravi Motha | Innerworks]]></description>
                    <pubDate>Fri, 20 Feb 2026 11:38:05 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/phases.umbraco.neattip</guid>
                    <title>Phases.Umbraco.NeatTip</title>
                    <link>https://marketplace.umbraco.com/package/phases.umbraco.neattip</link>
                    <description><![CDATA[NeatTip is an Umbraco package that automatically converts long property descriptions into compact, interactive tooltips. Instead of cluttering your content editing interface with lengthy descriptions, NeatTip displays a small icon next to property labels. Click or hover the icon to view the full description in a styled tooltip. Reduces visual clutter, supports draggable tooltips, and only activates in content editing pages.]]></description>
                    <pubDate>Fri, 20 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/vettvangur.umbracoazurestorageprovider</guid>
                    <title>Vettvangur.UmbracoAzureStorageProvider</title>
                    <link>https://marketplace.umbraco.com/package/vettvangur.umbracoazurestorageprovider</link>
                    <description><![CDATA[Azure Blob Storage provider for Umbraco CMS.]]></description>
                    <pubDate>Fri, 20 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/vettvangur.umbracostorageproviders</guid>
                    <title>Vettvangur.UmbracoStorageProviders</title>
                    <link>https://marketplace.umbraco.com/package/vettvangur.umbracostorageproviders</link>
                    <description><![CDATA[Shared storage providers infrastructure for Umbraco CMS]]></description>
                    <pubDate>Fri, 20 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/vettvangur.umbracoazurestorageprovider.imagesharp</guid>
                    <title>Vettvangur.UmbracoAzureStorageProvider.ImageSharp</title>
                    <link>https://marketplace.umbraco.com/package/vettvangur.umbracoazurestorageprovider.imagesharp</link>
                    <description><![CDATA[Adds ImageSharp support using the Azure Blob Storage provider for Umbraco CMS.]]></description>
                    <pubDate>Fri, 20 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/february/tracking-bouldering-sessions-with-a-garmin-watch-app-and-umbraco-dashboard/</guid>
                    <title>Tracking Bouldering Sessions with a Garmin Watch App and Umbraco Dashboard</title>
                    <link>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/february/tracking-bouldering-sessions-with-a-garmin-watch-app-and-umbraco-dashboard/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 20 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/february/tracking-bouldering-sessions-with-a-garmin-watch-app-and-umbraco-dashboard/</guid>
                    <title>Tracking Bouldering Sessions with a Garmin Watch App and Umbraco Dashboard</title>
                    <link>https://owain.codes/blog/2026/february/tracking-bouldering-sessions-with-a-garmin-watch-app-and-umbraco-dashboard/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 20 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=VnxqTnMjSYE</guid>
                    <title>Umbraco Compose demo by CTO, Filip Bech-Larsen.</title>
                    <link>https://www.youtube.com/watch?v=VnxqTnMjSYE</link>
                    <description><![CDATA[In this demo, Umbraco CTO Filip Bech-Larsen showcases Umbraco Compose, a data orchestration platform built to power modern composable architecture.&#xA;&#xA;You&#x2019;ll see how Compose connects multiple data sources &#x2014; including Umbraco CMS, Google Sheets, Algolia search, and Cloudflare &#x2014; into a single GraphQL layer designed for scalability, performance, and maintainability. Instead of building custom integrations for every client, Compose centralizes and shapes data for delivery across websites, apps, dashboards, and other digital channels.&#xA;&#xA;Filip demonstrates how to ingest 10,000 products in seconds, achieve a 99 Lighthouse performance score, switch data sources without breaking the frontend, and unlock new search capabilities simply by updating a GraphQL query &#x2014; no backend rewrites required.&#xA;&#xA;If you&#x27;re building composable digital platforms and want fewer integrations, less maintenance, and faster iteration, this demo shows what composable done right looks like.&#xA;&#xA;Chapters:&#xA;00:00 The Problem: Rebuilding custom integrations for every customer&#xA;00:24 What Umbraco Compose Is: Data orchestration &#x2B; GraphQL at scale&#xA;02:21 Composable Architecture Demo: CMS, Google Sheets, Algolia, Cloudflare&#xA;04:54 High-Volume Ingestion &#x2B; Performance (10,000 products, Lighthouse 99)&#xA;06:29 Switching Data Sources &#x2B; Enhancing Search with GraphQL&#xA;&#xA;Discover more about Umbraco Compose: https://umbraco.com/products/umbraco-compose/]]></description>
                    <pubDate>Thu, 19 Feb 2026 07:12:54 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://medium.com/@procustomsoftware/why-choose-umbraco-development-services-in-2026-c0b262856be0?source=rss------umbraco-5</guid>
                    <title>Why Choose Umbraco Development Services in 2026</title>
                    <link>https://medium.com/@procustomsoftware/why-choose-umbraco-development-services-in-2026-c0b262856be0?source=rss------umbraco-5</link>
                    <description><![CDATA[&lt;div class=&quot;medium-feed-item&quot;&gt;&lt;p class=&quot;medium-feed-image&quot;&gt;&lt;a href=&quot;https://medium.com/@procustomsoftware/why-choose-umbraco-development-services-in-2026-c0b262856be0?source=rss------umbraco-5&quot;&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1536/1*M59UFeIxPM31hYEAsgEBiQ.png&quot; width=&quot;1536&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;medium-feed-snippet&quot;&gt;In 2026, digital performance defines business success. For UK B2B companies and growing enterprises, choosing the right CMS is critical&amp;#x2026;&lt;/p&gt;&lt;p class=&quot;medium-feed-link&quot;&gt;&lt;a href=&quot;https://medium.com/@procustomsoftware/why-choose-umbraco-development-services-in-2026-c0b262856be0?source=rss------umbraco-5&quot;&gt;Continue reading on Medium &#xBB;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;]]></description>
                    <pubDate>Wed, 18 Feb 2026 12:01:10 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://uskinned.net/blog/were-nominated-can-we-make-it-two-in-a-row/</guid>
                    <title>uSkinned Nominated for Best Website Builder | CMS Critic Awards</title>
                    <link>https://uskinned.net/blog/were-nominated-can-we-make-it-two-in-a-row/</link>
                    <description><![CDATA[Nominated for Best Website Builder | CMS Critic Awards&#xA;&#xA;We&#x2019;re pleased to share that uSkinned has been nominated once again for Best Website Builder in the CMS Critic Awards.&#xA;&#xA;Voting closes 27th February.]]></description>
                    <pubDate>Wed, 18 Feb 2026 11:25:15 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbracospark/116085859516756826</guid>
                    <title>Umbraco Spark Low Ticket Alert!</title>
                    <link>https://umbracocommunity.social/@umbracospark/116085859516756826</link>
                    <description><![CDATA[@umbfyi tip]]></description>
                    <pubDate>Tue, 17 Feb 2026 12:11:18 Z</pubDate>
                        <category>community</category>
                        <category>mastodon</category>
                        <category>social</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/contenttrace.umbraco</guid>
                    <title>ContentTrace.Umbraco</title>
                    <link>https://marketplace.umbraco.com/package/contenttrace.umbraco</link>
                    <description><![CDATA[Content activity tracking for Umbraco 17. Logs save and publish actions and displays them in a backoffice dashboard.]]></description>
                    <pubDate>Tue, 17 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/uprofile-february-2026-jenny-bradshaw/</guid>
                    <title>uProfile February 2026 - Jenny Bradshaw</title>
                    <link>https://umbraco.com/blog/uprofile-february-2026-jenny-bradshaw/</link>
                    <description><![CDATA[Meet Jenny Bradshaw - From &quot;Um-WHAT?&quot; to Umbraco MVP]]></description>
                    <pubDate>Tue, 17 Feb 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/blockfarmeditor.umbraco</guid>
                    <title>BlockFarmEditor.Umbraco</title>
                    <link>https://marketplace.umbraco.com/package/blockfarmeditor.umbraco</link>
                    <description><![CDATA[Block Farm Editor for Umbraco. Allows for easy on-page editing using built-in Umbraco data types and property editors.]]></description>
                    <pubDate>Tue, 17 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/truthwillout.umbraco.rtestylesmanager</guid>
                    <title>Truthwillout.Umbraco.RteStylesManager</title>
                    <link>https://marketplace.umbraco.com/package/truthwillout.umbraco.rtestylesmanager</link>
                    <description><![CDATA[A visual dashboard for managing Umbraco Rich Text Editor styles and colors. Easily add, edit, and organize text styles with color pickers, live previews, and automatic CSS generation.]]></description>
                    <pubDate>Tue, 17 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/af.umbraco.azure.blob.media.storage</guid>
                    <title>AF.Umbraco.Azure.Blob.Media.Storage</title>
                    <link>https://marketplace.umbraco.com/package/af.umbraco.azure.blob.media.storage</link>
                    <description><![CDATA[Azure Blob media storage provider for Umbraco 15/16/17 (.NET 9/10). Built on Umbraco.StorageProviders.AzureBlob and Umbraco.StorageProviders.AzureBlob.ImageSharp, it configures Azure Blob media filesystem and ImageSharp cache with auto-composition (no Program.cs changes required), startup fail-fast checks (required settings, connectivity, container checks) and configurable ImageSharp cache-retention cleanup.]]></description>
                    <pubDate>Mon, 16 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.merchello</guid>
                    <title>Umbraco.Community.Merchello</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.merchello</link>
                    <description><![CDATA[Enterprise ecommerce for Umbraco - making enterprise ecommerce simple]]></description>
                    <pubDate>Mon, 16 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/oc.multihotspot</guid>
                    <title>OC.MultiHotspot</title>
                    <link>https://marketplace.umbraco.com/package/oc.multihotspot</link>
                    <description><![CDATA[A property editor that allows a backoffice user to add multiple hotspots on an image along with descriptions. Render the image with hotspots on the frontend with Leaflet JS]]></description>
                    <pubDate>Mon, 16 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://github.com/millnut/umbraco_lts_upgrade_audit</guid>
                    <title>A CLI tool to audit Umbraco 13 LTS projects and estimate upgrade effort to Umbraco 17 LTS.</title>
                    <link>https://github.com/millnut/umbraco_lts_upgrade_audit</link>
                    <description><![CDATA[millnut/umbraco_lts_upgrade_audit: A CLI tool to audit Umbraco 13 LTS projects and estimate upgrade effort to Umbraco 17 LTS.]]></description>
                    <pubDate>Sat, 14 Feb 2026 11:04:22 Z</pubDate>
                        <category>social</category>
                        <category>gihthub</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/uadvancedbutton</guid>
                    <title>uAdvancedButton</title>
                    <link>https://marketplace.umbraco.com/package/uadvancedbutton</link>
                    <description><![CDATA[Enterprise-level CTA system with advanced buttons, button groups, dropdown menus, analytics hooks, and full accessibility. Works in Block Grid, Block List, and as standalone ViewComponent.]]></description>
                    <pubDate>Sat, 14 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://jcdc.dev/blog/umbraco-17-package-updates</guid>
                    <title>Umbraco 17 Package Updates</title>
                    <link>https://jcdc.dev/blog/umbraco-17-package-updates</link>
                    <description><![CDATA[Explore my updated suite of packages for Umbraco 17 and enhance your next Umbraco project with tools for relations, custom trees, and content editor experience.]]></description>
                    <pubDate>Fri, 13 Feb 2026 20:30:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://github.com/abjerner/Limbo.Umbraco.BlockList/releases/tag/v13.0.3</guid>
                    <title>Limbo.Umbraco.BlockList 13.0.3</title>
                    <link>https://github.com/abjerner/Limbo.Umbraco.BlockList/releases/tag/v13.0.3</link>
                    <description><![CDATA[Umbraco package that extends the functionality of Umbraco&#x27;s build-in block list.]]></description>
                    <pubDate>Fri, 13 Feb 2026 10:20:28 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbraco/116057132584781368</guid>
                    <title>Umbraco Developer MCP 17.1.0 is here!</title>
                    <link>https://umbracocommunity.social/@umbraco/116057132584781368</link>
                    <description><![CDATA[Umbraco Developer MCP 17.1.0 is here! Enjoy precise content updates, fine-grained tool control, structured and validated tooling, improved testing, and more - laying a solid foundation for future AI-powered workflows with Umbraco. Release notes: https://github.com/umbraco/Umbraco-CMS-MCP-Dev/releases/tag/v17.1.0  Documentation: https://docs.umbraco.com/umbraco-cms/reference/developer-mcp #Umbraco]]></description>
                    <pubDate>Fri, 13 Feb 2026 09:03:27 Z</pubDate>
                        <category>hq</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/announcing-umbraco-contributing-partners-2025/</guid>
                    <title>Announcing: Umbraco Contributing Partners 2025</title>
                    <link>https://umbraco.com/blog/announcing-umbraco-contributing-partners-2025/</link>
                    <description><![CDATA[64 Platinum &amp; Gold Partners have earned the badge of being this year&#x27;s Contributing Partners]]></description>
                    <pubDate>Fri, 13 Feb 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=PIryRhziY1o</guid>
                    <title>Merchello MVP Walkthrough For Umbraco v17&#x2B;</title>
                    <link>https://www.youtube.com/watch?v=PIryRhziY1o</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Thu, 12 Feb 2026 20:20:00 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/our.umbraco.githubissues</guid>
                    <title>Our.Umbraco.GitHubIssues</title>
                    <link>https://marketplace.umbraco.com/package/our.umbraco.githubissues</link>
                    <description><![CDATA[Our.Umbraco.GitHubIssues is a small Umbraco package that brings open GitHub issues from the Umbraco project right into your backoffice.]]></description>
                    <pubDate>Thu, 12 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/crumpled.robotstxt</guid>
                    <title>Crumpled.RobotsTxt</title>
                    <link>https://marketplace.umbraco.com/package/crumpled.robotstxt</link>
                    <description><![CDATA[A flexible, configuration-driven robots.txt solution for Umbraco v13, v14, v15, v16 and v17 that protects your non-production environments from search engine indexing by default. Supports multi-site configurations, environment-aware rules, and flexible user-agent patterns with zero code setup.]]></description>
                    <pubDate>Thu, 12 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=GR-NZra1528</guid>
                    <title>DevRel Deep Dive: Creating Backoffice Extensions with AI Skills</title>
                    <link>https://www.youtube.com/watch?v=GR-NZra1528</link>
                    <description><![CDATA[This week Sebastiaan and Lotte are joined by Phil Whittaker, AI Staff Engineer at Umbraco to talk about what AI &#x201C;skills&#x201D; are and how you can use them to extend the Umbraco Backoffice. Phil talks us through installing the Umbraco Backoffice Skills, and then Seb demos using them to create a GitHub User Picker property editor.&#xA;&#xA;&#x1F440; Umbraco Backoffice Skills on GitHub: https://github.com/umbraco/Umbraco-CMS-Backoffice-Skills]]></description>
                    <pubDate>Wed, 11 Feb 2026 15:11:36 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://forum.umbraco.com/t/released-my-github-action-for-umbraco-cloud-deployments/7445</guid>
                    <title>GitHub Action for Umbraco Cloud Deployments Released</title>
                    <link>https://forum.umbraco.com/t/released-my-github-action-for-umbraco-cloud-deployments/7445</link>
                    <description><![CDATA[Released my GitHub Action for Umbraco Cloud Deployments - Umbraco community forum]]></description>
                    <pubDate>Wed, 11 Feb 2026 14:57:41 Z</pubDate>
                        <category>community</category>
                        <category>forum</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/our.umbraco.extensions.variables</guid>
                    <title>Our.Umbraco.Extensions.Variables</title>
                    <link>https://marketplace.umbraco.com/package/our.umbraco.extensions.variables</link>
                    <description><![CDATA[Variables property editor for Umbraco]]></description>
                    <pubDate>Wed, 11 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.bettericons</guid>
                    <title>Umbraco.Community.BetterIcons</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.bettericons</link>
                    <description><![CDATA[BetterIcons is a modern, powerful property editor for Umbraco CMS that provides access to 200,000&#x2B; icons from popular icon libraries including Material Design Icons, Font Awesome, Bootstrap Icons, and 100&#x2B; more. Built with React for a smooth, responsive user experience with smart search, color customization, and zero configuration.]]></description>
                    <pubDate>Wed, 11 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/our.umbraco.extensions.theming</guid>
                    <title>Our.Umbraco.Extensions.Theming</title>
                    <link>https://marketplace.umbraco.com/package/our.umbraco.extensions.theming</link>
                    <description><![CDATA[Theme picker and view engine for Umbraco]]></description>
                    <pubDate>Wed, 11 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbraco/116045689979220965</guid>
                    <title>Submissions for the Umbraco Awards 2026 are now open!</title>
                    <link>https://umbracocommunity.social/@umbraco/116045689979220965</link>
                    <description><![CDATA[&#x1F3C6; Submissions for the #Umbraco Awards 2026 are now open! Show off your work, get recognized, and inspire others!&#x2705; Fast &amp; easy - no video required&#x1F449; Submit now: https://codegarden.umbraco.com/awards/umbraco-awards]]></description>
                    <pubDate>Tue, 10 Feb 2026 10:55:38 Z</pubDate>
                        <category>social</category>
                        <category>hq</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://skttl.dev/blog/umbraco-skills-ai-agents/</guid>
                    <title>Umbraco Skills for AI Agents - A Game Changer for Backoffice Development</title>
                    <link>https://skttl.dev/blog/umbraco-skills-ai-agents/</link>
                    <description><![CDATA[Umbraco Skills for AI Agents - A Game Changer for Backoffice Development | skttl.dev]]></description>
                    <pubDate>Tue, 10 Feb 2026 10:21:53 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://github.com/patrickdemooij9/SeoToolkit.Umbraco/releases/tag/6.1.0</guid>
                    <title>SeoToolkit 6.1.0 is now available for the latest Umbraco version</title>
                    <link>https://github.com/patrickdemooij9/SeoToolkit.Umbraco/releases/tag/6.1.0</link>
                    <description><![CDATA[uSync compatability, page title template, content checks and much more! SeoToolkit 6.1.0 is now available for the latest Umbraco version. Check it out if you are interested in easy to use SEO! https://github.com/patrickdemooij9/SeoToolkit.Umbraco/releases/tag/6.1.0]]></description>
                    <pubDate>Tue, 10 Feb 2026 08:34:13 Z</pubDate>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://www.phases.io/insights/ai-in-umbraco-in-2026-choices-governance-and-day-to-day-use/</guid>
                    <title>AI in Umbraco in 2026: choices, governance, and day-to-day use</title>
                    <link>https://www.phases.io/insights/ai-in-umbraco-in-2026-choices-governance-and-day-to-day-use/</link>
                    <description><![CDATA[https://www.linkedin.com/posts/phases_ai-in-umbraco-2026-governance-choice-and-activity-7426869425099792385-Jjq7?utm_source=share&amp;utm_medium=member_ios&amp;rcm=ACoAAABj9KwBjr581HKBv-M3TbQu69Ia79rmfPw]]></description>
                    <pubDate>Tue, 10 Feb 2026 06:54:05 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/storage.healthchecks</guid>
                    <title>Storage.HealthChecks</title>
                    <link>https://marketplace.umbraco.com/package/storage.healthchecks</link>
                    <description><![CDATA[Health checks for monitoring and maintaining Umbraco media storage. Identifies duplicate files, large media, missing files, orphaned files and unused media items.]]></description>
                    <pubDate>Tue, 10 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbmetrics</guid>
                    <title>UmbMetrics</title>
                    <link>https://marketplace.umbraco.com/package/umbmetrics</link>
                    <description><![CDATA[Package Description]]></description>
                    <pubDate>Tue, 10 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/modulabry.umbraco.suite</guid>
                    <title>ModuLabry.Umbraco.Suite</title>
                    <link>https://marketplace.umbraco.com/package/modulabry.umbraco.suite</link>
                    <description><![CDATA[A streamlined property editor suite for Umbraco (verified stable for v14-v17). Includes Enum-driven and simple list components for Dropdowns, Checkboxes and RadioButtons with full localization support.]]></description>
                    <pubDate>Tue, 10 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbracomediasnapshot</guid>
                    <title>UmbracoMediaSnapshot</title>
                    <link>https://marketplace.umbraco.com/package/umbracomediasnapshot</link>
                    <description><![CDATA[Umbraco Media Snapshot adds lightweight media version history to Umbraco by automatically adding a File Version History property (fileVersionHistory) to common media types and creating the required Media Snapshot data type during installation/upgrade.]]></description>
                    <pubDate>Sat, 07 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbracoprism</guid>
                    <title>UmbracoPrism</title>
                    <link>https://marketplace.umbraco.com/package/umbracoprism</link>
                    <description><![CDATA[Multi-tenancy for Umbraco (v17&#x2B;) with dynamic branding and stateless identity. Prism resolves branding, identity, and content context at runtime based on the incoming domain.]]></description>
                    <pubDate>Sat, 07 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@aaronsadleruk/116014085027847668</guid>
                    <title>Umbraco SQL query to get a list of content using Macros in V13</title>
                    <link>https://umbracocommunity.social/@aaronsadleruk/116014085027847668</link>
                    <description><![CDATA[If anyone needs an #Umbraco SQL query to get a list of content using Macros in V13... I&#x27;ve dropped what I&#x27;ve used here:https://gist.github.com/AaronSadlerUK/f2bb83ccaf0b23840f6c06b45e536de1]]></description>
                    <pubDate>Thu, 05 Feb 2026 11:46:34 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://mattbrailsford.dev/introducing-umbraco-ai</guid>
                    <title>Introducing Umbraco AI</title>
                    <link>https://mattbrailsford.dev/introducing-umbraco-ai</link>
                    <description><![CDATA[If you caught the Umbraco Winter keynote webinar, you&#x2019;ll have seen us announce something I&#x2019;ve been working on for a while now - Umbraco AI. I&#x2019;ve...]]></description>
                    <pubDate>Thu, 05 Feb 2026 11:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=OY5YtA3mP5U</guid>
                    <title>Umbraco Highlights 2025</title>
                    <link>https://www.youtube.com/watch?v=OY5YtA3mP5U</link>
                    <description><![CDATA[Creating and updating your website should be the least of your worries. With Umbraco, you get a content management system known and loved for its flexibility and great editing experience.&#xA;&#xA;Umbraco is easy to get started with install, set up, and host it yourself or let us take care of it all for you on Umbraco Cloud. https://try.umbraco.com&#xA;&#xA;Learn more about Umbraco on our website https://umbraco.com&#xA;Discover our Umbraco Community: https://community.umbraco.com/&#xA;Find the Umbraco source code on Github: https://github.com/umbraco/Umbraco-CMS&#xA;Visit the Umbraco Documentation: https://docs.umbraco.com]]></description>
                    <pubDate>Thu, 05 Feb 2026 10:47:52 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=JqLSJJwkj5o</guid>
                    <title>Case Study: Thames Water UK x Umbraco</title>
                    <link>https://www.youtube.com/watch?v=JqLSJJwkj5o</link>
                    <description><![CDATA[How Thames Water built a secure, scalable and high-performance digital platform with Umbraco.&#xA;&#xA;Thames Water, the largest water company in the UK, serves more than 16 million people and relies on a highly available digital platform to support customers during critical situations. In this case study, the team explains why they moved to Umbraco CMS and how the transition improved performance, stability, and cost efficiency.&#xA;&#xA;The video covers Thames Water&#x2019;s gradual migration approach, how risk was reduced during the transition, and how the intuitive editor experience enabled the content team to work efficiently with minimal training. The result is a modern, scalable solution that supports high traffic volumes, improves customer communication, and delivers long-term value through reduced infrastructure and licensing costs.]]></description>
                    <pubDate>Thu, 05 Feb 2026 10:32:55 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=GK-eGhzZYpw</guid>
                    <title>Umbraco Winter Keynote 2026</title>
                    <link>https://www.youtube.com/watch?v=GK-eGhzZYpw</link>
                    <description><![CDATA[At the Winter Keynote 2026, we look back on a strong year for Umbraco and share what&#x2019;s next for the platform, partners, and community.&#xA;&#xA;The keynote covers highlights from 2025, including company growth, product milestones, global expansion, and the continued strength of the Umbraco community. We introduce major announcements such as 24/5 support, a new partner portal, and ISO 27001 certification.&#xA;&#xA;A key focus is Umbraco&#x2019;s approach to AI - built for choice, flexibility, and real-world use - with live demos of new AI capabilities inside Umbraco. The keynote also features the launch of Umbraco Compose, a new data orchestration platform designed to simplify composable architectures at scale.&#xA;&#xA;Finally, we share what&#x2019;s coming next for the CMS, the ecosystem, and the community including events, roadmap highlights, and a look ahead to Codegarden 2026.]]></description>
                    <pubDate>Thu, 05 Feb 2026 08:13:37 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.debasish.tech/blogs/from-umbraco-13-to-17-my-upgrade-journey-and-lessons-learned/</guid>
                    <title>From Umbraco 13 to 17: My Upgrade Journey and Lessons Learned</title>
                    <link>https://www.debasish.tech/blogs/from-umbraco-13-to-17-my-upgrade-journey-and-lessons-learned/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Thu, 05 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/af.umbraco.s3.media.storage</guid>
                    <title>AF.Umbraco.S3.Media.Storage</title>
                    <link>https://marketplace.umbraco.com/package/af.umbraco.s3.media.storage</link>
                    <description><![CDATA[AWS S3 media storage provider for Umbraco 17 (.NET 10). Based on original Our.Umbraco.StorageProviders.AWSS3 project (not compatible with Umbraco 17), the new project is fully refactored, optimized and extended for .NET 10 and Umbraco 17. Includes S3-backed IFileSystem integration, media delivery middleware, ImageSharp provider/cache, localized upload validation and configurable cache-retention cleanup. For ease management, the cache folder replicates the media folder hierarchy, ensuring a one-to-one correspondence between each media folder and its cache folder.]]></description>
                    <pubDate>Thu, 05 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/arroact.umbraco.graphql</guid>
                    <title>Arroact.Umbraco.GraphQL</title>
                    <link>https://marketplace.umbraco.com/package/arroact.umbraco.graphql</link>
                    <description><![CDATA[A powerful GraphQL API package for Umbraco with built-in authentication, interactive IDE dashboard, and comprehensive content/media querying capabilities. Features include lazy loading, BlockGrid support, MultiNodeTreePicker handling, and configurable API key authentication.]]></description>
                    <pubDate>Thu, 05 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/ai-intentionally/</guid>
                    <title>AI, intentionally</title>
                    <link>https://umbraco.com/blog/ai-intentionally/</link>
                    <description><![CDATA[Discover how Umbraco is building AI with purpose, putting choice, governance, and long-term value at the centre of digital experiences.]]></description>
                    <pubDate>Thu, 05 Feb 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=tXdbHn14Gn8</guid>
                    <title>Umbraco Compose example project</title>
                    <link>https://www.youtube.com/watch?v=tXdbHn14Gn8</link>
                    <description><![CDATA[YouTube: Umbraco Compose example project: https://www.youtube.com/watch?v=tXdbHn14Gn8&#xA;]]></description>
                    <pubDate>Wed, 04 Feb 2026 09:22:23 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://dev.to/jasonelkin/mitigating-cve-2025-67288-in-umbraco-13-if-you-feel-you-need-to-bl3</guid>
                    <title>Mitigating CVE-2025-67288 in Umbraco 13 (if you feel you need to)</title>
                    <link>https://dev.to/jasonelkin/mitigating-cve-2025-67288-in-umbraco-13-if-you-feel-you-need-to-bl3</link>
                    <description><![CDATA[&lt;p&gt;Firstly, this is a really ill-informed CVE. If you&#x27;ve not read &lt;a href=&quot;https://forum.umbraco.com/t/cve-2025-67288-and-v13/7079/6?u=jasonelkin&quot; rel=&quot;noopener noreferrer&quot;&gt;my comment on the Umbraco Forum&lt;/a&gt;, I&#x27;ll repeat the key bits, otherwise feel free to scroll down to the good stuff.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  A bit about CVE-2025-67288&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;If you want the details you can read the full CVE at &lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2025-67288&quot; rel=&quot;noopener noreferrer&quot;&gt;nvd.nist.gov&lt;/a&gt;. Umbraco is in the process of disputing it.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Let me break down why I think it&#x27;s mostly nonsense...&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Remote Code Execution?&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;It&#x2019;s an attention grabbing PoC..&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Upload a crafted PDF file containing embedded JavaScript.&lt;/li&gt;&#xA;&lt;li&gt;Observe that JavaScript from the PDF executes in the browser.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;But what does Umbraco have to do with that? You could upload the file anywhere - in fact, and click this link if you dare, &lt;a href=&quot;https://jasonelkin.github.io/docs/pdfs/success_xss.pdf&quot; rel=&quot;noopener noreferrer&quot;&gt;I&#x27;ve uploaded that file to a GitHub pages site&lt;/a&gt;.&lt;br&gt;&#xA;Does that mean GitHub is vulnerable to a CWE-434&#x2026;? No, and neither is Umbraco.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This is what a &lt;a href=&quot;https://cwe.mitre.org/data/definitions/434.html&quot; rel=&quot;noopener noreferrer&quot;&gt;CWE-434&lt;/a&gt; means...&lt;/p&gt;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The product allows the upload or transfer of dangerous file types that are &lt;strong&gt;automatically processed within its environment&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;p&gt;Emphasis mine, but this &quot;CVE&quot; doesn&#x2019;t pass that test. Umbraco doesn&#x27;t process the PDF such that arbitrary code can be run on your Umbraco site.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;So, remote code execution worthy a CVSS score of 10.0? No.&lt;/p&gt;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Is is really XSS?&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Look more closely at the XSS (Cross Site Scripting) claim. Where does the JavaScript actually run? In the browser, sure, but it&#x2019;s not run in the context of the Umbraco site (or GitHub.io, if you were brave and clicked the link above). It&#x2019;s sandboxed by the browser and not treated like it&#x2019;s running on your domain at all.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This is such a common misconception that Chromium has an FAQ titled &quot;Does executing JavaScript in a PDF file mean there&#x27;s an XSS vulnerability?&quot;. Spoiler alert, &lt;a href=&quot;https://chromium.googlesource.com/chromium/src/&#x2B;/HEAD/docs/security/faq.md#Does-executing-JavaScript-in-a-PDF-file-mean-there_s-an-XSS-vulnerability&quot; rel=&quot;noopener noreferrer&quot;&gt;the answer is no&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  It&#x27;s JavaScript, but not as we know it&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;It doesn&#x2019;t have access to any important browser APIs - i.e. no fetch() or document.cookies etc. in fact if you look at the alert itself you&#x2019;ll see it&#x2019;s calling app.alert()&#x2026; that&#x2019;s not a web browser API but a PDF one :face_with_monocle:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;If you try and craft a more complex JavaScript payload you&#x2019;ll quickly find that the browser will block any APIs that could present a real risk to the user.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Even if you could craft malicious JavaScript that executes in a browser, that CVE would really be the browser&#x2019;s problem, not Umbraco&#x2019;s.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;If you&#x27;re feeling extra nerdy, you can &lt;a href=&quot;https://docs.google.com/document/d/1olIb-1IFVqP2fLTq0eAdW-aL-K2dDDZGDe5mZgHGfO8/edit?tab=t.0#heading=h.wwlum47z8pg1&quot; rel=&quot;noopener noreferrer&quot;&gt;have a read of the design doc for the PDF Viewer in Chromium&lt;/a&gt;. It talks about sandboxing, what kinds of JavaScript execution are allowed, and why.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Obviously there&#x2019;s still a potential social engineering/phishing angle with these crafted PDFs&#x2026; but that&#x2019;s a whole different issue.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;But good news, you can still mitigate against it!&lt;/p&gt;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Enter the IFileStreamSecurityAnalyzer&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;It&#x27;s a simple interface you can implement that Umbraco will then run uploaded filestreams through so you can add any logic you want to check if the files are safe.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IFileStreamSecurityAnalyzer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;/// Indicates whether the analyzer should process the file&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;/// The implementation should be considerably faster than IsConsideredSafe&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;/// &amp;lt;param name=&quot;fileStream&quot;&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;&#xA;    &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ShouldHandle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;c1&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;/// Analyzes whether the file content is considered safe&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;/// &amp;lt;param name=&quot;fileStream&quot;&amp;gt;Needs to be a Read/Write seekable stream&amp;lt;/param&amp;gt;&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;/// &amp;lt;returns&amp;gt;Whether the file is considered safe&amp;lt;/returns&amp;gt;&lt;/span&gt;&#xA;    &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IsConsideredSafe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;The docs &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/reference/security/serverside-file-validation&quot; rel=&quot;noopener noreferrer&quot;&gt;have a nice example&lt;/a&gt; showing you how to protect against a potentially malicious SVG file.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;In a similar fashion we can implement our own class that will read a PDF&amp;lt; look for any JavaScript, and return false when &lt;code&gt;IsConsideredSafe()&lt;/code&gt; is called.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Notice the &lt;code&gt;ShouldHandle()&lt;/code&gt; method only takes the stream. File extensions don&#x27;t necessarily match up with what&#x27;s actually in a file so we need to check the contents first to see if this is actually a PDF. A quick way of doing that is to parse just the file signature in the file header.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;There&#x27;s a &lt;a href=&quot;https://github.com/neilharvey/FileSignatures/&quot; rel=&quot;noopener noreferrer&quot;&gt;package for that&lt;/a&gt;!&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;dotnet add package FileSignatures&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Then for the PDF reading, I&#x27;m using &lt;a href=&quot;https://uglytoad.github.io/PdfPig/&quot; rel=&quot;noopener noreferrer&quot;&gt;PdfPig&lt;/a&gt;:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;dotnet add package PdfPig&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Here I need to add a disclaimer. The following code is based on something I&#x27;m using in production but the PDF library I&#x27;m using has rather restrictive/expensive licensing and I wanted to give you a demo that &quot;Just Works&quot; with some friendly OSS libraries - so I asked AI to help me rewrite this for PdfPig.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PdfSecurityAnalyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;ILogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PdfSecurityAnalyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;IFileFormatInspector&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileFormatInspector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IFileStreamSecurityAnalyzer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HashSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_suspiciousKeys&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;        &lt;span class=&quot;s&quot;&gt;&quot;AA&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;// Additional Actions&lt;/span&gt;&#xA;        &lt;span class=&quot;s&quot;&gt;&quot;OpenAction&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// Actions triggered on document open&lt;/span&gt;&#xA;        &lt;span class=&quot;s&quot;&gt;&quot;JS&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;// JavaScript Stream&lt;/span&gt;&#xA;        &lt;span class=&quot;s&quot;&gt;&quot;JavaScript&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// Explicit JavaScript name&lt;/span&gt;&#xA;        &lt;span class=&quot;s&quot;&gt;&quot;Launch&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;// Launch external applications&lt;/span&gt;&#xA;        &lt;span class=&quot;s&quot;&gt;&quot;SubmitForm&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// Form submission (potential data exfiltration)&lt;/span&gt;&#xA;        &lt;span class=&quot;s&quot;&gt;&quot;ImportData&quot;&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// Import external data&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IsConsideredSafe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;fileStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Position&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ParsingOptions&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UseLenientParsing&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;            &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visited&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HashSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IndirectReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;&#xA;&#xA;            &lt;span class=&quot;c1&quot;&gt;// Check the entire document structure starting from catalog&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ContainsSuspiciousContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Structure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Catalog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CatalogDictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;LogWarning&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Failed to parse PDF for security analysis&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ContainsSuspiciousContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IToken&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfDocument&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HashSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IndirectReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;token&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;DictionaryToken&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dict&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CheckDictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;ArrayToken&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CheckArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;IndirectReferenceToken&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;refToken&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CheckIndirectReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;refToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;StreamToken&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ContainsSuspiciousContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StreamDictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;ObjectToken&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;objToken&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ContainsSuspiciousContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CheckDictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DictionaryToken&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfDocument&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HashSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IndirectReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;c1&quot;&gt;// Check for suspicious keys&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keyName&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_suspiciousKeys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keyName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;            &lt;span class=&quot;c1&quot;&gt;// Subtype Check: /S /JavaScript&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keyName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;S&quot;&lt;/span&gt; &#xA;                &lt;span class=&quot;p&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TryGet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NameToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NameToken&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subtype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;                &lt;span class=&quot;p&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subtype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;JavaScript&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;c1&quot;&gt;// Recurse into all dictionary values&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ContainsSuspiciousContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CheckArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ArrayToken&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfDocument&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HashSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IndirectReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ContainsSuspiciousContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CheckIndirectReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IndirectReferenceToken&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;refToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfDocument&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HashSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IndirectReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;refToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;n&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;refToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actualToken&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Structure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;refToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ContainsSuspiciousContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;actualToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ShouldHandle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileFormatInspector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DetermineFileFormat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Pdf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;And then to register it, use an IComposer:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RegisterFileStreamSecurityAnalysers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComposer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Compose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IUmbracoBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recognised&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FileFormatLocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetFormats&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OfType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pdf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inspector&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;FileFormatInspector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recognised&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddSingleton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IFileFormatInspector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inspector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddSingleton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IFileStreamSecurityAnalyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PdfSecurityAnalyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Notice I&#x27;m configuring the &lt;code&gt;FileFormatInspector&lt;/code&gt; to only look for PDFs, which is better for performance but you can add multiple file types or configure it to look for all types known by the library - have a look at &lt;a href=&quot;https://github.com/neilharvey/FileSignatures/&quot; rel=&quot;noopener noreferrer&quot;&gt;the GitHub Repo&lt;/a&gt; for more info.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;With the above code implemented, try and upload a PDF containing JavaScript (like the perfectly benign one I linked to above), and you&#x27;ll get this lovely error message.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiyn5khiy0wekqkl8fx7b.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiyn5khiy0wekqkl8fx7b.png&quot; alt=&quot; &quot; width=&quot;800&quot; height=&quot;248&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;You may get some false positives, but this was all about false positives really, wasn&#x27;t it...&lt;/p&gt;]]></description>
                    <pubDate>Wed, 04 Feb 2026 02:49:57 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.prompt.web</guid>
                    <title>Umbraco.AI.Prompt.Web</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.prompt.web</link>
                    <description><![CDATA[Management API for Umbraco AI Prompt]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/jumoo.translationmanager.umbracoai</guid>
                    <title>Jumoo.TranslationManager.UmbracoAi</title>
                    <link>https://marketplace.umbraco.com/package/jumoo.translationmanager.umbracoai</link>
                    <description><![CDATA[UmbracoAi Connector for Jumoo.TranslationManager]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/february/upgrading-umbraco-13-to-umbraco-17-issue/</guid>
                    <title>Upgrading Umbraco 13 to Umbraco 17 issue</title>
                    <link>https://33b6c16b-3387-4d68-9090-4cb1f20ea7b3.azurewebsites.nethttps://owain.codes/blog/2026/february/upgrading-umbraco-13-to-umbraco-17-issue/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.agent.persistence</guid>
                    <title>Umbraco.AI.Agent.Persistence</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.agent.persistence</link>
                    <description><![CDATA[EF Core persistence layer for Umbraco AI Agent]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.agent.web</guid>
                    <title>Umbraco.AI.Agent.Web</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.agent.web</link>
                    <description><![CDATA[Management API for Umbraco AI Agent]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.prompt.startup</guid>
                    <title>Umbraco.AI.Prompt.Startup</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.prompt.startup</link>
                    <description><![CDATA[Startup and DI registration for Umbraco AI Prompt]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.prompt.persistence.sqlserver</guid>
                    <title>Umbraco.AI.Prompt.Persistence.SqlServer</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.prompt.persistence.sqlserver</link>
                    <description><![CDATA[SQL Server migrations for Umbraco AI Prompt]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.startup</guid>
                    <title>Umbraco.AI.Startup</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.startup</link>
                    <description><![CDATA[Contains startup logic for Umbraco AI]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.prompt.persistence</guid>
                    <title>Umbraco.AI.Prompt.Persistence</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.prompt.persistence</link>
                    <description><![CDATA[EF Core persistence layer for Umbraco AI Prompt]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.prompt.persistence.sqlite</guid>
                    <title>Umbraco.AI.Prompt.Persistence.Sqlite</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.prompt.persistence.sqlite</link>
                    <description><![CDATA[SQLite migrations for Umbraco AI Prompt]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.persistence</guid>
                    <title>Umbraco.AI.Persistence</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.persistence</link>
                    <description><![CDATA[EF Core persistence layer for Umbraco AI]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.core</guid>
                    <title>Umbraco.AI.Core</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.core</link>
                    <description><![CDATA[Contains core logic for Umbraco AI]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.persistence.sqlserver</guid>
                    <title>Umbraco.AI.Persistence.SqlServer</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.persistence.sqlserver</link>
                    <description><![CDATA[SQL Server migrations for Umbraco AI persistence]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.prompt.core</guid>
                    <title>Umbraco.AI.Prompt.Core</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.prompt.core</link>
                    <description><![CDATA[Core domain models and services for Umbraco AI Prompt]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.agent.persistence.sqlite</guid>
                    <title>Umbraco.AI.Agent.Persistence.Sqlite</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.agent.persistence.sqlite</link>
                    <description><![CDATA[SQLite migrations for Umbraco AI Agent]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.agent.startup</guid>
                    <title>Umbraco.AI.Agent.Startup</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.agent.startup</link>
                    <description><![CDATA[Startup and DI registration for Umbraco AI Agent]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/february/upgrading-umbraco-13-to-umbraco-17-issue/</guid>
                    <title>Upgrading Umbraco 13 to Umbraco 17 issue</title>
                    <link>https://owain.codes/blog/2026/february/upgrading-umbraco-13-to-umbraco-17-issue/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.persistence.sqlite</guid>
                    <title>Umbraco.AI.Persistence.Sqlite</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.persistence.sqlite</link>
                    <description><![CDATA[SQLite migrations for Umbraco AI persistence]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.web</guid>
                    <title>Umbraco.AI.Web</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.web</link>
                    <description><![CDATA[Management API for Umbraco AI]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.agent.core</guid>
                    <title>Umbraco.AI.Agent.Core</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.agent.core</link>
                    <description><![CDATA[Core domain models and services for Umbraco AI Agent]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.agent.persistence.sqlserver</guid>
                    <title>Umbraco.AI.Agent.Persistence.SqlServer</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.agent.persistence.sqlserver</link>
                    <description><![CDATA[SQL Server migrations for Umbraco AI Agent]]></description>
                    <pubDate>Wed, 04 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=KpwlMLOf14o</guid>
                    <title>Umbraco Compose Unboxing</title>
                    <link>https://www.youtube.com/watch?v=KpwlMLOf14o</link>
                    <description><![CDATA[Umbraco Compose eases the management of data flows in complex enterprise projects. &#xA;&#xA;It&#x2019;s the &#x201C;in between&#x201D; data orchestration layer between your tech stack and your frontend(s) that ensures clean and streamlined connections, freeing you from hours of setting up custom endpoints, ongoing maintenance, and time-consuming debugging.  &#xA;&#xA;In this unboxing video, Lasse and Allen provide you with a technical deep dive into how Umbraco Compose works.]]></description>
                    <pubDate>Tue, 03 Feb 2026 15:45:36 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=fgc8w85hbP0</guid>
                    <title>Umbraco Compose - From Complexity to Clarity</title>
                    <link>https://www.youtube.com/watch?v=fgc8w85hbP0</link>
                    <description><![CDATA[No more &quot;Spaghetti Knot&quot; Architecture. With Umbraco Compose, you can build Clean Composable Architecture. &#xA;&#xA;Some call it data orchestration. Others, a fully managed backend-for-frontend. We call it Umbraco Compose.&#xA;&#xA;Learn more about Umbraco Compose here: www.umbraco/compose.com]]></description>
                    <pubDate>Tue, 03 Feb 2026 15:45:22 Z</pubDate>
                        <category>hq</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://skrift.io/issues/#124</guid>
                    <title>Skrift Issue #124</title>
                    <link>https://skrift.io/issues/#124</link>
                    <description><![CDATA[Featuring guest posts by Nathaniel Nunes on &quot;Using Serilog Enrichers with Umbraco&quot; and Georgina Bidder on &quot;Not Your Usual Compliance Monitoring Tool&quot;]]></description>
                    <pubDate>Tue, 03 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                        <category>skrift</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.commerce.paymentproviders.kustom</guid>
                    <title>Umbraco.Commerce.PaymentProviders.Kustom</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.commerce.paymentproviders.kustom</link>
                    <description><![CDATA[Kustom payment provider for Umbraco Commerce]]></description>
                    <pubDate>Tue, 03 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.prompt</guid>
                    <title>Umbraco.AI.Prompt</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.prompt</link>
                    <description><![CDATA[Prompt management plugin for Umbraco AI]]></description>
                    <pubDate>Tue, 03 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/introducing-umbraco-compose/</guid>
                    <title>Introducing Umbraco Compose</title>
                    <link>https://umbraco.com/blog/introducing-umbraco-compose/</link>
                    <description><![CDATA[We&#x2019;re proud to launch our new Data Orchestration Platform: Umbraco Compose. A platform that&#x2019;ll ease the management of data flows in complex enterprise projects. Discover how Compose can save you hundreds of development hours and struggles.]]></description>
                    <pubDate>Tue, 03 Feb 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/uheroslider</guid>
                    <title>uHeroSlider</title>
                    <link>https://marketplace.umbraco.com/package/uheroslider</link>
                    <description><![CDATA[A commercial-grade, advanced hero slider solution for Umbraco 17&#x2B;. Features image/video support, custom animations per slide, scheduling with timezone support, festival scheduling, auto-slide, loop controls, and fallback images.]]></description>
                    <pubDate>Tue, 03 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.openai</guid>
                    <title>Umbraco.AI.OpenAI</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.openai</link>
                    <description><![CDATA[OpenAI provider for Umbraco AI]]></description>
                    <pubDate>Tue, 03 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.google</guid>
                    <title>Umbraco.AI.Google</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.google</link>
                    <description><![CDATA[Google provider for Umbraco AI]]></description>
                    <pubDate>Tue, 03 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai</guid>
                    <title>Umbraco.AI</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai</link>
                    <description><![CDATA[Umbraco AI]]></description>
                    <pubDate>Tue, 03 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.agent</guid>
                    <title>Umbraco.AI.Agent</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.agent</link>
                    <description><![CDATA[Agent management plugin for Umbraco AI]]></description>
                    <pubDate>Tue, 03 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.anthropic</guid>
                    <title>Umbraco.AI.Anthropic</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.anthropic</link>
                    <description><![CDATA[Anthropic provider for Umbraco AI]]></description>
                    <pubDate>Tue, 03 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.microsoftfoundry</guid>
                    <title>Umbraco.AI.MicrosoftFoundry</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.microsoftfoundry</link>
                    <description><![CDATA[Microsoft AI Foundry provider for Umbraco AI]]></description>
                    <pubDate>Tue, 03 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.ai.amazon</guid>
                    <title>Umbraco.AI.Amazon</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.ai.amazon</link>
                    <description><![CDATA[Amazon Bedrock provider for Umbraco AI]]></description>
                    <pubDate>Tue, 03 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://mattbrailsford.dev/http-over-named-pipes</guid>
                    <title>Solving Port Conflicts in AI-Assisted Development: HTTP over Named Pipes</title>
                    <link>https://mattbrailsford.dev/http-over-named-pipes</link>
                    <description><![CDATA[The way I work day to day has changed quite a lot over the last 6 months.&#xA;AI coding assistants like Claude Code aren&#x2019;t just speeding up individual...]]></description>
                    <pubDate>Mon, 02 Feb 2026 19:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.nuget.org/packages/Umbraco.Community.UmbNav</guid>
                    <title>UmbNav 4.1.0 for Umbraco V17&#x2B;</title>
                    <link>https://www.nuget.org/packages/Umbraco.Community.UmbNav</link>
                    <description><![CDATA[UmbNav 4.1.0 for Umbraco V17&#x2B; is here!&#xA;&#xA;This update is a biggy:&#xA;&#x2705; Enhances drag and drop functionality.&#xA;&#x2705; Reworks the menu service.&#xA;&#x2705; Simplifies extension points.&#xA;&#x2705; Implements package migration for legacy data format.&#xA;&#x2705; Adds unit tests for increased code reliability.&#xA;&#x2705; Introduces code analysis and review workflows.&#xA;&#x2705; Bumps version number to 4.1.0.&#xA;&#x2705; IsActive extension method overhauled&#xA;&#xA;h5yr to hotchillicode  for the migration PR!&#xA;&#xA;Grab it here:&#xA;https://www.nuget.org/packages/Umbraco.Community.UmbNav]]></description>
                    <pubDate>Mon, 02 Feb 2026 13:10:16 Z</pubDate>
                        <category>community</category>
                        <category>nuget</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://dev.to/skttl/customizing-umbraco-modelsbuilder-output-1243</guid>
                    <title>Customizing Umbraco ModelsBuilder Output</title>
                    <link>https://dev.to/skttl/customizing-umbraco-modelsbuilder-output-1243</link>
                    <description><![CDATA[&lt;p&gt;Umbraco&#x27;s ModelsBuilder is a fantastic tool that generates strongly-typed models from your document types. But what if you want to customize the generated output? Maybe you want to add property alias constants or other custom code to your models.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;In this article, I&#x27;ll show you how to create a custom &lt;code&gt;ModelsGenerator&lt;/code&gt; that post-processes the generated files to add your own customizations.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The Problem&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;When working with Umbraco, you often need to reference property aliases as strings - for example, when using &lt;code&gt;SetValue()&lt;/code&gt; while creating or editing content through the ContentService, or maybe you need the dynamic property access from &lt;code&gt;IPublishedContent&lt;/code&gt;. This means scattering magic strings throughout your codebase:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// setting a property value on IContent&lt;/span&gt;&#xA;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pageTitle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;New Title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;c1&quot;&gt;// checking for a property on IPublishedContent&lt;/span&gt;&#xA;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;items&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Children&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;HasValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;featuredImage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;If a property alias changes, you&#x27;ll need to hunt down every occurrence. It would be much better to have strongly-typed constants for each property alias, so you get compile-time safety and IntelliSense support.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;ModelsBuilder does provide a way to get the property aliases from the document type, but it is rather verbose, and it requires a dependency on &lt;code&gt;IPublishedContentTypeCache&lt;/code&gt;:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;@using&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Umbraco&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Cms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PublishedCache&lt;/span&gt;&#xA;&lt;span class=&quot;n&quot;&gt;@inject&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IPublishedContentTypeCache&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_contentTypeCache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blocksPropertyAlias&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ContentPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetModelPropertyType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_contentTypeCache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Blocks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)?.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The Solution&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;We can create a custom &lt;code&gt;ModelsGenerator&lt;/code&gt; that runs after the standard generation and post-processes the output files. This approach:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Doesn&#x27;t require modifying Umbraco&#x27;s source code&lt;/li&gt;&#xA;&lt;li&gt;Works with the existing ModelsBuilder pipeline&lt;/li&gt;&#xA;&lt;li&gt;Allows for any kind of text manipulation on generated files&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;Here&#x27;s the full implementation:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Microsoft.Extensions.Hosting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Microsoft.Extensions.Options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Text.RegularExpressions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Umbraco.Cms.Core.Configuration.Models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Umbraco.Cms.Infrastructure.ModelsBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Umbraco.Cms.Infrastructure.ModelsBuilder.Building&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Umbraco.Extensions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;MyProject.ModelsGenerators&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyOwnModelsGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;UmbracoServices&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;umbracoService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;IOptionsMonitor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelsBuilderSettings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;OutOfDateModelsStatus&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outOfDateModels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;n&quot;&gt;IHostEnvironment&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hostingEnvironment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ModelsGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;umbracoService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outOfDateModels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hostingEnvironment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IModelsGenerator&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GenerateModels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GenerateModels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;modelsDirectory&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CurrentValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ModelsDirectoryAbsolute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hostingEnvironment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Exists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;modelsDirectory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetFiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;modelsDirectory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;*.generated.cs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileContents&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ReadAllText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;            &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newFileContents&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AddPropertyAliasConstants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newFileContents&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteAllText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newFileContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AddPropertyAliasConstants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;marker&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;public new const string ModelTypeAlias =&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;IndexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;marker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StringComparison&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ordinal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&quot;\[.*ImplementPropertyType\(&quot;&quot;([^&quot;&quot;]&#x2B;)&quot;&quot;\)\][\s\S]*?public\s&#x2B;(?:virtual\s&#x2B;)?[\w\.:&amp;lt;&amp;gt;]&#x2B;\s&#x2B;([A-Za-z0-9_]&#x2B;)\s*(?:{|=&amp;gt;)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matches&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Regex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Matches&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sb&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;StringBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;sb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;public new static class ModelPropertyAliases\n\t\t{\n&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;            &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;propName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;sb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;\t\t\tpublic const string &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;propName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; = \&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;\&quot;;\n&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;sb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;\t\t}\n\n\t\t&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Insert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  How It Works&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The custom generator does a few key things:&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  1. Inheriting from ModelsGenerator&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;By inheriting from &lt;code&gt;ModelsGenerator&lt;/code&gt; and implementing &lt;code&gt;IModelsGenerator&lt;/code&gt;, we can override the generation behavior while still using all the built-in functionality.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyOwnModelsGenerator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ModelsGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IModelsGenerator&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  2. Post-Processing Generated Files&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;The &lt;code&gt;GenerateModels()&lt;/code&gt; method first calls &lt;code&gt;base.GenerateModels()&lt;/code&gt; to run the standard generation, then iterates through all &lt;code&gt;*.generated.cs&lt;/code&gt; files to apply our customizations:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GenerateModels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GenerateModels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;modelsDirectory&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ModelsDirectoryAbsolute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_hostingEnvironment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetFiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;modelsDirectory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;*.generated.cs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;c1&quot;&gt;// Post-process each file...&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  3. Adding Property Alias Constants&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;The &lt;code&gt;AddPropertyAliasConstants&lt;/code&gt; method uses regex to find all properties marked with &lt;code&gt;[ImplementPropertyType]&lt;/code&gt; and extracts both the alias and property name. It then generates a nested static class containing constants for each property:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ModelPropertyAliases&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PageTitle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;pageTitle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FeaturedImage&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;featuredImage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Blocks&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;blocks&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Registering the Custom Generator&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;To use your custom generator, you need to register it with Umbraco&#x27;s dependency injection. Add this to your startup configuration:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddSingleton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IModelsGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MyOwnModelsGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Or if you&#x27;re using a composer:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ModelsGeneratorComposer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComposer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Compose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IUmbracoBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddSingleton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IModelsGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MyOwnModelsGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Using the Generated Constants&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Once the models are regenerated, you can use the constants throughout your code:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Before: magic strings&lt;/span&gt;&#xA;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pageTitle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;New Title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;c1&quot;&gt;// After: strongly-typed constants&lt;/span&gt;&#xA;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HomePage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelPropertyAliases&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PageTitle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;New Title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;c1&quot;&gt;// Works great in LINQ queries too&lt;/span&gt;&#xA;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;featured&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Children&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;HasValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Article&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelPropertyAliases&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FeaturedImage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Now if a property alias changes, you&#x27;ll get a compile-time error instead of a runtime surprise.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Final Thoughts&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Customizing ModelsBuilder output gives you more control over your generated code without fighting against the built-in tooling. By post-processing the generated files, you can add compile-time safety features like property alias constants while keeping all the benefits of automatic model generation.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The approach shown here - inheriting from &lt;code&gt;ModelsGenerator&lt;/code&gt; and processing files after generation - is clean, maintainable, and survives Umbraco upgrades since it doesn&#x27;t modify any core code.&lt;/p&gt;]]></description>
                    <pubDate>Mon, 02 Feb 2026 11:33:05 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://kjac.dev/posts/umbraco-media-search-with-azure-ai-vision/</guid>
                    <title>Umbraco media search with Azure AI Vision</title>
                    <link>https://kjac.dev/posts/umbraco-media-search-with-azure-ai-vision/</link>
                    <description><![CDATA[Integrating Azure AI Vision and Umbraco Search to implement image content search powered by image recognition.]]></description>
                    <pubDate>Mon, 02 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.customvalidator</guid>
                    <title>Umbraco.Community.CustomValidator</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.customvalidator</link>
                    <description><![CDATA[A comprehensive document validation framework for Umbraco CMS that provides real-time content validation with a backoffice UI. Display validation results directly in the Umbraco backoffice with support for multi-culture content, severity levels (Error, Warning, Info), and automatic publish blocking when errors are present.]]></description>
                    <pubDate>Mon, 02 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/ai.diagnostics</guid>
                    <title>AI.Diagnostics</title>
                    <link>https://marketplace.umbraco.com/package/ai.diagnostics</link>
                    <description><![CDATA[AI Diagnostics analyzes application logs using AI to simplify complex issues by identifying possible root causes and providing actionable suggestions to fix them.]]></description>
                    <pubDate>Sun, 01 Feb 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/arrosimpleform</guid>
                    <title>ArroSimpleForm</title>
                    <link>https://marketplace.umbraco.com/package/arrosimpleform</link>
                    <description><![CDATA[Arro Simple Form is a tool that allows Umbraco users to create dynamic forms without writing code and integrate them into their Umbraco websites. It saves user-submitted data and can automatically send emails upon form submission.]]></description>
                    <pubDate>Sat, 31 Jan 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/djretailing.umbraco.suite</guid>
                    <title>DJRetailing.Umbraco.Suite</title>
                    <link>https://marketplace.umbraco.com/package/djretailing.umbraco.suite</link>
                    <description><![CDATA[A streamlined property editor suite for Umbraco (verified stable for v14-v17). Includes Enum-driven and simple list components for Dropdowns, Checkboxes and RadioButtons with full localization support.]]></description>
                    <pubDate>Sat, 31 Jan 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=Z8N-dXWdq04</guid>
                    <title>umbraCoffee - New Year, new U?!</title>
                    <link>https://www.youtube.com/watch?v=Z8N-dXWdq04</link>
                    <description><![CDATA[Welcome to your monthly dose of #umbraCoffee&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;&#x200B;! Your hosts - Marcin and Callum - together with their guest(s) will drive through all of the community news and happenings in the Umbraco world. So... grab a cuppa, join us LIVE and enjoy!&#xA;&#xA;See ya?!&#xA;&#xA;---&#xA;&#x2615; Wanna buy us a coffee/pizza/donuts?&#xA;https://www.buymeacoffee.com/umbracoffee&#xA;---&#xA;&#xA;Notes:&#xA;&#xA;// TODO]]></description>
                    <pubDate>Fri, 30 Jan 2026 11:00:08 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/@umbraco-cms/mcp-dev</guid>
                    <title>@umbraco-cms/mcp-dev</title>
                    <link>https://marketplace.umbraco.com/package/@umbraco-cms/mcp-dev</link>
                    <description><![CDATA[An MCP (Model Context Protocol) server for Umbraco CMS that unlocks AI-powered content management via the Umbraco Management API.]]></description>
                    <pubDate>Fri, 30 Jan 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.debasish.tech/blogs/handling-editor-injected-javascript-in-umbraco-v17-with-umbracocommunitycspmanager/</guid>
                    <title>Handling editor-injected JavaScript in Umbraco v17 with Umbraco.Community.CSPManager</title>
                    <link>https://www.debasish.tech/blogs/handling-editor-injected-javascript-in-umbraco-v17-with-umbracocommunitycspmanager/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 30 Jan 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.debasish.tech/blogs/handling-editor-injected-javascript-in-umbraco-v17-with-umbraco-community-cspmanager/</guid>
                    <title>Handling editor-injected JavaScript in Umbraco v17 with Umbraco Community CSPManager</title>
                    <link>https://www.debasish.tech/blogs/handling-editor-injected-javascript-in-umbraco-v17-with-umbraco-community-cspmanager/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 30 Jan 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.nuget.org/packages/Our.Umbraco.TagHelpers/2.0.0</guid>
                    <title>TagHelpers v2.0.0 with Umbraco v16&#x2B; support</title>
                    <link>https://www.nuget.org/packages/Our.Umbraco.TagHelpers/2.0.0</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Thu, 29 Jan 2026 10:02:29 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>nuget</category>
                </item>
                <item>
                    <guid>https://www.jeroenbreuer.nl/blog/released-umbraco-compose-example-project</guid>
                    <title>Released: Umbraco Compose example project</title>
                    <link>https://www.jeroenbreuer.nl/blog/released-umbraco-compose-example-project</link>
                    <description><![CDATA[Released: Umbraco Compose example project - jeroenbreuer.nl]]></description>
                    <pubDate>Thu, 29 Jan 2026 08:03:27 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://discord.com/channels/869656431308189746/882981290662580264/1465425940669792502</guid>
                    <title>Find the right Umbraco icon with &quot;Umbraco Iconomancer&quot;</title>
                    <link>https://discord.com/channels/869656431308189746/882981290662580264/1465425940669792502</link>
                    <description><![CDATA[While fondly remembering going to the ucreate umbraco icons github page,&#xA;I did some digressing today trying to make the process of &quot;finding-the-right-icon&#x2122;&quot; even more enjoyable.&#xA;Meet the &quot;Umbraco Iconomancer&quot;, a Custom GPT with the sole purpose&#xA;of making your &quot;finding-the-right-icon&#x2122;&quot; experience umbazing. &#x1F601;&#x1F92D;&#xA;https://chatgpt.com/g/g-697788bd87888191aefe76e552c70820-umbraco-iconomancer]]></description>
                    <pubDate>Tue, 27 Jan 2026 17:24:19 Z</pubDate>
                        <category>community</category>
                        <category>discord</category>
                </item>
                <item>
                    <guid>https://dev.to/iovergaard/packagejson-as-single-source-of-truth-how-umbraco-auto-generates-typescript-paths-and-browser-101k</guid>
                    <title>Package.json as Single Source of Truth: How Umbraco Auto-Generates TypeScript Paths and Browser Import Maps</title>
                    <link>https://dev.to/iovergaard/packagejson-as-single-source-of-truth-how-umbraco-auto-generates-typescript-paths-and-browser-101k</link>
                    <description><![CDATA[&lt;h2&gt;&#xA;  &#xA;  &#xA;  Summary&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Building an extensible web application with 120&#x2B; shared packages creates a unique challenge: the same import must resolve to different locations during development (TypeScript source files), build time (external dependencies), and runtime (browser-served files). Traditional approaches require maintaining this mapping in three different config formats - TypeScript paths, test runner, and browser import maps - leading to inevitable configuration drift and an entire class of &quot;works in dev, breaks in production&quot; bugs.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Umbraco CMS solves this through code generation: treating package.json exports as a single source of truth and automatically generating all configurations from it. A 200-line transformation script reads the exports field and produces TypeScript paths (with dist-cms &#x2192; src transformations), browser import maps (with dist-cms &#x2192; /umbraco/backoffice/ transformations), and test runner configs - all from one edit point. This makes configuration drift architecturally impossible: if TypeScript can find it, the browser can load it.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The result is a pattern that scales to 120&#x2B; packages while maintaining correctness guarantees, enabling internal refactoring without breaking consumers, and providing the foundation for a professional, extensible package system built on web standards.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The Problem with Raw File Paths&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;When building extensions for Umbraco&#x27;s backoffice, you&#x27;ve probably written code like this:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UmbElementMixin&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@umbraco-cms/backoffice/element-api&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UMB_NOTIFICATION_CONTEXT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@umbraco-cms/backoffice/notification&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;But have you ever wondered how this actually works?&lt;/p&gt;&#xA;&#xA;&lt;p&gt;You DO install the &lt;code&gt;@umbraco-cms/backoffice&lt;/code&gt; NPM package for types, yet the browser doesn&#x27;t load code from &lt;code&gt;node_modules&lt;/code&gt;. Instead, it loads from the Umbraco server. How does TypeScript know about the types during development, while the browser loads different files at runtime?&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This is the &lt;strong&gt;dual-resolution problem&lt;/strong&gt; - the same import must resolve to different locations at development time versus runtime. Umbraco solves it elegantly through a three-layer implementation combining TypeScript paths, Vite&#x27;s external configuration, and browser import maps.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The Traditional Approach (And Why It&#x27;s Problematic)&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Before Umbraco 14, you might have seen Umbraco extensions written with AngularJS having magical service injections based on strings like this:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// &#x274C; Old approach: magic strings (entityService)&lt;/span&gt;&#xA;&lt;span class=&quot;nx&quot;&gt;angular&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;umbraco&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;directive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;function &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;entityService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;// Do work with entityService&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;You may even have imported modules of your own by virtue of Require.js or similar:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// &#x274C; Old approach: raw file paths&lt;/span&gt;&#xA;&lt;span class=&quot;nf&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/App_Plugins/MyPackage/utils.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;This works, but it has several problems:&lt;/p&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Brittle&lt;/strong&gt;: If you move files, all imports break&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Exposes Implementation&lt;/strong&gt;: Everyone sees your internal file structure&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Not Refactorable&lt;/strong&gt;: IDEs can&#x27;t help you rename or move things&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Unprofessional&lt;/strong&gt;: Looks like a hack rather than proper module architecture&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Hard to Type&lt;/strong&gt;: TypeScript struggles to provide IntelliSense for dynamic imports with string paths&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The Umbraco Solution: Three Layers for Dual Resolution&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Umbraco CMS version 14 and beyond solves the dual-resolution problem (development vs runtime) through a three-layer implementation that makes imports work in different contexts:&lt;/p&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Development (TypeScript)&lt;/strong&gt;: Resolves to source files for type-checking&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Build (Vite/Rollup)&lt;/strong&gt;: Marks as external, leaves imports as-is&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Runtime (Browser)&lt;/strong&gt;: Resolves to built files via importmap&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;p&gt;Let&#x27;s see how each layer works.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Layer 1: TypeScript Resolution&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;TypeScript needs to know what &lt;code&gt;@umbraco-cms/backoffice/notification&lt;/code&gt; means for type-checking.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;For Umbraco Core Development&lt;/strong&gt; (working on the backoffice itself):&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;compilerOptions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;paths&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@umbraco-cms/backoffice/notification&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./src/packages/core/notification/index.ts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;This maps imports to source files for development on Umbraco itself.&lt;/p&gt;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;Note for Umbraco core developers&lt;/strong&gt;: This &lt;code&gt;tsconfig.json&lt;/code&gt; is auto-generated from &lt;code&gt;package.json&lt;/code&gt; exports by a build script. See the next section to understand how this works.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;For Extension Authors&lt;/strong&gt; (building backoffice extensions):&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Just install the NPM package:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-D&lt;/span&gt; @umbraco-cms/backoffice&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;TypeScript automatically finds type definitions from &lt;code&gt;node_modules/@umbraco-cms/backoffice&lt;/code&gt; - no &lt;code&gt;paths&lt;/code&gt; config needed!&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: Full IntelliSense, type-checking, and refactoring support in your IDE.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Why&lt;/strong&gt;: Because the package.json file contains an &lt;code&gt;&quot;exports&quot;&lt;/code&gt; field that defines the public API (more on that later).&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Layer 2: Build Resolution (Vite)&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;When building an extension, Vite needs to know not to bundle Umbraco&#x27;s code. &lt;strong&gt;This is the key step&lt;/strong&gt; - even though you installed the NPM package, you mark it as external:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// vite.config.ts&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;defineConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;na&quot;&gt;rollupOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;na&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;                &lt;span class=&quot;sr&quot;&gt;/^@umbraco-cms/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Don&#x27;t bundle - even though it&#x27;s in node_modules!&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;This tells Vite: &quot;When you encounter &lt;code&gt;@umbraco-cms/backoffice/*&lt;/code&gt;, &lt;strong&gt;don&#x27;t bundle it&lt;/strong&gt; from &lt;code&gt;node_modules&lt;/code&gt;. Leave the import statement as-is in the output.&quot;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: Your built JavaScript contains &lt;code&gt;import(&#x27;@umbraco-cms/backoffice/notification&#x27;)&lt;/code&gt; exactly as written - &lt;strong&gt;no bundled code from the NPM package&lt;/strong&gt;. The NPM package was only used for TypeScript types during development.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This is important for versioning. You may, in fact, multi-target your package regardless of the version of the installed NPM package, as it only provides types.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Layer 3: Runtime Resolution (Importmap)&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;When the browser loads your extension, it needs to know where to find the actual files:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;importmap&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;imports&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@umbraco-cms/backoffice/notification&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/umbraco/backoffice/packages/core/notification/index.js&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;This is defined in the backoffice&#x27;s package manifest and tells the browser: &quot;When you see an import for &lt;code&gt;@umbraco-cms/backoffice/notification&lt;/code&gt;, load this actual file.&quot;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: The browser successfully loads the real JavaScript file at runtime.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  How It All Works Together&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Let&#x27;s follow an import through all three layers:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;You write:&lt;/strong&gt;&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UMB_NOTIFICATION_CONTEXT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@umbraco-cms/backoffice/notification&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;During Development:&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;TypeScript sees the import&lt;/li&gt;&#xA;&lt;li&gt;Finds types from the installed NPM package (&lt;code&gt;@umbraco-cms/backoffice&lt;/code&gt; in &lt;code&gt;node_modules&lt;/code&gt;)&lt;/li&gt;&#xA;&lt;li&gt;Provides IntelliSense from the &lt;code&gt;.d.ts&lt;/code&gt; files&lt;/li&gt;&#xA;&lt;li&gt;&#x2705; Full type safety and autocomplete&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;During Build:&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Vite encounters the import&lt;/li&gt;&#xA;&lt;li&gt;Checks &lt;code&gt;rollupOptions.external&lt;/code&gt; - matches &lt;code&gt;/^@umbraco-cms/&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Doesn&#x27;t bundle&lt;/strong&gt; the code from &lt;code&gt;node_modules&lt;/code&gt; - leaves import as-is&lt;/li&gt;&#xA;&lt;li&gt;&#x2705; Output contains: &lt;code&gt;import(&#x27;@umbraco-cms/backoffice/notification&#x27;)&lt;/code&gt; (no bundled code!)&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;At Runtime:&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Browser encounters the import&lt;/li&gt;&#xA;&lt;li&gt;Checks the importmap&lt;/li&gt;&#xA;&lt;li&gt;Resolves to &lt;code&gt;/umbraco/backoffice/packages/core/notification/index.js&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#x2705; Loads the actual file&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The Innovation: Code Generation from package.json&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Now here&#x27;s where Umbraco&#x27;s solution gets clever. With &lt;strong&gt;120&#x2B; packages&lt;/strong&gt; in the backoffice, manually maintaining TypeScript paths, Vite externals, and import maps would be a nightmare.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  The Scale Problem&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Consider what&#x27;s required for each of those 120&#x2B; packages:&lt;/p&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;TypeScript &lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/strong&gt;: Map &lt;code&gt;@umbraco-cms/backoffice/notification&lt;/code&gt; to &lt;code&gt;./src/packages/core/notification/index.ts&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Vite config&lt;/strong&gt;: Mark as external (regex pattern handles this automatically)&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Runtime &lt;code&gt;umbraco-package.json&lt;/code&gt;&lt;/strong&gt;: Map &lt;code&gt;@umbraco-cms/backoffice/notification&lt;/code&gt; to &lt;code&gt;/umbraco/backoffice/packages/core/notification/index.js&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Test runner configs&lt;/strong&gt;: Various formats for Web Test Runner&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;p&gt;That&#x27;s 120&#x2B; entries in &lt;code&gt;tsconfig.json&lt;/code&gt;, 120&#x2B; entries in the import map, and keeping them all in sync. A single typo breaks everything. Adding a new package requires updating multiple files in different formats.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;This is untenable.&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Umbraco&#x27;s Solution: Single Source of Truth&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Umbraco solves this with code generation, treating &lt;code&gt;package.json&lt;/code&gt; as the &lt;strong&gt;golden source of truth&lt;/strong&gt;:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;package.json exports (source of truth)&#xA;    &#x2193;&#xA;devops/importmap/index.js (reads and transforms)&#xA;    &#x2193;&#xA;    &#x251C;&#x2192; devops/tsconfig/index.js &#x2192; tsconfig.json (120&#x2B; paths)&#xA;    &#x251C;&#x2192; devops/build/create-umbraco-package.js &#x2192; umbraco-package.json (import map)&#xA;    &#x2514;&#x2192; Test runner configuration&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpomeb8ku02tp6sh0cea.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpomeb8ku02tp6sh0cea.png&quot; alt=&quot;Diagram showing package.json exports at the top flowing through devops/importmap/index.js script in the middle, which outputs to three targets at the bottom: tsconfig.json for TypeScript paths, umbraco-package.json for browser import maps, and test runner configuration files. Arrows show the transformation from a single source to multiple config formats.&quot; width=&quot;800&quot; height=&quot;476&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;One edit point. Four outputs. Always in sync.&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Why package.json as the Source?&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;The &lt;code&gt;package.json&lt;/code&gt; already defines the public API contract with its &lt;code&gt;exports&lt;/code&gt; field:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@umbraco-cms/backoffice&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;exports&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;./notification&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./dist-cms/packages/core/notification/index.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;./content&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./dist-cms/packages/content/content/index.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;./modal&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./dist-cms/packages/core/modal/index.js&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;117&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&#x2B;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;more&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;packages&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Why this is the perfect source:&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#x2705; &lt;strong&gt;Already required&lt;/strong&gt;: Published to npm, consumed by TypeScript naturally&lt;/li&gt;&#xA;&lt;li&gt;&#x2705; &lt;strong&gt;Defines the contract&lt;/strong&gt;: Lists every public import path&lt;/li&gt;&#xA;&lt;li&gt;&#x2705; &lt;strong&gt;Standard format&lt;/strong&gt;: Uses Node.js package exports (not a custom format)&lt;/li&gt;&#xA;&lt;li&gt;&#x2705; &lt;strong&gt;Single edit point&lt;/strong&gt;: Add/remove/rename a package in one place&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;The &lt;code&gt;&quot;.&quot;: null&lt;/code&gt; is intentional - it prevents importing the root package and forces consumers to use specific subpaths like &lt;code&gt;@umbraco-cms/backoffice/notification&lt;/code&gt;.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Implementation: The Transformation Pipeline&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Here&#x27;s how Umbraco&#x27;s build scripts transform this single source into multiple formats.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Step 1: Create Import Map Structure&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The &lt;code&gt;devops/importmap/index.js&lt;/code&gt; script reads &lt;code&gt;package.json&lt;/code&gt; exports and creates an intermediate import map:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createImportMap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;imports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;additionalImports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;c1&quot;&gt;// Iterate over the exports in package.json&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;packageJsonExports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;c1&quot;&gt;// Skip null exports and non-JS files&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;endsWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;moduleName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/^&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\.\/&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;            &lt;span class=&quot;c1&quot;&gt;// Transform the path based on context&lt;/span&gt;&#xA;            &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;modulePath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rootDir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                &lt;span class=&quot;nx&quot;&gt;modulePath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;modulePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/^&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\.\/&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;dist-cms/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rootDir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;replaceModuleExtensions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                &lt;span class=&quot;nx&quot;&gt;modulePath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;modulePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.ts&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;            &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;importAlias&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;packageJsonName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;moduleName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;            &lt;span class=&quot;nx&quot;&gt;imports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;importAlias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;modulePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;imports&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Step 2: Generate TypeScript Paths&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The &lt;code&gt;devops/tsconfig/index.js&lt;/code&gt; script uses &lt;code&gt;createImportMap()&lt;/code&gt; with transformations for TypeScript:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;importmap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;createImportMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;rootDir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./src&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// dist-cms &#x2192; src&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;additionalImports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@umbraco-cms/internal/test-utils&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./utils/test-utils.ts&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;replaceModuleExtensions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// .js &#x2192; .ts&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;c1&quot;&gt;// Convert to tsconfig.json format&lt;/span&gt;&#xA;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;paths&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;importmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;imports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;nx&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// tsconfig expects arrays&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;nx&quot;&gt;tsConfigBase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;compilerOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;paths&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Generated output (&lt;code&gt;tsconfig.json&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;compilerOptions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;paths&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@umbraco-cms/backoffice/notification&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./src/packages/core/notification/index.ts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@umbraco-cms/backoffice/content&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./src/packages/content/content/index.ts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@umbraco-cms/backoffice/modal&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./src/packages/core/modal/index.ts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;117&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&#x2B;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;more&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Step 3: Generate Runtime Import Map&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The &lt;code&gt;devops/build/create-umbraco-package.js&lt;/code&gt; script transforms for browsers:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;importmap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;createImportMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;rootDir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/umbraco/backoffice&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// dist-cms &#x2192; server path&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;replaceModuleExtensions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Keep .js for runtime&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;c1&quot;&gt;// Write to umbraco-package.json&lt;/span&gt;&#xA;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;manifest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@umbraco-cms/backoffice&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;packageVersion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;importmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;na&quot;&gt;imports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;importmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;imports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Generated output (&lt;code&gt;umbraco-package.json&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@umbraco-cms/backoffice&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;importmap&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;imports&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@umbraco-cms/backoffice/notification&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/umbraco/backoffice/packages/core/notification/index.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@umbraco-cms/backoffice/content&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/umbraco/backoffice/packages/content/content/index.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@umbraco-cms/backoffice/modal&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/umbraco/backoffice/packages/core/modal/index.js&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;117&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&#x2B;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;more&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  The Key Transformations&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;From the same package.json export &lt;code&gt;&quot;./notification&quot;: &quot;./dist-cms/packages/core/notification/index.js&quot;&lt;/code&gt;, we generate:&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Context&lt;/th&gt;&#xA;&lt;th&gt;Transformation&lt;/th&gt;&#xA;&lt;th&gt;Output&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;strong&gt;TypeScript&lt;/strong&gt;&lt;/td&gt;&#xA;&lt;td&gt;&#xA;&lt;code&gt;dist-cms&lt;/code&gt; &#x2192; &lt;code&gt;src&lt;/code&gt;&lt;br&gt;&lt;code&gt;.js&lt;/code&gt; &#x2192; &lt;code&gt;.ts&lt;/code&gt;&#xA;&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;./src/packages/core/notification/index.ts&lt;/code&gt;&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;strong&gt;Runtime&lt;/strong&gt;&lt;/td&gt;&#xA;&lt;td&gt;&#xA;&lt;code&gt;dist-cms&lt;/code&gt; &#x2192; &lt;code&gt;/umbraco/backoffice/&lt;/code&gt;&lt;br&gt;Keep &lt;code&gt;.js&lt;/code&gt;&#xA;&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;/umbraco/backoffice/packages/core/notification/index.js&lt;/code&gt;&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;strong&gt;Package Name&lt;/strong&gt;&lt;/td&gt;&#xA;&lt;td&gt;Prepend package name and subpath&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;@umbraco-cms/backoffice/notification&lt;/code&gt;&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&lt;/div&gt;&#xA;&#xA;&lt;p&gt;Same logical structure. Different physical paths for different contexts.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Build Pipeline Integration&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;These scripts run at specific points in the development lifecycle:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;During development:&lt;/strong&gt;&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;npm run generate:tsconfig  &lt;span class=&quot;c&quot;&gt;# Regenerates tsconfig.json from package.json&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Before build:&lt;/strong&gt;&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;npm run generate:manifest  &lt;span class=&quot;c&quot;&gt;# Generates umbraco-package.json with import map&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;In CI/CD:&lt;/strong&gt;&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;npm run package:validate   &lt;span class=&quot;c&quot;&gt;# Validates that exports, paths, and imports are in sync&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Adding a new package:&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Edit &lt;code&gt;package.json&lt;/code&gt;: Add one line to &lt;code&gt;exports&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Run &lt;code&gt;npm run generate:tsconfig&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Run &lt;code&gt;npm run generate:manifest&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Done &#x2705;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;p&gt;No manual editing of configs. No risk of typos or drift.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  The Result: Impossible to Have Config Drift&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Because everything is generated from the same source, it&#x27;s &lt;strong&gt;architecturally impossible&lt;/strong&gt; for configs to drift out of sync. If TypeScript can find it, the browser can load it. If the import map has it, TypeScript knows about it.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This eliminates an entire class of bugs:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#x274C; Import works in TypeScript but fails at runtime&lt;/li&gt;&#xA;&lt;li&gt;&#x274C; Import works at runtime but TypeScript can&#x27;t find types&lt;/li&gt;&#xA;&lt;li&gt;&#x274C; Test runner can&#x27;t resolve import that works everywhere else&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;With code generation, these bugs &lt;strong&gt;cannot exist&lt;/strong&gt;.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Why This Architecture Works at Scale&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The code generation approach provides significant advantages in production:&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  1. &lt;strong&gt;Eliminates Config Drift&lt;/strong&gt;&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Manual maintenance inevitably leads to drift. A developer adds a TypeScript path but forgets the import map. Tests pass locally but production breaks.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;With code generation, this is impossible. One source of truth means one failure mode: if &lt;code&gt;package.json&lt;/code&gt; is wrong, everything is wrong. Easy to catch, easy to fix.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  2. &lt;strong&gt;Maintainability&lt;/strong&gt;&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Manual approach:&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;120 packages &#xD7; 3 configs = 360 entries to maintain&lt;/li&gt;&#xA;&lt;li&gt;Each in a different format&lt;/li&gt;&#xA;&lt;li&gt;Spread across 4&#x2B; files&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Generated approach:&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;120 entries in &lt;code&gt;package.json&lt;/code&gt; (source of truth)&lt;/li&gt;&#xA;&lt;li&gt;1 script that generates everything else&lt;/li&gt;&#xA;&lt;li&gt;~200 lines of transformation logic (vs 360&#x2B; lines of config)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  3. &lt;strong&gt;Type Safety&lt;/strong&gt;&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;TypeScript provides full autocomplete and refactoring support. If you rename a package in &lt;code&gt;package.json&lt;/code&gt;, regenerate configs, and TypeScript immediately shows you every place that needs updating.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  4. &lt;strong&gt;Refactorability&lt;/strong&gt;&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Internal file structure can change without breaking consumers. As long as &lt;code&gt;package.json&lt;/code&gt; exports stay the same, consumers see a stable API. The generation scripts handle the internal path changes.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Example: Moving &lt;code&gt;notification&lt;/code&gt; from &lt;code&gt;packages/core/&lt;/code&gt; to &lt;code&gt;packages/alerts/&lt;/code&gt; requires:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Updating one path in &lt;code&gt;package.json&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Regenerating configs&lt;/li&gt;&#xA;&lt;li&gt;Zero changes for extension authors&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The NPM Package: Types and Code, But Not Bundled&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Here&#x27;s where the pattern gets clever. Umbraco publishes an NPM package that contains &lt;strong&gt;both runtime JavaScript and TypeScript definitions&lt;/strong&gt;:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-D&lt;/span&gt; @umbraco-cms/backoffice&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Extension authors install this package, but here&#x27;s the trick: they mark it as external in &lt;code&gt;vite.config.ts&lt;/code&gt; (as shown above), which &lt;strong&gt;prevents Vite from bundling the runtime code&lt;/strong&gt; even though it&#x27;s present in &lt;code&gt;node_modules&lt;/code&gt;.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This means:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;TypeScript uses the package for types and IntelliSense during development&lt;/li&gt;&#xA;&lt;li&gt;Vite sees it&#x27;s external and doesn&#x27;t bundle it&lt;/li&gt;&#xA;&lt;li&gt;The browser loads the actual runtime code from the server at runtime&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;The complete picture:&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Development&lt;/strong&gt;: TypeScript finds types from the installed NPM package&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Build&lt;/strong&gt;: Vite sees &lt;code&gt;external&lt;/code&gt; config and doesn&#x27;t bundle the code from &lt;code&gt;node_modules&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Runtime&lt;/strong&gt;: Browser uses importmap to load actual files from &lt;code&gt;/umbraco/backoffice/&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;The magic&lt;/strong&gt;: Same NPM package name (&lt;code&gt;@umbraco-cms/backoffice/*&lt;/code&gt;), but:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;In development &#x2192; resolved to types from &lt;code&gt;node_modules&lt;/code&gt; for IntelliSense&lt;/li&gt;&#xA;&lt;li&gt;At build &#x2192; marked external, not bundled&lt;/li&gt;&#xA;&lt;li&gt;At runtime &#x2192; resolved to server files via importmap&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Why Alternatives Don&#x27;t Work&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;At this point, you might be wondering: &quot;If import maps create all this config duplication, why use them at all? Are there better alternatives?&quot;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;It&#x27;s a fair question. Let&#x27;s consider what else we could have done.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Alternative 1: Traditional NPM Package (Bundle Our Code)&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;What if we published the runtime code to NPM and let extension authors bundle it?&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; @umbraco-cms/backoffice&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Extension authors would import and &lt;strong&gt;bundle our code&lt;/strong&gt; into their extensions.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Why this doesn&#x27;t work:&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#x274C; &lt;strong&gt;Code duplication&lt;/strong&gt;: Every extension bundles the same 22kb of Search code&lt;/li&gt;&#xA;&lt;li&gt;&#x274C; &lt;strong&gt;Version conflicts&lt;/strong&gt;: Extension A uses Search v1.0, Extension B uses v1.1 - both loaded&lt;/li&gt;&#xA;&lt;li&gt;&#x274C; &lt;strong&gt;No shared state&lt;/strong&gt;: Global contexts can&#x27;t communicate across separately bundled instances&lt;/li&gt;&#xA;&lt;li&gt;&#x274C; &lt;strong&gt;Bundle bloat&lt;/strong&gt;: The backoffice loads the same code 5 times for 5 extensions&lt;/li&gt;&#xA;&lt;li&gt;&#x274C; &lt;strong&gt;Defeats code-splitting&lt;/strong&gt;: We carefully split global/core bundles - all wasted&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Verdict&lt;/strong&gt;: This defeats the entire architectural purpose. We&#x27;d be back to the jQuery plugin days where every extension bundles duplicate dependencies.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Alternative 2: Raw File Paths (Skip the Abstraction)&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;What if we skipped logical imports and used raw paths?&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Extension authors would write:&lt;/span&gt;&#xA;&lt;span class=&quot;nx&quot;&gt;api&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/umbraco/backoffice/packages/content/index.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;UmbContentRepository&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}));&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Why this doesn&#x27;t work:&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#x274C; &lt;strong&gt;Brittle&lt;/strong&gt;: If we reorganize files, every extension breaks&lt;/li&gt;&#xA;&lt;li&gt;&#x274C; &lt;strong&gt;No abstraction&lt;/strong&gt;: Exposes implementation details to consumers&lt;/li&gt;&#xA;&lt;li&gt;&#x274C; &lt;strong&gt;No TypeScript support&lt;/strong&gt;: How do extension authors get types?&lt;/li&gt;&#xA;&lt;li&gt;&#x274C; &lt;strong&gt;Unprofessional&lt;/strong&gt;: Looks like a hack rather than proper package architecture&lt;/li&gt;&#xA;&lt;li&gt;&#x274C; &lt;strong&gt;Non-refactorable&lt;/strong&gt;: IDEs can&#x27;t help with renames or moves&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Alternative 3: Custom Vite Plugin&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;What if we built a Vite plugin that understands Umbraco packages?&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;umbracoPlugin&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@umbraco-cms/vite-plugin&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;defineConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;        &lt;span class=&quot;nf&quot;&gt;umbracoPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&#xA;            &lt;span class=&quot;na&quot;&gt;externalPackages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@umbraco-cms/backoffice&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;The plugin could auto-configure externals, generate TypeScript paths, and validate imports.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Why this doesn&#x27;t solve it:&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#x26A0;&#xFE0F; &lt;strong&gt;Still need import maps&lt;/strong&gt;: Browsers still need runtime resolution somehow&lt;/li&gt;&#xA;&lt;li&gt;&#x26A0;&#xFE0F; &lt;strong&gt;Another tool to maintain&lt;/strong&gt;: We&#x27;d have to build, document, and support it&lt;/li&gt;&#xA;&lt;li&gt;&#x26A0;&#xFE0F; &lt;strong&gt;Adoption barrier&lt;/strong&gt;: Extension authors must learn our custom tooling&lt;/li&gt;&#xA;&lt;li&gt;&#x2705; &lt;strong&gt;Could reduce duplication&lt;/strong&gt;: Might generate configs from a single source&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Verdict&lt;/strong&gt;: This could be a nice developer experience improvement, but it doesn&#x27;t eliminate the fundamental need for import maps at runtime.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  The Real Problem: Ecosystem Gap, Not the Pattern&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Here&#x27;s the critical insight: &lt;strong&gt;The problem isn&#x27;t import maps - it&#x27;s that the tooling ecosystem hasn&#x27;t standardized on them yet.&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Import maps are:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#x2705; &lt;strong&gt;Browser-native&lt;/strong&gt;: &lt;a href=&quot;https://html.spec.whatwg.org/multipage/webappapis.html#import-maps&quot; rel=&quot;noopener noreferrer&quot;&gt;WHATWG standard&lt;/a&gt;, shipped in all modern browsers&lt;/li&gt;&#xA;&lt;li&gt;&#x2705; &lt;strong&gt;Semantically correct&lt;/strong&gt;: Designed exactly for this use case&lt;/li&gt;&#xA;&lt;li&gt;&#x2705; &lt;strong&gt;The future&lt;/strong&gt;: The direction web standards are moving&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;But JavaScript tooling is:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#x274C; &lt;strong&gt;Behind the curve&lt;/strong&gt;: TypeScript, Vite, NPM don&#x27;t understand import maps&lt;/li&gt;&#xA;&lt;li&gt;&#x274C; &lt;strong&gt;Fragmented&lt;/strong&gt;: Each tool has its own config format for the same concept&lt;/li&gt;&#xA;&lt;li&gt;&#x274C; &lt;strong&gt;Slow to adapt&lt;/strong&gt;: Browser standards move faster than tooling&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;We&#x27;re not working around a limitation of import maps - we&#x27;re working around &lt;strong&gt;tooling that hasn&#x27;t caught up to the browser standard.&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  What Our Constraints Actually Are&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;When building a package for third-party extension authors, we must support:&lt;/p&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Type definitions at development time&lt;/strong&gt; - Extension authors need IntelliSense&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;No runtime bundling&lt;/strong&gt; - Can&#x27;t have code duplication and version conflicts&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Shared runtime state&lt;/strong&gt; - Global contexts must be singletons&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Standard tools&lt;/strong&gt; - Must work with TypeScript, Vite, standard browsers&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Clean API&lt;/strong&gt; - Professional package names, not raw file paths&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Import maps are the only solution that satisfies all five constraints.&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  What Would Actually Improve Things?&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Umbraco can control:&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#x2705; Build code generation scripts (we did this)&lt;/li&gt;&#xA;&lt;li&gt;&#x2705; Document the pattern for extension authors&lt;/li&gt;&#xA;&lt;li&gt;&#x2705; Provide templates and examples&lt;/li&gt;&#xA;&lt;li&gt;&#x26A0;&#xFE0F; Build Vite plugins to improve DX (nice-to-have, doesn&#x27;t eliminate import maps)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;The ecosystem needs:&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#x274C; Native import map support in TypeScript&lt;/li&gt;&#xA;&lt;li&gt;&#x274C; Native import map support in Vite/Rollup&lt;/li&gt;&#xA;&lt;li&gt;&#x274C; Standardized tooling that treats import maps as first-class&lt;/li&gt;&#xA;&lt;li&gt;&#x274C; Better coordination between browser standards and build tool vendors&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;Until the tooling catches up, patterns like Umbraco&#x27;s code generation are the pragmatic solution.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Conclusion&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The import map pattern is more than just a clever trick - it&#x27;s a fundamental architectural pattern that solves the dual-resolution problem (development vs runtime) elegantly through a three-layer implementation. By using logical module identifiers with different resolution strategies for TypeScript, Vite, and browsers, Umbraco creates a professional, maintainable, and extensible package system.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The real innovation is treating &lt;code&gt;package.json&lt;/code&gt; as a single source of truth and generating all configs from it. This eliminates an entire class of bugs, improves developer velocity, and makes it architecturally impossible for configs to drift out of sync.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;For 120&#x2B; packages, code generation isn&#x27;t just an optimization - it&#x27;s a requirement. Manual maintenance at this scale is untenable.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The three-layer system (TypeScript paths &#x2192; Vite externals &#x2192; import maps) might seem complex at first, but once you understand how each layer works, you&#x27;ll appreciate the elegance of the solution. It&#x27;s a pattern that makes modern web development with extensible packages possible.&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Appendix A: Building Extensions with This Pattern&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The following sections provide guidance for developers who want to build Umbraco extensions using this pattern.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;p&gt;You can use the same pattern for your own Umbraco packages. Here&#x27;s how you might implement it for a Search package:&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  1. Choose Your Namespace&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Use &lt;code&gt;@organization/your-package&lt;/code&gt; to stay within a self-defined scope, if you eventually publish this to an NPM feed.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;organization&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/search/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;core&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;organization&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/search/g&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lobal&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  2. Configure TypeScript (&lt;code&gt;tsconfig.json&lt;/code&gt;)&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Map logical imports to your source files:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;compilerOptions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;baseUrl&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;paths&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@organization/search/global&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./src/global/index.ts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@organization/search/core&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./src/core/index.ts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  3. Configure Vite (&lt;code&gt;vite.config.ts&lt;/code&gt;)&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Mark your package as external so it&#x27;s not self-bundled:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;defineConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;na&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;na&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;search-global&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;src/global/search-global.ts&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;                &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;search-core&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;src/core/search-core.ts&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;            &lt;span class=&quot;na&quot;&gt;formats&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;es&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;        &lt;span class=&quot;na&quot;&gt;rollupOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;na&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/^@umbraco-cms/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^@organization/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  4. Add Importmap (&lt;code&gt;umbraco-package.json&lt;/code&gt;)&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Tell browsers where to find your built files:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Your.Package.Id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@organization/search&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;extensions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bundle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;alias&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Your.Package.Bundle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/App_Plugins/YourPackage/bundle.js&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;importmap&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;imports&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@organization/search/global&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/App_Plugins/YourPackage/search-global.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@organization/search/core&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/App_Plugins/YourPackage/search-core.js&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Note how we use the same namespace scope in the importmap as in TypeScript and package.json. This way everything aligns.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  5. Use Logical Imports in Manifests&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Now use logical imports instead of raw paths:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// &#x2705; New approach: logical imports&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;manifests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;UmbExtensionManifest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;        &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;My.Repository&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;        &lt;span class=&quot;na&quot;&gt;api&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@organization/search/core&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MyRepository&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})),&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;c1&quot;&gt;// &#x2705; New approach: import values&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UMB_SEARCH_CONTEXT_TOKEN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@organization/search/global&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;UMB_SEARCH_CONTEXT_TOKEN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// logs: context token instance&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  6. Export Your Types (&lt;code&gt;package.json&lt;/code&gt;)&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;If you want others to extend your package, publish TypeScript definitions:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@organization/search&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;exports&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;./core&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;types&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./dist/core/index.d.ts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./dist/core/index.js&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;./global&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;types&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./dist/global/index.d.ts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./dist/global/index.js&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  When to Add Code Generation&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;For a small package with 2-3 subpaths, manual config maintenance is fine. But consider building a generation script (like Umbraco&#x27;s) when:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#x2705; You have 4&#x2B; subpaths&lt;/li&gt;&#xA;&lt;li&gt;&#x2705; You&#x27;re frequently adding new exports&lt;/li&gt;&#xA;&lt;li&gt;&#x2705; You&#x27;re building a package ecosystem&lt;/li&gt;&#xA;&lt;li&gt;&#x2705; You want others to extend your work&lt;/li&gt;&#xA;&lt;li&gt;&#x2705; Config drift has caused bugs&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;The script doesn&#x27;t need to be complex - just read &lt;code&gt;package.json&lt;/code&gt; exports and generate the various config formats. You can use Umbraco&#x27;s scripts as a reference: &lt;a href=&quot;https://github.com/umbraco/Umbraco-CMS/blob/main/src/Umbraco.Web.UI.Client/devops/importmap/index.js&quot; rel=&quot;noopener noreferrer&quot;&gt;devops/importmap/index.js&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Appendix B: Advanced Usage - Multiple Subpaths&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;You can split your package into multiple logical subpaths:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GlobalContext&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@organization/search/global&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Repository&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@organization/search/core&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Helpers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@organization/search/utils&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;Each subpath can have different loading characteristics:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;global&lt;/strong&gt;: Loaded upfront for event listeners&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;core&lt;/strong&gt;: Lazy-loaded on demand&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;utils&lt;/strong&gt;: Shared utilities&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;Just add each to your importmap:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;importmap&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;imports&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@organization/search/global&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/App_Plugins/Search/global.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@organization/search/core&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/App_Plugins/Search/core.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@organization/search/utils&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/App_Plugins/Search/utils.js&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  Benefits of Multiple Subpaths&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Code splitting&lt;/strong&gt;: Users only load what they use&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Lazy loading&lt;/strong&gt;: Core functionality loads on-demand&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Clear organization&lt;/strong&gt;: API surface is explicit&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Independent updates&lt;/strong&gt;: Update one subpath without affecting others&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Appendix C: Common Pitfalls&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  1. Forgetting to Mark as External&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;If you don&#x27;t mark your package as external in Vite config, it will bundle itself, breaking the lazy-load pattern:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// &#x274C; Wrong: Will self-bundle&lt;/span&gt;&#xA;&lt;span class=&quot;nx&quot;&gt;rollupOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;nl&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/^@umbraco-cms/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Missing your own package!&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;c1&quot;&gt;// &#x2705; Correct: Mark your own package as external&lt;/span&gt;&#xA;&lt;span class=&quot;nl&quot;&gt;rollupOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;na&quot;&gt;external&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&#xA;        &lt;span class=&quot;sr&quot;&gt;/^@umbraco-cms/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;        &lt;span class=&quot;sr&quot;&gt;/^@organization/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Add this!&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  2. Mismatched Paths&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;The tsconfig path must point to the &lt;strong&gt;exports file&lt;/strong&gt; (usually &lt;code&gt;index.ts&lt;/code&gt;), not the entry file:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// &#x274C; Wrong: Points to entry file&lt;/span&gt;&#xA;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@organization/search/core&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./src/core/search-core.ts&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;c1&quot;&gt;// &#x2705; Correct: Points to exports file&lt;/span&gt;&#xA;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@organization/search/core&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./src/core/index.ts&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  3. Missing Importmap Entry&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;If you add a new subpath, don&#x27;t forget to add it to the importmap:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;importmap&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;imports&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@organization/search/global&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/App_Plugins/Search/global.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@organization/search/core&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/App_Plugins/Search/core.js&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;            &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Don&#x27;t&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;forget&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;subpaths&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;here!&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  4. Config Drift&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;p&gt;Manually maintaining multiple configs leads to drift. If you have more than a few subpaths, consider implementing code generation like Umbraco does.&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;Further Reading:&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&quot;https://html.spec.whatwg.org/multipage/webappapis.html#import-maps&quot; rel=&quot;noopener noreferrer&quot;&gt;Import Maps Specification (WHATWG HTML Standard)&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&quot;https://github.com/WICG/import-maps&quot; rel=&quot;noopener noreferrer&quot;&gt;Import Maps Explainer (WICG)&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/customizing/overview&quot; rel=&quot;noopener noreferrer&quot;&gt;Umbraco Backoffice Extension Documentation&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping&quot; rel=&quot;noopener noreferrer&quot;&gt;TypeScript Path Mapping&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&quot;https://github.com/umbraco/Umbraco-CMS/tree/main/src/Umbraco.Web.UI.Client/devops&quot; rel=&quot;noopener noreferrer&quot;&gt;Umbraco&#x27;s Code Generation Scripts&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;]]></description>
                    <pubDate>Tue, 27 Jan 2026 15:34:30 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbracospark/115962199874893850</guid>
                    <title>Umbraco Spark Opportunity Programme applications close Wednesday 28 January</title>
                    <link>https://umbracocommunity.social/@umbracospark/115962199874893850</link>
                    <description><![CDATA[&#x23F0; Closes Wednesday 28 January 2026Our Opportunity Programme (with @MikeMasey at Huskey) offers free #Umbraco Spark tickets for people who might not otherwise attend tech conferences.&#x1F6A8; Only 2 tickets left&#x2714; No sponsored labels Apply or nominate:https://docs.google.com/forms/d/e/1FAIpQLSfeqxcsCukFFrW7KI5MZJROKB1KUNy1q5j_E1nPCmVG_x7Bxg/viewform]]></description>
                    <pubDate>Mon, 26 Jan 2026 15:55:44 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbraco/115961994895073918</guid>
                    <title>Grab your Umbraco Spark ticket before prices increase</title>
                    <link>https://umbracocommunity.social/@umbraco/115961994895073918</link>
                    <description><![CDATA[&#x23F3; 6 days left to grab Umbraco Spark tickets at &#xA3;125 &#x2B; VATA strong speaker line-up, practical sessions, and a brilliant Umbraco crowd.Prices increase at the end of January.&#x1F39F;&#xFE0F; https://www.tickettailor.com/events/umbukfdn/1896581&#x1F440; https://umbracospark.com/#what#UmbracoSpark #Umbraco #BristolTech #WebDev #DotNet]]></description>
                    <pubDate>Mon, 26 Jan 2026 15:08:15 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=HV5_7VGdLxg</guid>
                    <title>DevRel Deep Dive: Sitemap &amp; Robots.txt Packages from Blend Interactive</title>
                    <link>https://www.youtube.com/watch?v=HV5_7VGdLxg</link>
                    <description><![CDATA[This week Sebastiaan and Lotte look at two packages from Blend Interactive for adding and configuring your site&#x2019;s (or sites&#x2019;) sitemap.xml and robots.txt. During the demo Sebastiaan sets up Claude Code to use the Umbraco MCP Server, and uses that to save some time, or perhaps mouse clicks!&#xA;&#xA;&#x1F4E6; Blend &#x200B;Interactive &#x200B;Umbraco Sitemap on the Umbraco Marketplace: https://marketplace.umbraco.com/package/blendinteractive.umbraco.sitemap&#xA;&#x1F4E6; Blend &#x200B;Interactive &#x200B;Umbraco &#x200B;Robots&#x200B;Txt on the Umbraco Marketplace: https://marketplace.umbraco.com/package/blendinteractive.umbraco.robotstxt &#xA;&#xA;--------&#xA;&#x2753; Looking for help with your Umbraco projects? Visit the Forum&#xA; https://forum.umbraco.com&#xA; &#xA;&#x1F4AC; Want to chat with the friendly Umbraco Community? Join our Discord server&#xA; https://discord.umbraco.com&#xA; &#xA;&#x2709;&#xFE0F; Got a question (or topic suggestion) for the HQ Developer Relations team?&#xA; https://umbra.co/contact-devrel, or the &#x2018;contact-devrel&#x2019; channel on Discord&#xA; &#xA;#Umbraco]]></description>
                    <pubDate>Mon, 26 Jan 2026 13:49:49 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://dev.to/skttl/enhanced-event-logs-and-deployment-monitoring-for-kudu-in-umbraco-cloud-i66</guid>
                    <title>Enhanced Event Logs and Deployment Monitoring for Kudu in Umbraco Cloud</title>
                    <link>https://dev.to/skttl/enhanced-event-logs-and-deployment-monitoring-for-kudu-in-umbraco-cloud-i66</link>
                    <description><![CDATA[&lt;p&gt;When working with Umbraco Cloud, I occasionally need to access Kudu for debugging and deployment tasks. You can access Kudu by clicking the &quot;Kudu&quot; button in your site&#x27;s dashboard, or directly via the URL: &lt;code&gt;https://&amp;lt;site-name&amp;gt;.scm.&amp;lt;cloud-region&amp;gt;.umbraco.io&lt;/code&gt; (where the cloud region might be &lt;code&gt;euwest01&lt;/code&gt;, for example).&lt;/p&gt;&#xA;&#xA;&lt;p&gt;When a site fails to start or a deployment fails without clear errors, the event log in Kudu can provide crucial insights. However, the raw experience leaves much to be desired.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;To solve this problem, I created two userscripts that enhance the Kudu interface.&lt;/p&gt;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;What is a userscript?&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;A userscript is a program, usually written in JavaScript, for modifying web pages to augment browsing. Uses include adding shortcut buttons and keyboard shortcuts, controlling playback speeds, adding features to sites, and enhancing the browsing history.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;To use a userscript, you need a userscript manager. There are several available, but the most popular is &lt;a href=&quot;https://www.tampermonkey.net/&quot; rel=&quot;noopener noreferrer&quot;&gt;Tampermonkey&lt;/a&gt;. Tampermonkey is available for Chrome, Firefox, and Edge.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Visualizing Event Logs&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzga0elryhsaqshmfcuul.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzga0elryhsaqshmfcuul.png&quot; alt=&quot;Screenshot of the Event Log Viewer provided by the Kudu Event Log Viewer userscript&quot; width=&quot;800&quot; height=&quot;599&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;First thing to look at is the event log of the site. The event log contains information from IIS, and tells you any problems when starting the site. It can also contain information about failed deployments, and other issues.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;But, it&#x27;s not the most user-friendly experience. It&#x27;s a raw XML file, and you have to manually parse it.&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The event log is located at &lt;code&gt;/LogFiles/eventlog.xml&lt;/code&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;It can be a massive XML file with thousands of entries&lt;/li&gt;&#xA;&lt;li&gt;The most recent (and relevant) information is at the bottom&lt;/li&gt;&#xA;&lt;li&gt;There&#x27;s no syntax highlighting or formatting&lt;/li&gt;&#xA;&lt;li&gt;You have to manually parse XML in your head&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;This userscript adds a new &quot;Event Log&quot; tab to the Kudu interface, providing a much better experience:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Parsed and formatted&lt;/strong&gt;: Events are displayed in a clean table format&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Most recent first&lt;/strong&gt;: The latest events appear at the top (no more scrolling)&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Color-coded&lt;/strong&gt;: Each event type has its own color for quick identification&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Structured columns&lt;/strong&gt;: Event time, type, message, and source are clearly separated&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;The event log helps you diagnose issues like missing DLLs, IIS startup failures, configuration problems, and data-related errors.&lt;/p&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  How to use it&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Install the Kudu Event Log Viewer userscript from my &lt;a href=&quot;https://github.com/skttl/umbraco-userscripts&quot; rel=&quot;noopener noreferrer&quot;&gt;umbraco-userscripts&lt;/a&gt; repository&lt;/li&gt;&#xA;&lt;li&gt;Navigate to your Umbraco Cloud Kudu interface (e.g., &lt;code&gt;*.scm.euwest01.umbraco.io&lt;/code&gt;)&lt;/li&gt;&#xA;&lt;li&gt;Click the &quot;Event Log&quot; link in the navbar&lt;/li&gt;&#xA;&lt;li&gt;Click &quot;Load Event Log&quot; to fetch and display events&lt;/li&gt;&#xA;&lt;li&gt;Events are displayed in Bootstrap panels with full details&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Tracking Deployments&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmsxb6l114rg30pcceh2q.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmsxb6l114rg30pcceh2q.png&quot; alt=&quot;Screenshot of the Deployment Viewer provided by the Umbraco Cloud Deployment Viewer userscript&quot; width=&quot;800&quot; height=&quot;599&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;When using CI/CD with Umbraco Cloud, deployment visibility is limited compared to traditional git push deployments. You lose the immediate feedback from git logs about build status and deployment progress.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Normally, when a deployment fails, you need to manually navigate through files in &lt;code&gt;/site/deployments&lt;/code&gt; to find:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Which deployment is currently active&lt;/li&gt;&#xA;&lt;li&gt;Individual deployment folders with logs and status files&lt;/li&gt;&#xA;&lt;li&gt;Scattered information across multiple locations&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;The Deployment Viewer userscript consolidates all this information into a single dashboard:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Deployment status&lt;/strong&gt;: See the current state of all deployments&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Live logs&lt;/strong&gt;: View logs for each deployment&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Auto-refresh&lt;/strong&gt;: Enable live updates to monitor deployments in real-time&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Manual triggers&lt;/strong&gt;: Start a new deployment without making a git change&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h3&gt;&#xA;  &#xA;  &#xA;  How to use it&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Install the Umbraco Cloud Deployment Viewer userscript from my &lt;a href=&quot;https://github.com/skttl/umbraco-userscripts&quot; rel=&quot;noopener noreferrer&quot;&gt;umbraco-userscripts&lt;/a&gt; repository&lt;/li&gt;&#xA;&lt;li&gt;Navigate to your Umbraco Cloud Kudu interface (e.g., &lt;code&gt;*.scm.euwest01.umbraco.io&lt;/code&gt;)&lt;/li&gt;&#xA;&lt;li&gt;Click the &quot;Deployments&quot; link in the navbar&lt;/li&gt;&#xA;&lt;li&gt;View the latest deployment status and log&lt;/li&gt;&#xA;&lt;li&gt;Click &quot;Auto-refresh&quot; to enable live log and status updates&lt;/li&gt;&#xA;&lt;li&gt;Click &quot;Trigger New Deployment&quot; to start a new deployment&lt;/li&gt;&#xA;&lt;li&gt;Click on any deployment in the history table to view full details in a modal&lt;/li&gt;&#xA;&lt;li&gt;Click file counts to view the deployment manifest&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Final Thoughts&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;While Umbraco Cloud&#x27;s dashboard provides excellent visibility for most scenarios, these userscripts fill important gaps when you need to dig deeper. They transform Kudu from a basic file browser into a powerful debugging and deployment monitoring tool.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Both userscripts are available on &lt;a href=&quot;https://github.com/skttl/umbraco-userscripts&quot; rel=&quot;noopener noreferrer&quot;&gt;GitHub&lt;/a&gt;. Give them a try the next time you&#x27;re troubleshooting a deployment issue or investigating a site failure.&lt;/p&gt;]]></description>
                    <pubDate>Mon, 26 Jan 2026 09:11:18 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@lee/115950636394898597</guid>
                    <title>Umbraco Contentment 6.1.0 is out now</title>
                    <link>https://umbracocommunity.social/@lee/115950636394898597</link>
                    <description><![CDATA[#umbraco #Contentment 6.1.0https://github.com/leekelleher/umbraco-contentment/releases/tag/6.1.0TL;DR, bug fixes and new Liquid.js-powered &quot;Block Editor Custom View&quot; feature.]]></description>
                    <pubDate>Sat, 24 Jan 2026 15:03:32 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/unavbar</guid>
                    <title>uNavbar</title>
                    <link>https://marketplace.umbraco.com/package/unavbar</link>
                    <description><![CDATA[A commercial-grade, dynamic navigation solution for Umbraco 17&#x2B;. easily manage menus, branding, and responsive layouts from the backoffice.]]></description>
                    <pubDate>Sat, 24 Jan 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.johanreitsma.com/blogs/fix-draft-block-gridlist-items-after-upgrading-from-umbraco-13-to-17-vary-by-culture-element-types/</guid>
                    <title>Fix Draft Block Grid/List Items After Upgrading from Umbraco 13 to 17 (Vary by Culture Element Types)</title>
                    <link>https://www.johanreitsma.com/blogs/fix-draft-block-gridlist-items-after-upgrading-from-umbraco-13-to-17-vary-by-culture-element-types/</link>
                    <description><![CDATA[Upgrading from Umbraco 13 to 17 and suddenly seeing Draft blocks or empty content in other languages? This post shows the cause, the SQL fix to apply before upgrading, and how to validate everything after the migration....]]></description>
                    <pubDate>Fri, 23 Jan 2026 15:15:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbraco/115943593340257266</guid>
                    <title>Umbraco achieves ISO 27001 certification</title>
                    <link>https://umbracocommunity.social/@umbraco/115943593340257266</link>
                    <description><![CDATA[&#x1F389; Confetti alert!Even though we&#x2019;ve been playing with the big boys for years&#x2026; we&#x2019;ve now got the ISO 27001 certification to prove it! &#x2705;This means our product teams follow audited, structured, and continuously improved security practices, giving partners and customers even more reason to trust Umbraco in enterprise and regulated environments.A massive shout-out to the teams who made this happen &#x1F44F;Read more on https://umbra.co/4r3RDTT#Umbraco]]></description>
                    <pubDate>Fri, 23 Jan 2026 11:35:11 Z</pubDate>
                        <category>hq</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://www.arroact.com/blogs/umbraco-security-vulnerabilities/</guid>
                    <title>Top 10 Umbraco Security Vulnerabilities that You Must know in 2026</title>
                    <link>https://www.arroact.com/blogs/umbraco-security-vulnerabilities/</link>
                    <description><![CDATA[Top 10 Umbraco Security Vulnerabilities that You Must know in 2026]]></description>
                    <pubDate>Fri, 23 Jan 2026 08:10:11 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/iso-27001/</guid>
                    <title>Umbraco&#x27;s product organisation achieves ISO 27001 certification</title>
                    <link>https://umbraco.com/blog/iso-27001/</link>
                    <description><![CDATA[The Umbraco product organisation achieves ISO 27001 certification to strengthen security and enterprise readiness.]]></description>
                    <pubDate>Fri, 23 Jan 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbracospark/115938637999376821</guid>
                    <title>Rock Solid Knowledge continuing their support as a sponsor of UmbracoSpark 2026</title>
                    <link>https://umbracocommunity.social/@umbracospark/115938637999376821</link>
                    <description><![CDATA[Great to have Rock Solid Knowledge continuing their support as a sponsor of #UmbracoSpark 2026 &#x1F64C;It&#x27;s always a pleasure to work with teams that consistently invest in the Umbraco community.&#x1F440; We still have ONE sponsor spot available&#x1F39F;&#xFE0F; 2 free tickets &#x2B; extra tickets at &#xA3;75pp and more!More info:&#x1F517; https://umbracospark.com&#x1F517; https://www.rocksolidknowledge.com/#UmbracoSpark #Umbraco #BristolTech #TechEvents #WebDev #DotNet]]></description>
                    <pubDate>Thu, 22 Jan 2026 12:09:08 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://fa9976c2-5840-4a63-82ec-42e17b070c7d-1.azurewebsites.net/blog/archive/upgrading-from-umbraco-13-to-17-lts-lessons-from-the-trenches/</guid>
                    <title>Upgrading from Umbraco 13 to 17 LTS: Lessons from the Trenches</title>
                    <link>https://fa9976c2-5840-4a63-82ec-42e17b070c7d-1.azurewebsites.net/blog/archive/upgrading-from-umbraco-13-to-17-lts-lessons-from-the-trenches/</link>
                    <description><![CDATA[&lt;p&gt;Upgrades, upgrades, upgrades!&#xA0; Upgrades are a hot topic in the Umbraco community ever since version 17 was released last November. There are a lot of great reasons to upgrade to this major version besides simply moving to the latest Long-Term Supported (LTS) version. Our team here at ProWorks has a ton of Umbraco upgrade experience and are here to help you make your upgrade a success. This article will update as we learn about new challenges and find solutions. Ready? Let&#x27;s do this!&lt;/p&gt;&#xA;&lt;p&gt;&lt;a type=&quot;external&quot; href=&quot;#final-thoughts&quot; title=&quot;See the changelog at the bottom if you&#x27;re coming back to this after a while&quot; data-anchor=&quot;#final-thoughts&quot;&gt;See the changelog at the bottom if you&#x27;re coming back to this after a while&lt;/a&gt; - &lt;em&gt;Updated: January 22, 2026&lt;/em&gt;&lt;/p&gt;&#xA;&lt;h2&gt;Why Upgrade?&lt;/h2&gt;&#xA;&lt;p&gt;Let&#x27;s look at why you would upgrade to the latest v17 version:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;em&gt;&lt;strong&gt;Timely Security Updates&lt;/strong&gt;&lt;/em&gt; - As a LTS version, your site can stay up to date with security patches and easiest to keep up to date in the future. Umbraco 17 is supported through November 27, 2028.&lt;/li&gt;&#xA;&lt;li&gt;&lt;em&gt;&lt;strong&gt;Better Site Performance&#xA0;&lt;/strong&gt;&lt;/em&gt;- The rebuilt HybridCache speeds up startups especially on large sites. This means less down time after deploys to live. The latest .NET version 10 framework also improves performance which helps with your page speeds.&lt;/li&gt;&#xA;&lt;li&gt;&lt;em&gt;&lt;strong&gt;Better Back-Office Performance&lt;/strong&gt;&lt;/em&gt; - The rebuilt back-office is faster and allows for standards-based extensions and future-proofed architecture that no longer relies on Angular or other external large frameworks that could no longer be supported.&lt;/li&gt;&#xA;&lt;li&gt;&lt;em&gt;&lt;strong&gt;Deep AI Chat Integrations&lt;/strong&gt;&lt;/em&gt; - The official Umbraco MCP Server only works on version 17 and allows AI to &quot;talk&quot; to your specific Umbraco back-office to report on, add, or modify content.&lt;/li&gt;&#xA;&lt;li&gt;&lt;em&gt;&lt;strong&gt;Better &lt;/strong&gt;&lt;/em&gt;&lt;em&gt;&lt;strong&gt;Automation and I&lt;/strong&gt;&lt;/em&gt;&lt;em&gt;&lt;strong&gt;ntegration Support &lt;/strong&gt;&lt;/em&gt;- The new Management API allows for automation of everything that can be done by a content editor or developer in the back-office. This is important for deep integrations with external tools, marketing automations, and AI Agent connections.&lt;/li&gt;&#xA;&lt;li&gt;&lt;em&gt;&lt;strong&gt;Scalable Back-office&lt;/strong&gt;&lt;/em&gt; - Version 17 supports load-balancing the back-office. This allows the back-office to scale out like the front-end for performance and simplifies hosting load-balanced Umbraco websites.&lt;/li&gt;&#xA;&lt;li&gt;Read even more on the official v17 release article: &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://umbraco.com/blog/umbraco-17-lts-release/&quot; target=&quot;_blank&quot; title=&quot;Umbraco 17 LTS: Final Release&quot;&gt;Umbraco 17 LTS: Final Release&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;There is really a lot of truly great features available in version 17 and many more on the horizon in 18 and 19. It&#x27;s a perfect time to get this upgrade done so those other upgrades are less painful later.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;The sections below dive into the technical details of upgrading. If you&#x27;d rather have a conversation about what an upgrade means for your organization (timeline, budget, and business impact) we&#x27;re happy to help.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a style=&quot;color: #fff; background-image: none;&quot; type=&quot;external&quot; href=&quot;#section-footer&quot; title=&quot;Request an Initial Consultation&quot; class=&quot;pw-button&quot; data-anchor=&quot;#section-footer&quot;&gt;Schedule a Consultation&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2&gt;Prepare for Your Upgrade&lt;/h2&gt;&#xA;&lt;p&gt;A good result always starts with a good plan, right?&lt;/p&gt;&#xA;&lt;h4&gt;Current Umbraco Version?&lt;/h4&gt;&#xA;&lt;p&gt;First, you should assess where your site currently is. Are you on version 13? Or something older?&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Version 8-9:&lt;/strong&gt; You will need to upgrade to v10, then v13, then v17 - in fact, in general it is recommended to upgrade to each LTS version on your path to the latest. There may need to be custom migrations if the site uses Grid or other unsupported editors. Content migration may be preferable is some cases. v8 has API changes that could mean major code refactoring.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Version 10-12:&lt;/strong&gt; Upgrade to the latest v13, then to v17. Getting to v13 should be relatively straight-forward, but an assessment is always helpful for planning.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Version 13:&lt;/strong&gt; Upgrade to the latest version of v13, currently 13.13.0.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Learn more about each version here: &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://releases.umbraco.com/all-releases&quot; target=&quot;_blank&quot; title=&quot;https://releases.umbraco.com/all-releases&quot;&gt;https://releases.umbraco.com/all-releases&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;(Please feel free to &lt;a type=&quot;external&quot; href=&quot;#section-footer&quot; title=&quot;contact ProWorks&quot; data-anchor=&quot;#section-footer&quot;&gt;contact ProWorks&lt;/a&gt; and get our recommendations)&lt;/p&gt;&#xA;&lt;h4&gt;Using Outdated Property Editors?&lt;/h4&gt;&#xA;&lt;p&gt;If you are using any deprecated or legacy property editors, its best to update them to use the latest version in v13 before upgrading.&lt;/p&gt;&#xA;&lt;p&gt;Property editors to migrate to in v13:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;MediaPicker -&amp;gt; MediaPicker3&lt;/li&gt;&#xA;&lt;li&gt;Nested Content -&amp;gt; Block List&lt;/li&gt;&#xA;&lt;li&gt;Stacked Content -&amp;gt; Block List&lt;/li&gt;&#xA;&lt;li&gt;Grid -&amp;gt; Block Grid&lt;/li&gt;&#xA;&lt;li&gt;Macros -&amp;gt; Blocks (Or remove if unused)&lt;/li&gt;&#xA;&lt;li&gt;XPath in pickers -&amp;gt; Plan for a change to use the new dynamic root setup&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;By addressing these structural elements first, the content will migrate much easier to v17.&lt;/p&gt;&#xA;&lt;h4&gt;v17 Package Support?&lt;/h4&gt;&#xA;&lt;p&gt;Do you have Umbraco Packages installed (it&#x27;s likely)? Go to the Umbraco Marketplace (&lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://marketplace.umbraco.com/&quot; target=&quot;_blank&quot; title=&quot;https://marketplace.umbraco.com/&quot;&gt;https://marketplace.umbraco.com/&lt;/a&gt;) or the package Repository and verify that each package supports v17. Many of the most used packages are ready for v17 now. Some are working on it and may have a beta version that likely works well. Some may not have any v17 support.&lt;/p&gt;&#xA;&lt;p&gt;If you&#x27;re unsure and its not clear from the repo, then asking on the Umbraco Forums (&lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://forum.umbraco.com/&quot; target=&quot;_blank&quot; title=&quot;https://forum.umbraco.com/&quot;&gt;https://forum.umbraco.com/&lt;/a&gt;) would be a good way to see how others are dealing with this package. Is there a new version coming soon? Is there a new package that effectively replaces this one?&lt;/p&gt;&#xA;&lt;p&gt;As always,&#xA0;we can help give you a recommendation to move forward on. We have been doing this a long time and would love to help! &lt;a type=&quot;external&quot; href=&quot;#section-footer&quot; title=&quot;Contact Us&quot; data-anchor=&quot;#section-footer&quot;&gt;Connect with us below&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h4&gt;Custom/Bespoke Back-Office Extensions?&lt;/h4&gt;&#xA;&lt;p&gt;If your site has custom Angular.js extensions, then those will need to be re-written in the new Typescript/Lit/Web Components extension model. For the initial upgrade you can simply disable or remove them and address them after the main upgrade is complete.&lt;/p&gt;&#xA;&lt;h4&gt;Using Smidge?&lt;/h4&gt;&#xA;&lt;p&gt;Smidge was removed in v17 and you will need to reinstall it if used by any custom code or by the site in general. It is straight-forward to re-add to your site and you can learn more on the Github repo: &lt;a href=&quot;https://github.com/Shazwazza/Smidge&quot;&gt;https://github.com/Shazwazza/Smidge&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;There is also an Umbraco-specific package that you can install here: &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://marketplace.umbraco.com/package/umbraco.community.smidge&quot; target=&quot;_blank&quot; title=&quot;https://marketplace.umbraco.com/package/umbraco.community.smidge&quot;&gt;https://marketplace.umbraco.com/package/umbraco.community.smidge&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h4&gt;TipTap or TinyMCE?&lt;/h4&gt;&#xA;&lt;p&gt;Umbraco has migrated to a new RTE component called TipTap. It will migrate all of your RTEs to this new editor by default unless you install a community package, &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://github.com/ProWorksCorporation/TinyMCE-Umbraco&quot; target=&quot;_blank&quot; title=&quot;TinyMCE.Umbraco Github Repository&quot;&gt;TinyMCE.Umbraco&lt;/a&gt;. This package will prevent the migration and keep the TinyMCE editor installed and used as in previous versions. &lt;a href=&quot;/blog/archive/tinymceumbraco-v17-released-and-ready-for-umbraco-17/&quot; title=&quot;TinyMCE.Umbraco v17 Released and Ready for Umbraco 17&quot;&gt;Read more about TinyMCE.Umbraco v17 in this post&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;You will need to decide if you want to keep using TinyMCE or move to TipTap. If you have TinyMCE customizations or complex RTE setups, you may want to keep TinyMCE. The package also gives you the option of easily adding premium features like AI tools. TipTap is based on ProseMirror and is more lightweight so may be preferred in some use cases.&lt;/p&gt;&#xA;&lt;h4&gt;Use Umbraco Forms?&lt;/h4&gt;&#xA;&lt;p&gt;If you use Umbraco Forms, then you may need to migrate to the new licensing structure. It is now licensed annually instead of a one-time cost. Umbraco Forms is included with Umbraco Cloud so this is less of a concern if you are hosted on Umbraco Cloud. Your choice is to license Umbraco Forms going forward or remove it in favor of a different solution.&lt;/p&gt;&#xA;&lt;h4&gt;Review Official Documentation:&lt;/h4&gt;&#xA;&lt;p&gt;Take a look at the Version Specific Upgrades documentation guide in the Official Umbraco Documentation: &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific&quot; target=&quot;_blank&quot; title=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific&quot;&gt;Version Specific Upgrades&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;There may be other key breaking changes highlighted there that will be important for your site.&lt;/p&gt;&#xA;&lt;p&gt;Also, the Upgrade Details document has information on some edge cases and older versions as well: &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/upgrade-details&quot; target=&quot;_blank&quot; title=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/upgrade-details&quot;&gt;Upgrade Details&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2&gt;Pre-Upgrade Process&lt;/h2&gt;&#xA;&lt;p&gt;I&#x27;ll assume you have solutions for all the above issues and are ready to try out an upgrade! Great! Now, take a step to make sure you have all of this in place:&lt;/p&gt;&#xA;&lt;h4&gt;Backup Your Database / Media&lt;/h4&gt;&#xA;&lt;p&gt;Always backup your database before starting. You will miss something and may need to iterate a few times to get the migrations just right.&lt;/p&gt;&#xA;&lt;p&gt;Also, now is a good time to get a backup of the latest media and pull it locally.&lt;/p&gt;&#xA;&lt;h4&gt;Side-by-Side Setup&lt;/h4&gt;&#xA;&lt;p&gt;Ideally, you have a v13 site for reference running locally and your future v17 site ready to upgrade. These should be using separate databases and be able to run completely side-by-side. This lets you quickly iterate with v13 changes and re-run the v17 upgrade as needed. In addition, this allows you to quickly verify that the site looks and works as expected.&lt;/p&gt;&#xA;&lt;p&gt;If you&#x27;re using Git, make sure you have each version on separate feature branches.&lt;/p&gt;&#xA;&lt;h4&gt;Verify Dev Setup&lt;/h4&gt;&#xA;&lt;p&gt;Get your development setup ready for .NET 10 and Umbraco v17:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Install .NET 10 SDK&lt;/li&gt;&#xA;&lt;li&gt;Update Visual Studio (2022 v17.12&#x2B; or 2026)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4&gt;Verify Latest v13&lt;/h4&gt;&#xA;&lt;p&gt;One last check to make sure you&#x27;re on the latest Umbraco v13 release. If not, do this first.&lt;/p&gt;&#xA;&lt;h2&gt;Upgrade Time!&lt;/h2&gt;&#xA;&lt;p&gt;Let&#x27;s do this.&lt;/p&gt;&#xA;&lt;h4&gt;1. Update Project Target Frameworks&lt;/h4&gt;&#xA;&lt;p&gt;This can be done directly in the .csproj files through the TargetFramework element:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;    &amp;lt;!-- Change target framework --&amp;gt;&#xA;    &amp;lt;TargetFramework&amp;gt;net10.0&amp;lt;/TargetFramework&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h4&gt;2. Update Nuget Packages&lt;/h4&gt;&#xA;&lt;p&gt;Update all Umbraco packages to version 17.latest:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Cms&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Cms.Web.Website&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;If using Umbraco Cloud update these as well:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Cloud.Cms&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Cloud.StorageProviders.AzureBlob&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Deploy.Cloud&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Deploy.Contrib&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Remove these packages as they aren&#x27;t needed for v17:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Cloud.Cms.PublicAccess&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Cloud.Identity.Cms&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Cms.Web.BackOffice&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Update all other packages used including Umbraco Extensions like:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Community.Contentment&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Forms&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Any other packages used that support v17&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4&gt;3. Delete Build Artifacts&lt;/h4&gt;&#xA;&lt;p&gt;Delete all of the&#xA0;&lt;code&gt;bin&lt;/code&gt; and &lt;code&gt;obj&lt;/code&gt; directories in each of the projects of your solution. Umbraco has reported that Visual Studio&#x27;s &quot;Clean Solution&quot; option is sometimes not enough.&lt;/p&gt;&#xA;&lt;h4&gt;4. Code Changes&lt;/h4&gt;&#xA;&lt;p&gt;There are a few code changes needed to get the Solution compiling.&lt;/p&gt;&#xA;&lt;h5&gt;Program.cs:&lt;/h5&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Remove&#xA0;&lt;code&gt;UseInstallerEndpoints()&lt;/code&gt;&#xA0;as this is now automatically setup in v17&lt;/li&gt;&#xA;&lt;li&gt;Consider comparing a fresh installed Umbraco v17 &lt;strong&gt;Program.cs&lt;/strong&gt; with your current code and verify that you have the latest patterns in place. I have found other areas that were missing and easy to miss.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h5&gt;_ViewImports.cshtml:&lt;/h5&gt;&#xA;&lt;div&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Remove Smidge references:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/div&gt;&#xA;&lt;pre&gt;&lt;code&gt;@* REMOVE these lines: *@&#xA;@addTagHelper *, Smidge&#xA;@inject Smidge.SmidgeHelper SmidgeHelper&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h5&gt;Generated Models&lt;/h5&gt;&#xA;&lt;p&gt;If you used strongly typed models and have Umbraco generate them to code files in your project/solution, then the solution likely won&#x27;t compile.&lt;/p&gt;&#xA;&lt;p&gt;You have two options:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Delete all generated models from the directory in your project and set the &lt;code&gt;Umbraco.Cms.ModelsBuilder.ModelsMode&lt;/code&gt; to &quot;InMemoryAuto&quot; from &quot;SourceCodeAuto&quot; or &quot;SourceCodeManual&quot;. This will allow you to run the upgrade then switch it back and regenerate them after the v17 back-office is working. If you do this, you will need to install the &lt;code&gt;Umbraco.Cms.DevelopmentMode.Backoffice&lt;/code&gt; to allow the &quot;InMemoryAuto&quot; mode to work in v17.&lt;/li&gt;&#xA;&lt;li&gt;Tweak the v13 generated models so they compile and regenerate them after the v17 back-office is working. This involves:&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Changing &lt;code&gt;IPublishedContent&lt;/code&gt; from:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;global::Umbraco.Cms.Core.Models.PublishedContent.IPublishedContent Image { get; }&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;To &lt;code&gt;MediaWithCrops&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;&#xA;global::Umbraco.Cms.Core.Models.MediaWithCrops Image { get; }&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Watch for &lt;code&gt;IEnumerable&lt;/code&gt; references as well as they need to be changed to use &lt;code&gt;MediaWithCrops&lt;/code&gt; as well. Then fix any other build errors that you see.&lt;/p&gt;&#xA;&lt;p&gt;Ultimately you want to run the back-office so you can regenerate them. So editing them manually is a temporary solution if you&#x27;re having trouble compiling the solution.&lt;/p&gt;&#xA;&lt;h4&gt;5. Configure Razor Files for .NET v10&lt;/h4&gt;&#xA;&lt;h5&gt;Verify Runtime Modes&lt;/h5&gt;&#xA;&lt;p&gt;.NET 10 deprecated runtime Razor compilation. Views are now compiled at build time by default.&lt;/p&gt;&#xA;&lt;p&gt;Verify your .csproj has the following:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;   &amp;lt;PropertyGroup&amp;gt;&#xA;      &amp;lt;CopyRazorGenerateFilesToPublishDirectory&amp;gt;true&amp;lt;/CopyRazorGenerateFilesToPublishDirectory&amp;gt;&#xA;   &amp;lt;/PropertyGroup&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I recommend compiling your Razor files to find any issues at build time instead of at runtime. Remove these lines from your .csproj:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;      &amp;lt;RazorCompileOnBuild&amp;gt;false&amp;lt;/RazorCompileOnBuild&amp;gt;&#xA;      &amp;lt;RazorCompileOnPublish&amp;gt;false&amp;lt;/RazorCompileOnPublish&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;More on Runtime modes from the Umbraco Documentation: &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/runtime-modes&quot; target=&quot;_blank&quot; title=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/runtime-modes&quot;&gt;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/runtime-modes&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;If you need to restore the runtime Razor view compilation or want to use &lt;code&gt;InMemoryAuto&lt;/code&gt; model building, then you will need to install this package:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;dotnet add package Umbraco.Cms.DevelopmentMode.Backoffice&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Read more in the Version Specific Guide to determine if you need this package: &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific#umbraco-17&quot; target=&quot;_blank&quot; title=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific#umbraco-17&quot; data-anchor=&quot;#umbraco-17&quot;&gt;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific#umbraco-17&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h4&gt;6. Optional: Disable Custom Packages&lt;/h4&gt;&#xA;&lt;p&gt;If you are planning to migrate custom back-office packages after the initial upgrade is complete, then you could simply disable any custom code and exclude it from the project.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Rename folders in &lt;code&gt;App_Plugins&lt;/code&gt; with custom extensions to have &quot;.disabled&quot; at the end of the folder name.&lt;/li&gt;&#xA;&lt;li&gt;Update the &lt;code&gt;App_Plugins&lt;/code&gt; content include entry in the .csproj to exclude any folders with &quot;.disabled&quot; at the end:&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;pre&gt;&lt;code&gt;      &amp;lt;Content Include=&quot;App_Plugins\**&quot; Exclude=&quot;App_Plugins\*.disabled\**&quot;&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;If you have extensions added via Razor Class Library, you may need to remove the reference or delete the .dll from the &lt;code&gt;bin&lt;/code&gt; folder. &#xA0;&lt;/p&gt;&#xA;&lt;h4&gt;7. Optional: Explicitly Set LocalTimeZone&lt;/h4&gt;&#xA;&lt;p&gt;The change to use UTC by default for System Dates may have implications for your site. Read more in the Version Specific Guide on whether you want to explicitly set a server time zone in appsettings.json.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific#umbraco-17&quot; target=&quot;_blank&quot; title=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific#umbraco-17&quot; data-anchor=&quot;#umbraco-17&quot;&gt;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific#umbraco-17&lt;/a&gt;&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;{&#xA;   &quot;Umbraco&quot;: {&#xA;      &quot;CMS&quot;: {&#xA;         &quot;SystemDateMigration&quot;: {&#xA;            &quot;LocalServerTimeZone&quot;: &quot;Eastern Standard Time&quot;&#xA;         }&#xA;      }&#xA;   }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h4&gt;8. Licensing Changes&lt;/h4&gt;&#xA;&lt;p&gt;If you are using Umbraco Deploy or Umbraco Forms, then you will need to migrate the licensing from the file-based .lic to the configuration settings in appsettings.json&lt;/p&gt;&#xA;&lt;h5&gt;Remove .lic Files&lt;/h5&gt;&#xA;&lt;p&gt;Remove the &lt;code&gt;.lic&lt;/code&gt; files inside of the &lt;code&gt;umbraco/Licenses&lt;/code&gt; folder for Umbraco Deploy and Umbraco Forms.&lt;/p&gt;&#xA;&lt;h5&gt;Add Licensing Configuration&lt;/h5&gt;&#xA;&lt;p&gt;For Umbraco Cloud sites, you can add these settings to your appsettings.json file. If you have a different hosting setup, you will need to replace &quot;UMBRACO-CLOUD&quot; with your license key.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;{&#xA;&#xA0; &quot;Umbraco&quot;: {&#xA;&#xA0; &#xA0; &quot;Licenses&quot;: {&#xA;&#xA0; &#xA0; &#xA0; &quot;Products&quot;: {&#xA;&#xA0; &#xA0; &#xA0; &#xA0; &quot;Umbraco.Forms&quot;: &quot;UMBRACO-CLOUD&quot;,&#xA;&#xA0; &#xA0; &#xA0; &#xA0; &quot;Umbraco.Deploy&quot;: &quot;UMBRACO-CLOUD&quot;&#xA;&#xA0; &#xA0; &#xA0; }&#xA;&#xA0; &#xA0; }&#xA;&#xA0; }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2&gt;Build, Run, and Test!&lt;/h2&gt;&#xA;&lt;p&gt;Is the site rendering as expected? Does the back-office load and you are able to login? If yes, you&#x27;re on your way to v17.&lt;/p&gt;&#xA;&lt;p&gt;Now its time to perform your detailed regression testing by verifying all the packages migrated as expected, all property editors are working as expected, and you can make changes as you would expect.&lt;/p&gt;&#xA;&lt;p&gt;Here are some items you may want to focus on to verify the upgrade:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The site builds without errors&lt;/li&gt;&#xA;&lt;li&gt;All pages render correctly&lt;/li&gt;&#xA;&lt;li&gt;Backoffice login works&lt;/li&gt;&#xA;&lt;li&gt;Content editing works&lt;/li&gt;&#xA;&lt;li&gt;No console errors/warnings&lt;/li&gt;&#xA;&lt;li&gt;Block List editors function&lt;/li&gt;&#xA;&lt;li&gt;Rich text editors function&lt;/li&gt;&#xA;&lt;li&gt;Media uploads work&lt;/li&gt;&#xA;&lt;li&gt;Search returns results&lt;/li&gt;&#xA;&lt;li&gt;Licenses show as valid&lt;/li&gt;&#xA;&lt;li&gt;Forms submit and save entries&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2&gt;Migrating Custom Extensions to v17&lt;/h2&gt;&#xA;&lt;div&gt;Once the back-office and site appear to be working, it&#x27;s time to migrate those custom extensions to v17. That process is out of scope for this article, but here are some resources to get you started:&lt;/div&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://docs.umbraco.com/umbraco-cms/extending/property-editors&quot; target=&quot;_blank&quot; title=&quot;Building Property Editors in v17&quot;&gt;Building Property Editors in v17&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://docs.umbraco.com/umbraco-cms/customizing/ui-library&quot; target=&quot;_blank&quot; title=&quot;Umbraco UI Library&quot;&gt;Umbraco UI Library&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://kjac.dev/posts/migrating-extensions-from-umbraco-13-to-17/&quot; target=&quot;_blank&quot; title=&quot;Migrating Extensions from v13 to v17&quot;&gt;Migrating Extensions from v13 to v17&lt;/a&gt; by Kenn Jacobsen&lt;/li&gt;&#xA;&lt;li&gt;&lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://24days.in/umbraco-cms/2024/switching-to-web-components/)&quot; target=&quot;_blank&quot; title=&quot;From AngularJS to Web Components&quot;&gt;From AngularJS to Web Components&lt;/a&gt; by Jesper Mayntzhusen&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h2&gt;&#xA;&lt;p&gt;Upgrading to v17 is worth the effort as it is the Umbraco version to take the community into the future. AI, modern web frameworks, enterprise features, and so much more make this an upgrade to prioritize. With v13 support ending December 14th, 2026 the time to start planning an upgrade is now.&lt;/p&gt;&#xA;&lt;h2&gt;Need help with your Umbraco upgrade?&lt;/h2&gt;&#xA;&lt;p&gt;Reach out to us for an initial consultation so we can help make your upgrade a success!&lt;/p&gt;&#xA;&lt;p&gt;&lt;a style=&quot;color: #fff; background-image: none;&quot; type=&quot;external&quot; href=&quot;#section-footer&quot; title=&quot;Schedule a Consultation&quot; class=&quot;pw-button&quot; data-anchor=&quot;#section-footer&quot;&gt;Schedule a Consultation&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2 id=&quot;change-log&quot;&gt;Change Log&lt;/h2&gt;&#xA;&lt;div&gt;2026-01-22: Initial Version&lt;/div&gt;]]></description>
                    <pubDate>Thu, 22 Jan 2026 10:20:17 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.proworks.com/blog/archive/upgrading-from-umbraco-13-to-17-lts-lessons-from-the-trenches/</guid>
                    <title>Upgrading from Umbraco 13 to 17 LTS: Lessons from the Trenches</title>
                    <link>https://www.proworks.com/blog/archive/upgrading-from-umbraco-13-to-17-lts-lessons-from-the-trenches/</link>
                    <description><![CDATA[&lt;p&gt;Upgrades, upgrades, upgrades!&#xA0; Upgrades are a hot topic in the Umbraco community ever since version 17 was released last November. There are a lot of great reasons to upgrade to this major version besides simply moving to the latest Long-Term Supported (LTS) version. Our team here at ProWorks has a ton of Umbraco upgrade experience and are here to help you make your upgrade a success. This article will update as we learn about new challenges and find solutions. Ready? Let&#x27;s do this!&lt;/p&gt;&#xA;&lt;p&gt;&lt;a type=&quot;external&quot; href=&quot;#final-thoughts&quot; title=&quot;See the changelog at the bottom if you&#x27;re coming back to this after a while&quot; data-anchor=&quot;#final-thoughts&quot;&gt;See the changelog at the bottom if you&#x27;re coming back to this after a while&lt;/a&gt; - &lt;em&gt;Updated: January 22, 2026&lt;/em&gt;&lt;/p&gt;&#xA;&lt;h2&gt;Why Upgrade?&lt;/h2&gt;&#xA;&lt;p&gt;Let&#x27;s look at why you would upgrade to the latest v17 version:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;em&gt;&lt;strong&gt;Most recent LTS&#xA0;version&lt;/strong&gt;&lt;/em&gt; - stay up to date with security patches and easiest to keep up to date in the future. Umbraco 17 is supported through November 27, 2028.&lt;/li&gt;&#xA;&lt;li&gt;&lt;em&gt;&lt;strong&gt;Performance improvements&lt;/strong&gt;&lt;/em&gt; - The rebuilt HybridCache speeds up startups especially on large sites. The latest .NET version 10 framework also improves performance.&lt;/li&gt;&#xA;&lt;li&gt;&lt;em&gt;&lt;strong&gt;Modern back-office SPA&lt;/strong&gt;&lt;/em&gt; - Rebuilt back-office allows for standards-based extensions and future-proofed architecture that no longer relies on Angular or other external large frameworks.&lt;/li&gt;&#xA;&lt;li&gt;&lt;em&gt;&lt;strong&gt;Deep AI Chat Integrations with Umbraco MCP&lt;/strong&gt;&lt;/em&gt;&#xA0;- The official Umbraco MCP Server only works on version 17 and allows AI to &quot;talk&quot; to your specific Umbraco back-office to report on, add, or modify content.&lt;/li&gt;&#xA;&lt;li&gt;&lt;em&gt;&lt;strong&gt;Full Management API&lt;/strong&gt;&lt;/em&gt; - This allows for automation of everything that can be done by a content editor or developer in the back-office.&lt;/li&gt;&#xA;&lt;li&gt;&lt;em&gt;&lt;strong&gt;Load-balancing the Back-office&lt;/strong&gt;&lt;/em&gt; - This allows the back-office to scale out like the front-end and simplifies hosting load-balanced Umbraco websites.&lt;/li&gt;&#xA;&lt;li&gt;Read even more on the official v17 release article: &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://umbraco.com/blog/umbraco-17-lts-release/&quot; target=&quot;_blank&quot; title=&quot;Umbraco 17 LTS: Final Release&quot;&gt;Umbraco 17 LTS: Final Release&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;There is really a lot of truly great features available in version 17 and many more on the horizon in 18 and 19. It&#x27;s a perfect time to get this upgrade done so those other upgrades are less painful later.&lt;/p&gt;&#xA;&lt;h2&gt;Prepare for Your Upgrade&lt;/h2&gt;&#xA;&lt;p&gt;A good result always starts with a good plan, right?&lt;/p&gt;&#xA;&lt;h4&gt;Current Umbraco Version?&lt;/h4&gt;&#xA;&lt;p&gt;First, you should assess where your site currently is. Are you on version 13? Or something older?&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Version 8-9:&lt;/strong&gt; You will need to upgrade to v10, then v13, then v17 - in fact, in general it is recommended to upgrade to each LTS version on your path to the latest. There may need to be custom migrations if the site uses Grid or other unsupported editors. Content migration may be preferable is some cases. v8 has API changes that could mean major code refactoring.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Version 10-12:&lt;/strong&gt; Upgrade to the latest v13, then to v17. Getting to v13 should be relatively straight-forward, but an assessment is always helpful for planning.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Version 13:&lt;/strong&gt; Upgrade to the latest version of v13, currently 13.13.0.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Learn more about each version here: &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://releases.umbraco.com/all-releases&quot; target=&quot;_blank&quot; title=&quot;https://releases.umbraco.com/all-releases&quot;&gt;https://releases.umbraco.com/all-releases&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;(Please feel free to &lt;a type=&quot;external&quot; href=&quot;#section-footer&quot; title=&quot;contact ProWorks&quot; data-anchor=&quot;#section-footer&quot;&gt;contact ProWorks&lt;/a&gt; and get our recommendations)&lt;/p&gt;&#xA;&lt;h4&gt;Using Outdated Property Editors?&lt;/h4&gt;&#xA;&lt;p&gt;If you are using any deprecated or legacy property editors, its best to update them to use the latest version in v13 before upgrading.&lt;/p&gt;&#xA;&lt;p&gt;Property editors to migrate to in v13:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;MediaPicker -&amp;gt; MediaPicker3&lt;/li&gt;&#xA;&lt;li&gt;Nested Content -&amp;gt; Block List&lt;/li&gt;&#xA;&lt;li&gt;Stacked Content -&amp;gt; Block List&lt;/li&gt;&#xA;&lt;li&gt;Grid -&amp;gt; Block Grid&lt;/li&gt;&#xA;&lt;li&gt;Macros -&amp;gt; Blocks (Or remove if unused)&lt;/li&gt;&#xA;&lt;li&gt;XPath in pickers -&amp;gt; Plan for a change to use the new dynamic root setup&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;By addressing these structural elements first, the content will migrate much easier to v17.&lt;/p&gt;&#xA;&lt;h4&gt;v17 Package Support?&lt;/h4&gt;&#xA;&lt;p&gt;Do you have Umbraco Packages installed (it&#x27;s likely)? Go to the Umbraco Marketplace (&lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://marketplace.umbraco.com/&quot; target=&quot;_blank&quot; title=&quot;https://marketplace.umbraco.com/&quot;&gt;https://marketplace.umbraco.com/&lt;/a&gt;) or the package Repository and verify that each package supports v17. Many of the most used packages are ready for v17 now. Some are working on it and may have a beta version that likely works well. Some may not have any v17 support.&lt;/p&gt;&#xA;&lt;p&gt;If you&#x27;re unsure and its not clear from the repo, then asking on the Umbraco Forums (&lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://forum.umbraco.com/&quot; target=&quot;_blank&quot; title=&quot;https://forum.umbraco.com/&quot;&gt;https://forum.umbraco.com/&lt;/a&gt;) would be a good way to see how others are dealing with this package. Is there a new version coming soon? Is there a new package that effectively replaces this one?&lt;/p&gt;&#xA;&lt;p&gt;As always,&#xA0;we can help give you a recommendation to move forward on. We have been doing this a long time and would love to help! &lt;a type=&quot;external&quot; href=&quot;#section-footer&quot; title=&quot;Contact Us&quot; data-anchor=&quot;#section-footer&quot;&gt;Connect with us below&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h4&gt;Custom/Bespoke Back-Office Extensions?&lt;/h4&gt;&#xA;&lt;p&gt;If your site has custom Angular.js extensions, then those will need to be re-written in the new Typescript/Lit/Web Components extension model. For the initial upgrade you can simply disable or remove them and address them after the main upgrade is complete.&lt;/p&gt;&#xA;&lt;h4&gt;Using Smidge?&lt;/h4&gt;&#xA;&lt;p&gt;Smidge was removed in v17 and you will need to reinstall it if used by any custom code or by the site in general. It is straight-forward to re-add to your site and you can learn more on the Github repo: &lt;a href=&quot;https://github.com/Shazwazza/Smidge&quot;&gt;https://github.com/Shazwazza/Smidge&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;There is also an Umbraco-specific package that you can install here: &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://marketplace.umbraco.com/package/umbraco.community.smidge&quot; target=&quot;_blank&quot; title=&quot;https://marketplace.umbraco.com/package/umbraco.community.smidge&quot;&gt;https://marketplace.umbraco.com/package/umbraco.community.smidge&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h4&gt;TipTap or TinyMCE?&lt;/h4&gt;&#xA;&lt;p&gt;Umbraco has migrated to a new RTE component called TipTap. It will migrate all of your RTEs to this new editor by default unless you install a community package, &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://github.com/ProWorksCorporation/TinyMCE-Umbraco&quot; target=&quot;_blank&quot; title=&quot;TinyMCE.Umbraco Github Repository&quot;&gt;TinyMCE.Umbraco&lt;/a&gt;. This package will prevent the migration and keep the TinyMCE editor installed and used as in previous versions. &lt;a href=&quot;/blog/archive/tinymceumbraco-v17-released-and-ready-for-umbraco-17/&quot; title=&quot;TinyMCE.Umbraco v17 Released and Ready for Umbraco 17&quot;&gt;Read more about TinyMCE.Umbraco v17 in this post&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;You will need to decide if you want to keep using TinyMCE or move to TipTap. If you have TinyMCE customizations or complex RTE setups, you may want to keep TinyMCE. The package also gives you the option of easily adding premium features like AI tools. TipTap is based on ProseMirror and is more lightweight so may be preferred in some use cases.&lt;/p&gt;&#xA;&lt;h4&gt;Use Umbraco Forms?&lt;/h4&gt;&#xA;&lt;p&gt;If you use Umbraco Forms, then you may need to migrate to the new licensing structure. It is now licensed annually instead of a one-time cost. Umbraco Forms is included with Umbraco Cloud so this is less of a concern if you are hosted on Umbraco Cloud. Your choice is to license Umbraco Forms going forward or remove it in favor of a different solution.&lt;/p&gt;&#xA;&lt;h4&gt;Review Official Documentation:&lt;/h4&gt;&#xA;&lt;p&gt;Take a look at the Version Specific Upgrades documentation guide in the Official Umbraco Documentation: &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific&quot; target=&quot;_blank&quot; title=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific&quot;&gt;Version Specific Upgrades&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;There may be other key breaking changes highlighted there that will be important for your site.&lt;/p&gt;&#xA;&lt;p&gt;Also, the Upgrade Details document has information on some edge cases and older versions as well: &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/upgrade-details&quot; target=&quot;_blank&quot; title=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/upgrade-details&quot;&gt;Upgrade Details&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2&gt;Pre-Upgrade Process&lt;/h2&gt;&#xA;&lt;p&gt;I&#x27;ll assume you have solutions for all the above issues and are ready to try out an upgrade! Great! Now, take a step to make sure you have all of this in place:&lt;/p&gt;&#xA;&lt;h4&gt;Backup Your Database / Media&lt;/h4&gt;&#xA;&lt;p&gt;Always backup your database before starting. You will miss something and may need to iterate a few times to get the migrations just right.&lt;/p&gt;&#xA;&lt;p&gt;Also, now is a good time to get a backup of the latest media and pull it locally.&lt;/p&gt;&#xA;&lt;h4&gt;Side-by-Side Setup&lt;/h4&gt;&#xA;&lt;p&gt;Ideally, you have a v13 site for reference running locally and your future v17 site ready to upgrade. These should be using separate databases and be able to run completely side-by-side. This lets you quickly iterate with v13 changes and re-run the v17 upgrade as needed. In addition, this allows you to quickly verify that the site looks and works as expected.&lt;/p&gt;&#xA;&lt;p&gt;If you&#x27;re using Git, make sure you have each version on separate feature branches.&lt;/p&gt;&#xA;&lt;h4&gt;Verify Dev Setup&lt;/h4&gt;&#xA;&lt;p&gt;Get your development setup ready for .NET 10 and Umbraco v17:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Install .NET 10 SDK&lt;/li&gt;&#xA;&lt;li&gt;Update Visual Studio (2022 v17.12&#x2B; or 2026)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4&gt;Verify Latest v13&lt;/h4&gt;&#xA;&lt;p&gt;One last check to make sure you&#x27;re on the latest Umbraco v13 release. If not, do this first.&lt;/p&gt;&#xA;&lt;h2&gt;Upgrade Time!&lt;/h2&gt;&#xA;&lt;p&gt;Let&#x27;s do this.&lt;/p&gt;&#xA;&lt;h4&gt;1. Update Project Target Frameworks&lt;/h4&gt;&#xA;&lt;p&gt;This can be done directly in the .csproj files through the TargetFramework element:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;    &amp;lt;!-- Change target framework --&amp;gt;&#xA;    &amp;lt;TargetFramework&amp;gt;net10.0&amp;lt;/TargetFramework&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h4&gt;2. Update Nuget Packages&lt;/h4&gt;&#xA;&lt;p&gt;Update all Umbraco packages to version 17.latest:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Cms&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Cms.Web.Website&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;If using Umbraco Cloud update these as well:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Cloud.Cms&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Cloud.StorageProviders.AzureBlob&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Deploy.Cloud&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Deploy.Contrib&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Remove these packages as they aren&#x27;t needed for v17:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Cloud.Cms.PublicAccess&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Cloud.Identity.Cms&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Cms.Web.BackOffice&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Update all other packages used including Umbraco Extensions like:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Community.Contentment&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Umbraco.Forms&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Any other packages used that support v17&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4&gt;3. Delete Build Artifacts&lt;/h4&gt;&#xA;&lt;p&gt;Delete all of the&#xA0;&lt;code&gt;bin&lt;/code&gt; and &lt;code&gt;obj&lt;/code&gt; directories in each of the projects of your solution. Umbraco has reported that Visual Studio&#x27;s &quot;Clean Solution&quot; option is sometimes not enough.&lt;/p&gt;&#xA;&lt;h4&gt;4. Code Changes&lt;/h4&gt;&#xA;&lt;p&gt;There are a few code changes needed to get the Solution compiling.&lt;/p&gt;&#xA;&lt;h5&gt;Program.cs:&lt;/h5&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Remove&#xA0;&lt;code&gt;UseInstallerEndpoints()&lt;/code&gt;&#xA0;as this is now automatically setup in v17&lt;/li&gt;&#xA;&lt;li&gt;Consider comparing a fresh installed Umbraco v17 &lt;strong&gt;Program.cs&lt;/strong&gt; with your current code and verify that you have the latest patterns in place. I have found other areas that were missing and easy to miss.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h5&gt;_ViewImports.cshtml:&lt;/h5&gt;&#xA;&lt;div&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Remove Smidge references:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/div&gt;&#xA;&lt;pre&gt;&lt;code&gt;@* REMOVE these lines: *@&#xA;@addTagHelper *, Smidge&#xA;@inject Smidge.SmidgeHelper SmidgeHelper&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h5&gt;Generated Models&lt;/h5&gt;&#xA;&lt;p&gt;If you used strongly typed models and have Umbraco generate them to code files in your project/solution, then the solution likely won&#x27;t compile.&lt;/p&gt;&#xA;&lt;p&gt;You have two options:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Delete all generated models from the directory in your project and set the &lt;code&gt;Umbraco.Cms.ModelsBuilder.ModelsMode&lt;/code&gt; to &quot;InMemoryAuto&quot; from &quot;SourceCodeAuto&quot; or &quot;SourceCodeManual&quot;. This will allow you to run the upgrade then switch it back and regenerate them after the v17 back-office is working. If you do this, you will need to install the &lt;code&gt;Umbraco.Cms.DevelopmentMode.Backoffice&lt;/code&gt; to allow the &quot;InMemoryAuto&quot; mode to work in v17.&lt;/li&gt;&#xA;&lt;li&gt;Tweak the v13 generated models so they compile and regenerate them after the v17 back-office is working. This involves:&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Changing &lt;code&gt;IPublishedContent&lt;/code&gt; from:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;global::Umbraco.Cms.Core.Models.PublishedContent.IPublishedContent Image { get; }&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;To &lt;code&gt;MediaWithCrops&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;&#xA;global::Umbraco.Cms.Core.Models.MediaWithCrops Image { get; }&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Watch for &lt;code&gt;IEnumerable&lt;/code&gt; references as well as they need to be changed to use &lt;code&gt;MediaWithCrops&lt;/code&gt; as well. Then fix any other build errors that you see.&lt;/p&gt;&#xA;&lt;p&gt;Ultimately you want to run the back-office so you can regenerate them. So editing them manually is a temporary solution if you&#x27;re having trouble compiling the solution.&lt;/p&gt;&#xA;&lt;h4&gt;5. Configure Razor Files for .NET v10&lt;/h4&gt;&#xA;&lt;h5&gt;Verify Runtime Modes&lt;/h5&gt;&#xA;&lt;p&gt;.NET 10 deprecated runtime Razor compilation. Views are now compiled at build time by default.&lt;/p&gt;&#xA;&lt;p&gt;Verify your .csproj has the following:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;   &amp;lt;PropertyGroup&amp;gt;&#xA;      &amp;lt;CopyRazorGenerateFilesToPublishDirectory&amp;gt;true&amp;lt;/CopyRazorGenerateFilesToPublishDirectory&amp;gt;&#xA;   &amp;lt;/PropertyGroup&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I recommend compiling your Razor files to find any issues at build time instead of at runtime. Remove these lines from your .csproj:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;      &amp;lt;RazorCompileOnBuild&amp;gt;false&amp;lt;/RazorCompileOnBuild&amp;gt;&#xA;      &amp;lt;RazorCompileOnPublish&amp;gt;false&amp;lt;/RazorCompileOnPublish&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;More on Runtime modes from the Umbraco Documentation: &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/runtime-modes&quot; target=&quot;_blank&quot; title=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/runtime-modes&quot;&gt;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/runtime-modes&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;If you need to restore the runtime Razor view compilation or want to use &lt;code&gt;InMemoryAuto&lt;/code&gt; model building, then you will need to install this package:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;dotnet add package Umbraco.Cms.DevelopmentMode.Backoffice&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Read more in the Version Specific Guide to determine if you need this package: &lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific#umbraco-17&quot; target=&quot;_blank&quot; title=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific#umbraco-17&quot; data-anchor=&quot;#umbraco-17&quot;&gt;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific#umbraco-17&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h4&gt;6. Optional: Disable Custom Packages&lt;/h4&gt;&#xA;&lt;p&gt;If you are planning to migrate custom back-office packages after the initial upgrade is complete, then you could simply disable any custom code and exclude it from the project.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Rename folders in &lt;code&gt;App_Plugins&lt;/code&gt; with custom extensions to have &quot;.disabled&quot; at the end of the folder name.&lt;/li&gt;&#xA;&lt;li&gt;Update the &lt;code&gt;App_Plugins&lt;/code&gt; content include entry in the .csproj to exclude any folders with &quot;.disabled&quot; at the end:&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;pre&gt;&lt;code&gt;      &amp;lt;Content Include=&quot;App_Plugins\**&quot; Exclude=&quot;App_Plugins\*.disabled\**&quot;&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;If you have extensions added via Razor Class Library, you may need to remove the reference or delete the .dll from the &lt;code&gt;bin&lt;/code&gt; folder. &#xA0;&lt;/p&gt;&#xA;&lt;h4&gt;7. Optional: Explicitly Set LocalTimeZone&lt;/h4&gt;&#xA;&lt;p&gt;The change to use UTC by default for System Dates may have implications for your site. Read more in the Version Specific Guide on whether you want to explicitly set a server time zone in appsettings.json.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific#umbraco-17&quot; target=&quot;_blank&quot; title=&quot;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific#umbraco-17&quot; data-anchor=&quot;#umbraco-17&quot;&gt;https://docs.umbraco.com/umbraco-cms/fundamentals/setup/upgrading/version-specific#umbraco-17&lt;/a&gt;&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;{&#xA;   &quot;Umbraco&quot;: {&#xA;      &quot;CMS&quot;: {&#xA;         &quot;SystemDateMigration&quot;: {&#xA;            &quot;LocalServerTimeZone&quot;: &quot;Eastern Standard Time&quot;&#xA;         }&#xA;      }&#xA;   }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h4&gt;8. Licensing Changes&lt;/h4&gt;&#xA;&lt;p&gt;If you are using Umbraco Deploy or Umbraco Forms, then you will need to migrate the licensing from the file-based .lic to the configuration settings in appsettings.json&lt;/p&gt;&#xA;&lt;h5&gt;Remove .lic Files&lt;/h5&gt;&#xA;&lt;p&gt;Remove the &lt;code&gt;.lic&lt;/code&gt; files inside of the &lt;code&gt;umbraco/Licenses&lt;/code&gt; folder for Umbraco Deploy and Umbraco Forms.&lt;/p&gt;&#xA;&lt;h5&gt;Add Licensing Configuration&lt;/h5&gt;&#xA;&lt;p&gt;For Umbraco Cloud sites, you can add these settings to your appsettings.json file. If you have a different hosting setup, you will need to replace &quot;UMBRACO-CLOUD&quot; with your license key.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;{&#xA;&#xA0; &quot;Umbraco&quot;: {&#xA;&#xA0; &#xA0; &quot;Licenses&quot;: {&#xA;&#xA0; &#xA0; &#xA0; &quot;Products&quot;: {&#xA;&#xA0; &#xA0; &#xA0; &#xA0; &quot;Umbraco.Forms&quot;: &quot;UMBRACO-CLOUD&quot;,&#xA;&#xA0; &#xA0; &#xA0; &#xA0; &quot;Umbraco.Deploy&quot;: &quot;UMBRACO-CLOUD&quot;&#xA;&#xA0; &#xA0; &#xA0; }&#xA;&#xA0; &#xA0; }&#xA;&#xA0; }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2&gt;Build, Run, and Test!&lt;/h2&gt;&#xA;&lt;p&gt;Is the site rendering as expected? Does the back-office load and you are able to login? If yes, you&#x27;re on your way to v17.&lt;/p&gt;&#xA;&lt;p&gt;Now its time to perform your detailed regression testing by verifying all the packages migrated as expected, all property editors are working as expected, and you can make changes as you would expect.&lt;/p&gt;&#xA;&lt;p&gt;Here are some items you may want to focus on to verify the upgrade:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The site builds without errors&lt;/li&gt;&#xA;&lt;li&gt;All pages render correctly&lt;/li&gt;&#xA;&lt;li&gt;Backoffice login works&lt;/li&gt;&#xA;&lt;li&gt;Content editing works&lt;/li&gt;&#xA;&lt;li&gt;No console errors/warnings&lt;/li&gt;&#xA;&lt;li&gt;Block List editors function&lt;/li&gt;&#xA;&lt;li&gt;Rich text editors function&lt;/li&gt;&#xA;&lt;li&gt;Media uploads work&lt;/li&gt;&#xA;&lt;li&gt;Search returns results&lt;/li&gt;&#xA;&lt;li&gt;Licenses show as valid&lt;/li&gt;&#xA;&lt;li&gt;Forms submit and save entries&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2&gt;Migrating Custom Extensions to v17&lt;/h2&gt;&#xA;&lt;div&gt;Once the back-office and site appear to be working, it&#x27;s time to migrate those custom extensions to v17. That process is out of scope for this article, but here are some resources to get you started:&lt;/div&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://docs.umbraco.com/umbraco-cms/extending/property-editors&quot; target=&quot;_blank&quot; title=&quot;Building Property Editors in v17&quot;&gt;Building Property Editors in v17&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://docs.umbraco.com/umbraco-cms/customizing/ui-library&quot; target=&quot;_blank&quot; title=&quot;Umbraco UI Library&quot;&gt;Umbraco UI Library&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://kjac.dev/posts/migrating-extensions-from-umbraco-13-to-17/&quot; target=&quot;_blank&quot; title=&quot;Migrating Extensions from v13 to v17&quot;&gt;Migrating Extensions from v13 to v17&lt;/a&gt; by Kenn Jacobsen&lt;/li&gt;&#xA;&lt;li&gt;&lt;a rel=&quot;noopener&quot; type=&quot;external&quot; href=&quot;https://24days.in/umbraco-cms/2024/switching-to-web-components/)&quot; target=&quot;_blank&quot; title=&quot;From AngularJS to Web Components&quot;&gt;From AngularJS to Web Components&lt;/a&gt; by Jesper Mayntzhusen&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h2&gt;&#xA;&lt;p&gt;Upgrading to v17 is worth the effort as it is the Umbraco version to take the community into the future. AI, modern web frameworks, enterprise features, and so much more make this an upgrade to prioritize. With v13 support ending December 14th, 2026 the time to start planning an upgrade is now.&lt;/p&gt;&#xA;&lt;h2&gt;Need help with your Umbraco upgrade?&lt;/h2&gt;&#xA;&lt;p&gt;Reach out to us for an initial consultation so we can help make your upgrade a success!&lt;/p&gt;&#xA;&lt;p&gt;&lt;a style=&quot;color: #fff; background-image: none;&quot; type=&quot;external&quot; href=&quot;#section-footer&quot; title=&quot;Schedule a Consultation&quot; class=&quot;pw-button&quot; data-anchor=&quot;#section-footer&quot;&gt;Schedule a Consultation&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2 id=&quot;change-log&quot;&gt;Change Log&lt;/h2&gt;&#xA;&lt;div&gt;2026-01-22: Initial Version&lt;/div&gt;]]></description>
                    <pubDate>Thu, 22 Jan 2026 10:20:17 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbracospark/115932975121252464</guid>
                    <title>The Pre Spark Umbraco Hackathon and Package Jam is back!</title>
                    <link>https://umbracocommunity.social/@umbracospark/115932975121252464</link>
                    <description><![CDATA[&#x1F389; The Pre Spark Umbraco Hackathon and Package Jam is back! &#x1F389;Sign-ups are now open &#x1F449; https://www.meetup.com/umbristol/events/312954840If you&#x2019;re heading to #UmbracoSpark (tickets: https://www.tickettailor.com/events/umbukfdn/1896581) and taking part in the Package Jam, this is a great chance to collaborate in person as a team beforehand.#Umbraco #truedigital #umbristol #Bristol #TechCommunity]]></description>
                    <pubDate>Wed, 21 Jan 2026 12:11:39 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@UmbHost/115921099362344088</guid>
                    <title>UmbHost  GreenStack is now live!</title>
                    <link>https://umbracocommunity.social/@UmbHost/115921099362344088</link>
                    <description><![CDATA[&#x1F680; GreenStack is LIVE!After months of development, our load-balanced Umbraco hosting platform is here.&#x2705; Multi-replica infrastructure&#x2705; 99.9% uptime guarantee&#x2705; Zero-downtime deployments&#x2705; Powered by 100% renewable energyFrom &#xA3;20/mo https://umbhost.net/gb/blog/2026/01/greenstack-is-live-load-balanced-umbraco-hosting-is-here #GreenStack #Umbraco #WebHosting #SustainableHosting #CloudHosting #UmbHost]]></description>
                    <pubDate>Mon, 19 Jan 2026 09:43:34 Z</pubDate>
                        <category>community</category>
                        <category>mastodon</category>
                        <category>social</category>
                </item>
                <item>
                    <guid>https://dev.to/skttl/make-umbracos-welcome-dashboard-your-own-i1a</guid>
                    <title>Make Umbraco&#x2019;s Welcome Dashboard Your Own</title>
                    <link>https://dev.to/skttl/make-umbracos-welcome-dashboard-your-own-i1a</link>
                    <description><![CDATA[&lt;p&gt;Umbraco comes with a default Welcome dashboard in the backoffice. It displays news from Umbraco HQ along with handy links to documentation, training, and other community resources.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;That&#x2019;s great for developers, but when you&#x2019;re building Umbraco sites for clients, those links are often not the most relevant. In fact, the traditional recommendation has often been to simply remove the Welcome dashboard entirely.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;But with the current backoffice (which I should probably stop calling &lt;em&gt;new&lt;/em&gt; by now), there are plenty of extension points - and the Welcome dashboard is one of them.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;So instead of removing it, why not use it for your own content?&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Extending the Welcome dashboard&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The Welcome dashboard is powered by a service in the backend, and you can replace or extend its behaviour by implementing the &lt;code&gt;INewsDashboardService&lt;/code&gt; interface in your own C# code.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Once you do that, Umbraco will use your implementation to populate the dashboard.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;All you need to return is a &lt;code&gt;NewsDashboardResponseModel&lt;/code&gt;, which contains a collection of items to display. Each item supports:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A header&lt;/li&gt;&#xA;&lt;li&gt;Body text&lt;/li&gt;&#xA;&lt;li&gt;An image (URL &#x2B; alt text)&lt;/li&gt;&#xA;&lt;li&gt;A link URL&lt;/li&gt;&#xA;&lt;li&gt;Button text&lt;/li&gt;&#xA;&lt;li&gt;A priority (High, Medium, or Low)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;The dashboard will automatically sort the items by priority before rendering them.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  A (slightly useless) example implementation&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;As a simple demonstration, here&#x2019;s an intentionally useless implementation that displays the weather from 12 random locations on Earth every time the dashboard loads.&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Text.Json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Umbraco.Cms.Api.Management.Services.NewsDashboard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Umbraco.Cms.Api.Management.ViewModels.NewsDashboard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UselessNewsDashboardService&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INewsDashboardService&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HttpClient&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_httpClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AppCaches&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_appCaches&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GiNewsDashboardService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HttpClient&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httpClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AppCaches&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;appCaches&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;_httpClient&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httpClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;_appCaches&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;appCaches&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewsDashboardResponseModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetItemsAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;c1&quot;&gt;// fetch some data - this depends on your usecase!&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;locations&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_appCaches&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RuntimeCache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetCacheItemAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;                &lt;span class=&quot;s&quot;&gt;&quot;randomWeather&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;                &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetWeatherFromRandomLocationsAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;TimeSpan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FromHours&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;c1&quot;&gt;// build the response model&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;NewsDashboardResponseModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;Items&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;locations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;NewsDashboardItemResponseModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;Header&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;Priority&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;High&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// or Medium or Low&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;Url&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;ImageUrl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ImageUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ShortDescription&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;ButtonText&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Go to website&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;c1&quot;&gt;// below are methods for communicating with the weather API &lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;// - you don&#x27;t need these&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WeatherResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetWeatherAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;c1&quot;&gt;// this is just to prevent 529 Too many requests&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Delay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Shared&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&#xA;            &lt;span class=&quot;s&quot;&gt;$&quot;https://api.open-meteo.com/v1/forecast&quot;&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;&#x2B;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$&quot;?latitude=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;amp;longitude=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;&#x2B;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$&quot;&amp;amp;current_weather=true&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_httpClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetStringAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JsonDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RootElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;current_weather&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;temperature&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;temperature&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetDouble&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;weatherCode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;weathercode&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetInt32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;description&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetDescription&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;weatherCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;imageUrl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetImageUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;weatherCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;WeatherResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;Title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temperature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&#xB0;C&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;ShortDescription&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$&quot;Weather at &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;ImageUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;imageUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;Url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$&quot;https://www.open-meteo.com/en/forecast?latitude=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;amp;longitude=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;record&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WeatherResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ShortDescription&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ImageUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetDescription&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Clear sky&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Partly cloudy&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;m&quot;&gt;45&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;48&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Fog&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;m&quot;&gt;51&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;53&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;55&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Drizzle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;m&quot;&gt;61&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;63&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;65&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Rain&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;m&quot;&gt;71&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;73&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;75&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Snow&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;m&quot;&gt;80&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;81&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;82&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Rain showers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;m&quot;&gt;95&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Thunderstorm&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Unknown weather&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetImageUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://cdn-icons-png.flaticon.com/512/869/869869.png&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://cdn-icons-png.flaticon.com/512/1163/1163661.png&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;m&quot;&gt;61&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;63&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;65&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://cdn-icons-png.flaticon.com/512/3351/3351979.png&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;m&quot;&gt;71&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;73&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;75&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://cdn-icons-png.flaticon.com/512/642/642102.png&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;m&quot;&gt;95&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://cdn-icons-png.flaticon.com/512/1146/1146869.png&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://cdn-icons-png.flaticon.com/512/1779/1779940.png&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;You also have to register the service with a Composer, like so:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Umbraco.Cms.Core.Composing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UselessNewsDashboardComposer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComposer&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Compose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IUmbracoBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddSingleton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INewsDashboardService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UselessNewsDashboardComposer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;And there you have it:&lt;/p&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frl5tzrs373it81y3c5pb.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frl5tzrs373it81y3c5pb.png&quot; alt=&quot;A useless news dashboard in Umbraco showing weather information from random places on Earth&quot; width=&quot;800&quot; height=&quot;841&quot;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This example obviously isn&#x2019;t very useful - but it shows how little code is required to take control of the dashboard content.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  A practical use case&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Where this does become useful is for agencies and teams building Umbraco sites for clients.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Instead of showing Umbraco HQ news, you can use the Welcome dashboard to:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Share important project updates&lt;/li&gt;&#xA;&lt;li&gt;Announce new features or releases&lt;/li&gt;&#xA;&lt;li&gt;Provide onboarding instructions&lt;/li&gt;&#xA;&lt;li&gt;Link to internal documentation or support channels&lt;/li&gt;&#xA;&lt;li&gt;Communicate maintenance windows or known issues&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;In other words, it becomes a direct communication channel inside your client&#x2019;s CMS.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Final thoughts&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Rather than removing the Welcome dashboard altogether, extending it allows you to turn an otherwise generic screen into something genuinely valuable for your clients.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;With just a small custom service, you can make the Umbraco backoffice feel more tailored, more informative, and more aligned with the people actually using it.&lt;/p&gt;]]></description>
                    <pubDate>Mon, 19 Jan 2026 07:26:41 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/uprofile-january-2026-adam-prendergast/</guid>
                    <title>uProfile January 2026 - Adam Prendergast</title>
                    <link>https://umbraco.com/blog/uprofile-january-2026-adam-prendergast/</link>
                    <description><![CDATA[Meet Helen Chaplin &#x2014; a passionate sustainability advocate and avid world traveller]]></description>
                    <pubDate>Mon, 19 Jan 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@helloblake/115906539790690066</guid>
                    <title>Umbraco US Festival looking for community feedback</title>
                    <link>https://umbracocommunity.social/@helloblake/115906539790690066</link>
                    <description><![CDATA[&#x1F44B; #Umbraco community! We&#x2019;d love your input as we plan this year&#x2019;s Umbraco US Festival!What topics would you like to see discussed? Are there people (or you!) who would be great to speak on those subjects?We&#x2019;re also looking for folks who want to help behind the scenes, reviewing sessions, helping with comms, social posts, website updates, and more. All skill sets welcome!&#x1F4AC; Reply with ideas, tag someone, or reach out at events@umbracousfoundation.org to get involved.]]></description>
                    <pubDate>Sat, 17 Jan 2026 07:38:26 Z</pubDate>
                        <category>community</category>
                        <category>mastodon</category>
                        <category>social</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/blendinteractive.umbraco.sitemap</guid>
                    <title>BlendInteractive.Umbraco.Sitemap</title>
                    <link>https://marketplace.umbraco.com/package/blendinteractive.umbraco.sitemap</link>
                    <description><![CDATA[sitemap.xml dynmically generated using the AppSettings and can be configured per environment.]]></description>
                    <pubDate>Sat, 17 Jan 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/djretailing.umbraco.dropdown</guid>
                    <title>DJRetailing.Umbraco.Dropdown</title>
                    <link>https://marketplace.umbraco.com/package/djretailing.umbraco.dropdown</link>
                    <description><![CDATA[Sleek dropdown suite for Umbraco. Verified stable for v14-v17. Supports C# Enums and Simple Dropdowns with full localization.]]></description>
                    <pubDate>Sat, 17 Jan 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/blendinteractive.umbraco.robotstxt</guid>
                    <title>BlendInteractive.Umbraco.RobotsTxt</title>
                    <link>https://marketplace.umbraco.com/package/blendinteractive.umbraco.robotstxt</link>
                    <description><![CDATA[robots.txt dynmically generated using the AppSettings and can be configured per environment.]]></description>
                    <pubDate>Sat, 17 Jan 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbracospark/115899473100284278</guid>
                    <title>Umbraco Spark 2026 speaker line-up is live</title>
                    <link>https://umbracocommunity.social/@umbracospark/115899473100284278</link>
                    <description><![CDATA[&#x1F680; The Umbraco Spark 2026 speaker line-up is live!From Niels Lyngs&#xF8; on the backoffice, to Carl Sargunar&#x2019;s live load balancing, and Georgina &amp; Matt&#x2019;s AI-driven humor&#x2014;this year&#x2019;s Spark has something for every web professional.&#x1F39F;&#xFE0F; Tickets are limited! &#xA3;125 &#x2B; VAT until 31 Jan. Check out the full line-up &amp; get tickets https://umbracospark.com/ #UmbracoSpark #Umbraco #WebDev #TechEvents]]></description>
                    <pubDate>Thu, 15 Jan 2026 14:17:07 Z</pubDate>
                        <category>mastodon</category>
                        <category>social</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=CuBm41uczBM</guid>
                    <title>DevRel Deep Dive: Table Editing Community Packages</title>
                    <link>https://www.youtube.com/watch?v=CuBm41uczBM</link>
                    <description><![CDATA[This week Sebastiaan and Lotte take a look at two community packages that landed recently on the Umbraco marketplace, both adding the ability to allow editors to manage tabular data for properties: Webwonders &#x200B;Umbraco &#x200B;Table&#x200B;Editor and Umb&#x200B;Host &#x200B;Tables.&#xA;&#xA;&#x1F4E6; Webwonders &#x200B;Umbraco &#x200B;Table&#x200B;Editor on the Umbraco Marketplace: https://marketplace.umbraco.com/package/webwonders.umbraco.tableeditor&#xA;&#x1F4E6; Umb&#x200B;Host &#x200B;Tables on the Umbraco Marketplace: https://marketplace.umbraco.com/package/umbhost.tables&#xA;&#xA;--------&#xA;&#x2753; Looking for help with your Umbraco projects? Visit the Forum&#xA; https://forum.umbraco.com&#xA; &#xA;&#x1F4AC; Want to chat with the friendly Umbraco Community? Join our Discord server&#xA; https://discord.umbraco.com&#xA; &#xA;&#x2709;&#xFE0F; Got a question (or topic suggestion) for the HQ Developer Relations team?&#xA; https://umbra.co/contact-devrel, or the &#x2018;contact-devrel&#x2019; channel on Discord&#xA; &#xA;#Umbraco]]></description>
                    <pubDate>Wed, 14 Jan 2026 15:41:21 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbracospark/115893344443045520</guid>
                    <title>Sponsor the Umbraco Spark Pre-Party in Bristol</title>
                    <link>https://umbracocommunity.social/@umbracospark/115893344443045520</link>
                    <description><![CDATA[&#x1F4A1; Want your brand at the heart of the Umbraco community?Sponsor the Umbraco Spark Pre-Party in Bristol @ Roxy Lanes, Bristol &#x1F37B;&#x2714;&#xFE0F; Sole sponsor&#x2714;&#xFE0F; 2 free Spark 2026 tickets&#x2714;&#xFE0F; Food, drinks &amp; good vibes for the community #UmbracoSpark #Umbraco #BristolTech #WebDev #DotNet]]></description>
                    <pubDate>Wed, 14 Jan 2026 14:55:16 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://dev.to/mathilde_hoest/what-working-in-forensic-psychiatry-has-taught-me-about-the-umbraco-community-54lj</guid>
                    <title>What Working in Forensic Psychiatry Has Taught Me About the Umbraco Community - DEV Community</title>
                    <link>https://dev.to/mathilde_hoest/what-working-in-forensic-psychiatry-has-taught-me-about-the-umbraco-community-54lj</link>
                    <description><![CDATA[What Working in Forensic Psychiatry Has Taught Me About the Umbraco Community - DEV Community]]></description>
                    <pubDate>Wed, 14 Jan 2026 09:13:40 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.nathanielnunes.com/blog/using-umbraco-media-picker-crops-with-nextjs</guid>
                    <title>Using Umbraco Media Picker Crops with Next.js</title>
                    <link>https://www.nathanielnunes.com/blog/using-umbraco-media-picker-crops-with-nextjs</link>
                    <description><![CDATA[https://www.nathanielnunes.com/blog/using-umbraco-media-picker-crops-with-nextjs&#xA;&#xA;@UMB.FYI#3772 tip]]></description>
                    <pubDate>Tue, 13 Jan 2026 11:00:28 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/our.umbraco.extensions.polyfills</guid>
                    <title>Our.Umbraco.Extensions.Polyfills</title>
                    <link>https://marketplace.umbraco.com/package/our.umbraco.extensions.polyfills</link>
                    <description><![CDATA[Polyfills for broader compatibility in Umbraco]]></description>
                    <pubDate>Tue, 13 Jan 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/perplex.contentblockstoblocklist</guid>
                    <title>Perplex.ContentBlocksToBlockList</title>
                    <link>https://marketplace.umbraco.com/package/perplex.contentblockstoblocklist</link>
                    <description><![CDATA[Migrates Perplex.ContentBlocks data types and property data to Umbraco.BlockList]]></description>
                    <pubDate>Tue, 13 Jan 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/our.umbraco.extensions.localization</guid>
                    <title>Our.Umbraco.Extensions.Localization</title>
                    <link>https://marketplace.umbraco.com/package/our.umbraco.extensions.localization</link>
                    <description><![CDATA[Extensions for improved localization in Umbraco]]></description>
                    <pubDate>Tue, 13 Jan 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/our.umbraco.extensions.blocks</guid>
                    <title>Our.Umbraco.Extensions.Blocks</title>
                    <link>https://marketplace.umbraco.com/package/our.umbraco.extensions.blocks</link>
                    <description><![CDATA[Extensions for working with Blocks in Umbraco]]></description>
                    <pubDate>Tue, 13 Jan 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.linkedin.com/posts/developerlee_some-of-you-might-remember-merchello-the-ugcPost-7415400419331637248-baMp/</guid>
                    <title>Merchello, the community ecommerce package for Umbraco is making a come back</title>
                    <link>https://www.linkedin.com/posts/developerlee_some-of-you-might-remember-merchello-the-ugcPost-7415400419331637248-baMp/</link>
                    <description><![CDATA[Merchello]]></description>
                    <pubDate>Mon, 12 Jan 2026 10:31:32 Z</pubDate>
                        <category>linkedin</category>
                        <category>community</category>
                        <category>social</category>
                </item>
                <item>
                    <guid>https://www.johanreitsma.com/blogs/upgrading-from-umbraco-13-to-17-my-practical-approach/</guid>
                    <title>Upgrading from Umbraco 13 to 17: My Practical Approach</title>
                    <link>https://www.johanreitsma.com/blogs/upgrading-from-umbraco-13-to-17-my-practical-approach/</link>
                    <description><![CDATA[...]]></description>
                    <pubDate>Mon, 12 Jan 2026 09:07:29 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://cultiv.social/@sebastiaan/115865097803711443</guid>
                    <title>DevRel Deep Dives are back!</title>
                    <link>https://cultiv.social/@sebastiaan/115865097803711443</link>
                    <description><![CDATA[Yes, DevRel Deep Dives are back after a bit of a longer break.In this episode @lotte and I have special guest @leekelleher in to show us around some new goodies in yesterday&#x27;s Umbraco 17.1.0 release. https://www.youtube.com/watch?v=9PtP2qIfYM0#Umbraco]]></description>
                    <pubDate>Sun, 11 Jan 2026 11:44:18 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://medium.com/@sornphut/anthem-tryhackme-walkthrough-37ef5d28f9d1?source=rss------umbraco-5</guid>
                    <title>Anthem | TryHackMe | Walkthrough</title>
                    <link>https://medium.com/@sornphut/anthem-tryhackme-walkthrough-37ef5d28f9d1?source=rss------umbraco-5</link>
                    <description><![CDATA[&lt;div class=&quot;medium-feed-item&quot;&gt;&lt;p class=&quot;medium-feed-image&quot;&gt;&lt;a href=&quot;https://medium.com/@sornphut/anthem-tryhackme-walkthrough-37ef5d28f9d1?source=rss------umbraco-5&quot;&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/600/0*3vh2w4xfoKc9PXfJ.gif&quot; width=&quot;600&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;medium-feed-snippet&quot;&gt;Initial Access&lt;/p&gt;&lt;p class=&quot;medium-feed-link&quot;&gt;&lt;a href=&quot;https://medium.com/@sornphut/anthem-tryhackme-walkthrough-37ef5d28f9d1?source=rss------umbraco-5&quot;&gt;Continue reading on Medium &#xBB;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;]]></description>
                    <pubDate>Sat, 10 Jan 2026 17:13:35 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=9PtP2qIfYM0</guid>
                    <title>Umbraco 17.1 highlights with Lee Kelleher</title>
                    <link>https://www.youtube.com/watch?v=9PtP2qIfYM0</link>
                    <description><![CDATA[Sebastiaan and Lotte look at some highlights of the latest Umbraco release - version 17.1 - with the help of Lee Kelleher from the Umbraco CMS team. Umbraco 17.1 brings a lot of accessibility and UX improvements, bug fixes and other enhancements. Learn about Block Sort Mode, configuring Additional Preview Environments for headless implementations, and more!&#xA;&#xA;&#x1F440; Check out the 17.1 release notes: https://releases.umbraco.com/release/umbraco/Umbraco-CMS/17.1.0&#xA;&#xA;&#x1F4D5;Additional preview environments support: https://docs.umbraco.com/umbraco-cms/reference/content-delivery-api/additional-preview-environments-support &#xA;&#xA;--------&#xA;&#x2753; Looking for help with your Umbraco projects? Visit the Forum&#xA; https://forum.umbraco.com&#xA; &#xA;&#x1F4AC; Want to chat with the friendly Umbraco Community? Join our Discord server&#xA; https://discord.umbraco.com&#xA; &#xA;&#x2709;&#xFE0F; Got a question (or topic suggestion) for the HQ Developer Relations team?&#xA; https://umbra.co/contact-devrel, or the &#x2018;contact-devrel&#x2019; channel on Discord&#xA; &#xA;#Umbraco]]></description>
                    <pubDate>Fri, 09 Jan 2026 10:46:25 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://dev.to/skttl/readable-simple-chinese-url-segments-in-umbraco-with-npinyin-ajp</guid>
                    <title>Readable, simple Chinese URL segments in Umbraco with NPinyin</title>
                    <link>https://dev.to/skttl/readable-simple-chinese-url-segments-in-umbraco-with-npinyin-ajp</link>
                    <description><![CDATA[&lt;p&gt;On a recent project, the client had a Chinese version of their site. The texts and titles were, of course, written using Chinese characters, which meant that the URLs were automatically generated using those characters as well.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;For SEO and UX reasons, we wanted the URLs to use Latin characters instead. While search engines are perfectly capable of indexing Chinese URLs, we felt that Latin URLs would perform better in practice.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Our reasoning was:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;p&gt;Latin URLs are more readable (especially since the audience was not exclusively Chinese), which we assumed would lead to higher click-through rates&lt;/p&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;p&gt;Hyphenated Latin words provide clearer URL keyword signals&lt;/p&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;p&gt;Sharing URLs and linking to them is much easier with Latin characters than with encoded Chinese characters&lt;/p&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;For example, a title like:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;&#x51FB;&#x638C;&#xFF01;&#x4F60;&#x592A;&#x68D2;&#x4E86;&#xFF01;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;would normally generate a URL segment using Chinese characters. With pinyin conversion applied, it instead becomes:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;/ji-zhang-ni-tai-bang-le&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;The latter is much easier to read, share, and reason about, especially in mixed-language environments.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Converting Chinese characters to Latin using pinyin&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Umbraco already tries to convert special characters when generating URLs, but the default character replacement set is quite limited. You can see the default configuration in the request handler settings in the documentation article about &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/reference/configuration/requesthandlersettings&quot; rel=&quot;noopener noreferrer&quot;&gt;Request Handler Settings&lt;/a&gt;.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Because of the nature of Chinese characters, having more than 50,000 of them, mapping each character to a Latin equivalent is not feasible. Instead, we can use pinyin, which is a Latin-based phonetic transcription system for Chinese characters.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Using pinyin allows us to convert Chinese text into readable Latin equivalents without maintaining huge character maps. There is an open-source NuGet package called &lt;a href=&quot;https://www.nuget.org/packages/NPinyin.Core&quot; rel=&quot;noopener noreferrer&quot;&gt;NPinyin.Core&lt;/a&gt; that makes this conversion straightforward. It&#x2019;s lightweight and integrates cleanly into existing logic.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;This approach also works well for mixed-language titles, such as:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;&#x51FB;&#x638C;&#xFF01;You Rock!&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;which results in:&lt;br&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;/ji-zhang-you-rock&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Using a custom URL segment provider in Umbraco&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;With the conversion logic in place, the next step was to make Umbraco use it when generating URL segments.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;When Umbraco generates URL segments, it runs through a set of URL segment providers, and it&#x2019;s possible to create a custom one. The process is simple and &lt;a href=&quot;https://docs.umbraco.com/umbraco-cms/reference/routing/request-pipeline/outbound-pipeline#url-segment-provider&quot; rel=&quot;noopener noreferrer&quot;&gt;well documented&lt;/a&gt;.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;By adding a small amount of additional logic to separate Chinese characters with dashes, we ended up with a short and simple custom segment provider that generates readable, SEO-friendly Latin URLs for Chinese pages.&lt;/p&gt;&#xA;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;** Note: **&lt;br&gt;&#xA;This approach converts each Chinese character to its pinyin representation and inserts dashes between characters. While this is not full linguistic word segmentation, it produces consistent, readable URL segments without adding unnecessary complexity.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Example implementation&#xA;&lt;/h2&gt;&#xA;&#xA;&#xA;&#xA;&lt;div class=&quot;highlight js-code-highlight&quot;&gt;&#xA;&lt;pre class=&quot;highlight csharp&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;NPinyin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Umbraco.Cms.Core.Models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Umbraco.Cms.Core.Strings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Project.Core.Urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;&lt;span class=&quot;c1&quot;&gt;// Custom URL segment provider that wraps Umbraco&#x27;s default provider&lt;/span&gt;&#xA;&lt;span class=&quot;c1&quot;&gt;// and applies Chinese to Pinyin conversion on top.&lt;/span&gt;&#xA;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ChineseUrlSegmentProvider&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IUrlSegmentProvider&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;// We delegate to the default provider first, so we keep&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;// Umbraco&#x27;s built-in behavior for non-Chinese characters.&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DefaultUrlSegmentProvider&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_defaultUrlSegmentProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ChineseUrlSegmentProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IShortStringHelper&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shortStringHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;n&quot;&gt;_defaultUrlSegmentProvider&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;DefaultUrlSegmentProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shortStringHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetUrlSegment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IContentBase&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;culture&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;c1&quot;&gt;// Let Umbraco generate the initial URL segment,&lt;/span&gt;&#xA;        &lt;span class=&quot;c1&quot;&gt;// then post-process it with our custom logic.&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ChineseToPinyinWithDashes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&#xA;            &lt;span class=&quot;n&quot;&gt;_defaultUrlSegmentProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetUrlSegment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;culture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;c1&quot;&gt;// Converts Chinese characters to pinyin and inserts dashes&lt;/span&gt;&#xA;    &lt;span class=&quot;c1&quot;&gt;// between consecutive Chinese characters to improve readability.&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ChineseToPinyinWithDashes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sb&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;StringBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastWasChinese&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;IsChinese&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                &lt;span class=&quot;c1&quot;&gt;// Insert a dash between consecutive Chinese characters&lt;/span&gt;&#xA;                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastWasChinese&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;                &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                    &lt;span class=&quot;n&quot;&gt;sb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;&#x27;-&#x27;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;                &lt;span class=&quot;c1&quot;&gt;// Convert the individual character to pinyin&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;sb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pinyin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetPinyin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()));&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;lastWasChinese&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;                &lt;span class=&quot;c1&quot;&gt;// Non-Chinese characters are passed through unchanged&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;sb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&#xA;                &lt;span class=&quot;n&quot;&gt;lastWasChinese&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&#xA;    &lt;span class=&quot;c1&quot;&gt;// Simple Unicode range check for CJK Unified Ideographs&lt;/span&gt;&#xA;    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IsChinese&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&#xA;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0x4E00&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0x9FFF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&#xA;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Results&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;With this approach in place, Chinese pages now automatically generate clean, readable, and shareable URL segments without any manual intervention. It works equally well for fully Chinese titles and mixed-language content, and it integrates cleanly into Umbraco&#x2019;s existing routing pipeline.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The solution is lightweight, easy to maintain, and avoids the complexity of large character-mapping tables or full linguistic word segmentation &#x2014; making it a practical choice for real-world Umbraco projects.&lt;/p&gt;]]></description>
                    <pubDate>Fri, 09 Jan 2026 08:29:17 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/fastgooey</guid>
                    <title>FastGooey</title>
                    <link>https://marketplace.umbraco.com/package/fastgooey</link>
                    <description><![CDATA[Render content into native iOS and macOS UI directly from your Umbraco projects.]]></description>
                    <pubDate>Fri, 09 Jan 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.linkedin.com/posts/phil-whittaker-82481716_umbraco-ai-mcp-activity-7415068292215930880-0KRg?utm_source=share&amp;utm_medium=member_ios&amp;rcm=ACoAAABj9KwBjr581HKBv-M3TbQu69Ia79rmfPw</guid>
                    <title>Umbraco CMS Developer MCP v17.0.1-beta.3 is out!</title>
                    <link>https://www.linkedin.com/posts/phil-whittaker-82481716_umbraco-ai-mcp-activity-7415068292215930880-0KRg?utm_source=share&amp;utm_medium=member_ios&amp;rcm=ACoAAABj9KwBjr581HKBv-M3TbQu69Ia79rmfPw</link>
                    <description><![CDATA[https://www.linkedin.com/posts/phil-whittaker-82481716_umbraco-ai-mcp-activity-7415068292215930880-0KRg?utm_source=share&amp;utm_medium=member_ios&amp;rcm=ACoAAABj9KwBjr581HKBv-M3TbQu69Ia79rmfPw]]></description>
                    <pubDate>Thu, 08 Jan 2026 17:51:47 Z</pubDate>
                        <category>community</category>
                        <category>linkedin</category>
                        <category>social</category>
                </item>
                <item>
                    <guid>https://mastodon.social/@deanleigh/115859499427123459</guid>
                    <title>UmBootstrap-17.1.0 released to match the release of Umbraco-17.1.0</title>
                    <link>https://mastodon.social/@deanleigh/115859499427123459</link>
                    <description><![CDATA[I have just released #UmBootstrap-17.1.0 to match the release of #Umbraco-17.1.0.It includes a some new features, content and bugfixeshttps://umbootstrap.com/]]></description>
                    <pubDate>Thu, 08 Jan 2026 13:27:19 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbracospark/115853702848510381</guid>
                    <title>The Call for Speakers for Umbraco Spark is now closed!</title>
                    <link>https://umbracocommunity.social/@umbracospark/115853702848510381</link>
                    <description><![CDATA[&#x1F3A4; The Call for Speakers for Umbraco Spark is now closed!Thank you to everyone who submitted &#x2014; we&#x2019;re now reviewing all proposals.Speaker line up coming soon &#x1F440;&#x1F449; https://umbracospark.com/#UmbracoSpark #CFP #Umbraco]]></description>
                    <pubDate>Thu, 08 Jan 2026 12:02:37 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@umbracospark/115859367848729995</guid>
                    <title>Busra Sengul from true digital will be one of the MCs at Umbraco Spark 2026</title>
                    <link>https://umbracocommunity.social/@umbracospark/115859367848729995</link>
                    <description><![CDATA[Announcement time! &#x1F680; Busra Sengul from true digital will be one of the MCs at Umbraco Spark 2026!Speaker lineup coming soon &#x2014; stay tuned &#x1F440; &#x1F449; https://umbracospark.com/#UmbracoSpark #truedigital #Umbraco]]></description>
                    <pubDate>Thu, 08 Jan 2026 12:02:24 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/new-year-new-perspectives-the-importance-of-togetherness/</guid>
                    <title>New Year, New Perspectives: The Importance of Togetherness</title>
                    <link>https://umbraco.com/blog/new-year-new-perspectives-the-importance-of-togetherness/</link>
                    <description><![CDATA[A new year has a funny way of inviting reflection. December often finds us looking back at the path we&#x2019;ve taken, evaluating what worked, what didn&#x27;t, and what we hope looks different twelve months from now.]]></description>
                    <pubDate>Thu, 08 Jan 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/rewdboy.umbraco.editlink</guid>
                    <title>Rewdboy.Umbraco.EditLink</title>
                    <link>https://marketplace.umbraco.com/package/rewdboy.umbraco.editlink</link>
                    <description><![CDATA[Package Description]]></description>
                    <pubDate>Thu, 08 Jan 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
    </channel>
</rss>