<?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>Mon, 27 Jul 2026 21:04:31 Z</lastBuildDate>
        <language>en</language>
        <generator>Umbraco</generator>
                <item>
                    <guid>https://owain.codes/blog/2026/july/a-reusable-deploy-pipeline-for-umbraco-cloud/</guid>
                    <title>A reusable deploy pipeline for Umbraco Cloud</title>
                    <link>https://owain.codes/blog/2026/july/a-reusable-deploy-pipeline-for-umbraco-cloud/</link>
                    <description><![CDATA[Create a reusable deploy pipeline for Umbraco Cloud]]></description>
                    <pubDate>Mon, 27 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbhost.automate.teamwork</guid>
                    <title>UmbHost.Automate.Teamwork</title>
                    <link>https://marketplace.umbraco.com/package/umbhost.automate.teamwork</link>
                    <description><![CDATA[Teamwork Projects connection type and actions for Umbraco Automate.]]></description>
                    <pubDate>Fri, 24 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbhost.automate.github</guid>
                    <title>UmbHost.Automate.GitHub</title>
                    <link>https://marketplace.umbraco.com/package/umbhost.automate.github</link>
                    <description><![CDATA[GitHub connection type, actions, a jsonpath binding filter and an X-Hub-Signature-256 webhook authenticator for Umbraco Automate.]]></description>
                    <pubDate>Fri, 24 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-upcoming-security-patch-for-umbraco-forms-ready-on-july-28-2026-at-08-am-utc/</guid>
                    <title>Security Advisory: Upcoming Security Patch for Umbraco Forms ready on July 28, 2026 at 08 AM UTC</title>
                    <link>https://umbraco.com/blog/security-advisory-upcoming-security-patch-for-umbraco-forms-ready-on-july-28-2026-at-08-am-utc/</link>
                    <description><![CDATA[A security vulnerability has been identified in Umbraco Forms. A security patch for Umbraco Forms 13, 17, and 18 are scheduled for release on Tuesday, July 28th, 2026 at 08 AM UTC.]]></description>
                    <pubDate>Thu, 23 Jul 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/green-track-to-codegarden/</guid>
                    <title>The Green Track to Codegarden</title>
                    <link>https://umbraco.com/blog/green-track-to-codegarden/</link>
                    <description><![CDATA[Discover how Umbraco&#x27;s Green Track travelers saved 1.5 tonnes of CO2 by taking the train to Codegarden, redefining productive and sustainable business travel.]]></description>
                    <pubDate>Wed, 22 Jul 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.ai.mediajanitor</guid>
                    <title>Umbraco.Community.AI.MediaJanitor</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.ai.mediajanitor</link>
                    <description><![CDATA[An AI Media Assistant for the Umbraco Media section. Finds images with missing alt text, generic names, or in the wrong folder and suggests a better file name, alt text, caption, and folder &#x2014; you review, edit, and apply.]]></description>
                    <pubDate>Tue, 21 Jul 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.adminonly</guid>
                    <title>Umbraco.Community.AdminOnly</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.adminonly</link>
                    <description><![CDATA[A friendlier backoffice for non-admin editors. Hide document types, tabs and properties from everyone who isn&#x27;t an administrator &#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 lock icon marking every hidden item. Configuration is point-and-click from a settings dashboard, so there is no code to write and nothing to recompile. Note: this is a backoffice UX layer, not server-side authorization &#x2014; use Umbraco&#x27;s user groups and permissions to protect sensitive data.]]></description>
                    <pubDate>Tue, 21 Jul 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.iconpicker</guid>
                    <title>Umbraco.Community.IconPicker</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.iconpicker</link>
                    <description><![CDATA[Pick SVG icons straight from your own sprite. IconPicker adds a property editor that reads any SVG sprite in your site&#x27;s wwwroot folder and lets editors choose a symbol from it &#x2014; no icon library to install, no duplicate assets. The icons your designer delivered are the icons your editors get.]]></description>
                    <pubDate>Tue, 21 Jul 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.linkedpages</guid>
                    <title>Umbraco.Community.LinkedPages</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.linkedpages</link>
                    <description><![CDATA[Package Description]]></description>
                    <pubDate>Tue, 21 Jul 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.headsup</guid>
                    <title>Umbraco.Community.HeadsUp</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.headsup</link>
                    <description><![CDATA[Protects Umbraco editors against lost content when the same document is open in multiple tabs or edited by multiple users. Notifies other editors in real time when a document they have open is saved or published, lists the changed fields and offers to reload.]]></description>
                    <pubDate>Tue, 21 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://flowcourier.com/blog/aeo-for-umbraco/</guid>
                    <title>AEO for Umbraco: Your Next Visitor Is an AI</title>
                    <link>https://flowcourier.com/blog/aeo-for-umbraco/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 20 Jul 2026 17:24:00 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://blog.tsd.digital/assume-your-software-will-outlive-its-end-of-life/</guid>
                    <title>Assume your software will outlive its end-of-life</title>
                    <link>https://blog.tsd.digital/assume-your-software-will-outlive-its-end-of-life/</link>
                    <description><![CDATA[We still run an Umbraco v4 site, on purpose. End-of-life is a date on the vendor&#x27;s calendar, not a fact about your customer&#x27;s business. Why the version you ship is the one worth designing for, and how to tell a managed risk from plain neglect.]]></description>
                    <pubDate>Mon, 20 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/thebuilder.webanalytics</guid>
                    <title>TheBuilder.WebAnalytics</title>
                    <link>https://marketplace.umbraco.com/package/thebuilder.webanalytics</link>
                    <description><![CDATA[Vercel Web Analytics inside the Umbraco backoffice.]]></description>
                    <pubDate>Sun, 19 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.urlviewer</guid>
                    <title>uTPro.Feature.UrlViewer</title>
                    <link>https://marketplace.umbraco.com/package/utpro.feature.urlviewer</link>
                    <description><![CDATA[Fetch and inspect any URL as Googlebot, Bingbot or a real browser, directly from your Umbraco site (Umbraco 16, 17, 18). Follows the full redirect chain and shows the response headers for every hop, renders the raw HTML source with line numbers, and analyses the page for spam/hack keywords, hidden CSS (a common cloaking trick), meta tags and common JavaScript issues (eval, document.write, obfuscation, mixed content and more). Includes automatic cloaking detection that compares what a search-engine bot sees versus what Chrome sees, plus a one-click VirusTotal link for the domain. Ideal for SEO debugging, diagnosing hacked or cloaked pages, and inspecting redirects. The fetch runs server-side and blocks private/local addresses for safety.]]></description>
                    <pubDate>Fri, 17 Jul 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.formsaudittrail</guid>
                    <title>Umbraco.Community.FormsAuditTrail</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.formsaudittrail</link>
                    <description><![CDATA[A view-only audit trail for Umbraco Forms design changes. Tracks who changed what on form designs (fields, pages, workflows and form settings) and surfaces the history in a backoffice dashboard with filtering, field-level diffs and CSV export.]]></description>
                    <pubDate>Fri, 17 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/cloudlens</guid>
                    <title>CloudLens</title>
                    <link>https://marketplace.umbraco.com/package/cloudlens</link>
                    <description><![CDATA[Compare content between Umbraco Cloud environments from the backoffice before every deployment.]]></description>
                    <pubDate>Fri, 17 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/july/build-a-custom-umbraco-automate-action/</guid>
                    <title>Build a custom Umbraco Automate action</title>
                    <link>https://owain.codes/blog/2026/july/build-a-custom-umbraco-automate-action/</link>
                    <description><![CDATA[Creating a custom action in Umbraco Automate to pull tags from a blog and display them as hashtags in social connections.]]></description>
                    <pubDate>Fri, 17 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@owaincodes/116928799744745888</guid>
                    <title>Owain.Codes v2 Umbraco Automate packages for Bluesky, Mastodon and LinkedIn have been released.</title>
                    <link>https://umbracocommunity.social/@owaincodes/116928799744745888</link>
                    <description><![CDATA[Busy night - version 2 of my Umbraco.Automate packages have been released. Changing the config pattern and a few improvements. Bluesky, Mastodon and LinkedIn packages all updated. #umbraco]]></description>
                    <pubDate>Thu, 16 Jul 2026 10:59:00 Z</pubDate>
                        <category>community</category>
                        <category>mastodon</category>
                        <category>social</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/flowcourier.umbraco.aeo</guid>
                    <title>Flowcourier.Umbraco.AEO</title>
                    <link>https://marketplace.umbraco.com/package/flowcourier.umbraco.aeo</link>
                    <description><![CDATA[Make your Umbraco site readable by AI answer engines (ChatGPT, Claude, Perplexity, Gemini, &#x2026;). Install one package and your site immediately serves an /llms.txt index, an /llms-full.txt full-site Markdown dump, and a clean Markdown rendering of any page when you append .md to its URL &#x2014; all generated live from the published-content cache, with no editor work and no content changes. Multi-site and multilingual aware, discoverable via alternate links, content negotiation and an optional robots.txt hint, with ETag/304 caching built in. Designed for sites where Umbraco renders the front end (Razor/MVC) &#x2014; not for headless setups. Free for Umbraco 17.5&#x2B;, including commercial production use.]]></description>
                    <pubDate>Thu, 16 Jul 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.dictionarylocalization</guid>
                    <title>Esatto.Umbraco.Backoffice.DictionaryLocalization</title>
                    <link>https://marketplace.umbraco.com/package/esatto.umbraco.backoffice.dictionarylocalization</link>
                    <description><![CDATA[Bridges Umbraco 17 content Dictionary items into the backoffice UI localization system. After install, any `#Key` in a content-type property label (or anywhere `localize.string()` is called) resolves to the current backoffice user&#x27;s culture value from the Dictionary section. Works for every existing and future dictionary key; no per-key manifest wiring.]]></description>
                    <pubDate>Thu, 16 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/foxcart.members</guid>
                    <title>FoxCart.Members</title>
                    <link>https://marketplace.umbraco.com/package/foxcart.members</link>
                    <description><![CDATA[Member area addon for FoxCart: profile management, order history, saved addresses and complete authentication flows built on Umbraco Members. Ships as a Razor Class Library with overridable Flowbite-style default views.]]></description>
                    <pubDate>Thu, 16 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://medium.com/@associative-india/top-umbraco-development-company-in-pune-associative-780722f22eb2?source=rss------umbraco-5</guid>
                    <title>Top Umbraco Development Company in Pune | Associative</title>
                    <link>https://medium.com/@associative-india/top-umbraco-development-company-in-pune-associative-780722f22eb2?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/@associative-india/top-umbraco-development-company-in-pune-associative-780722f22eb2?source=rss------umbraco-5&quot;&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1080/1*-vNHPgEKoCTInnwPbQpBcA.png&quot; width=&quot;1080&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;medium-feed-snippet&quot;&gt;Welcome to Associative, a premier full-service software development firm headquartered in Pune, Maharashtra, India.&lt;/p&gt;&lt;p class=&quot;medium-feed-link&quot;&gt;&lt;a href=&quot;https://medium.com/@associative-india/top-umbraco-development-company-in-pune-associative-780722f22eb2?source=rss------umbraco-5&quot;&gt;Continue reading on Medium &#xBB;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;]]></description>
                    <pubDate>Wed, 15 Jul 2026 10:15:28 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.getnet</guid>
                    <title>SplatDev.Umbraco.Plugins.Getnet</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.getnet</link>
                    <description><![CDATA[Umbraco 17 plugin that registers the Getnet (Santander acquirer) SDK (SplatDev.Payments.Getnet): options binding, the API client, and the named Getnet HttpClient. Webhook/backoffice controllers and payment orchestration are application-specific and stay in the consuming app.]]></description>
                    <pubDate>Wed, 15 Jul 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.santander</guid>
                    <title>SplatDev.Umbraco.Plugins.Santander</title>
                    <link>https://marketplace.umbraco.com/package/splatdev.umbraco.plugins.santander</link>
                    <description><![CDATA[Umbraco 17 plugin for the Santander Open Banking suite: a composer that registers SplatDev.Payments.Santander (options, client, the 8 product services, and the named mTLS HttpClient with the ICP-Brasil e-CNPJ certificate) plus a guarded backoffice/server-to-server banking API controller.]]></description>
                    <pubDate>Wed, 15 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/dragonfly.umbraco10.forms.web</guid>
                    <title>Dragonfly.Umbraco10.Forms.Web</title>
                    <link>https://marketplace.umbraco.com/package/dragonfly.umbraco10.forms.web</link>
                    <description><![CDATA[A collection of custom Umbraco Forms FieldTypes and Helpers (Umbraco 17&#x2B;) [Full install for website]]]></description>
                    <pubDate>Wed, 15 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.dynamicdave.nl/blog/no-laptop-still-learning-an-umbraco-developers-holiday-checklist/</guid>
                    <title>No Laptop, Still Learning: An Umbraco Developer&#x27;s Holiday Checklist</title>
                    <link>https://www.dynamicdave.nl/blog/no-laptop-still-learning-an-umbraco-developers-holiday-checklist/</link>
                    <description><![CDATA[In a few days, I&#x27;m packing my bags for a holiday, and for the first time in ages, my laptop will stay home. No Visual Studio. No Docker containers spinning up in the background. No sneaky last-minute Git commits. And, honestly, no more of those &quot;let me just fix this one bug real quick&quot; moments.And to be completely honest? I can&#x27;t wait.But that doesn&#x27;t mean I&#x27;m putting my developer brain entirely on pause. If you&#x27;ve been working with Umbraco for years&#x2014;like me&#x2014;you know it&#x27;s much more than a tool you clock in and out of each day. It&#x27;s a community, an ecosystem, and, let&#x27;s be real, a craft that&#x27;s always changing. Even if I don&#x27;t write a line of code, there&#x27;s no shortage of ways to stay inspired and come back from my break with fresh perspectives.Here&#x27;s how I&#x27;m planning to keep the inspiration flowing while away.]]></description>
                    <pubDate>Tue, 14 Jul 2026 22:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://github.com/skybrud/Skybrud.Umbraco.Redirects/releases/tag/v18.0.0-alpha001</guid>
                    <title>Skybrud.Umbraco.Redirects 18.0.0-alpha001</title>
                    <link>https://github.com/skybrud/Skybrud.Umbraco.Redirects/releases/tag/v18.0.0-alpha001</link>
                    <description><![CDATA[Award winning redirects manager for Umbraco.]]></description>
                    <pubDate>Tue, 14 Jul 2026 12:12:30 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/utpro.feature.jobmonitor</guid>
                    <title>uTPro.Feature.JobMonitor</title>
                    <link>https://marketplace.umbraco.com/package/utpro.feature.jobmonitor</link>
                    <description><![CDATA[Read-and-trigger monitor for Umbraco recurring background jobs (Umbraco 16, 17, 18). Adds a Jobs dashboard under the Settings section that lists every recurring background job registered in the site, shows each job&#x27;s timing parameters (period, delay, server roles), records execution telemetry the CMS does not persist natively, estimates the next run, reflects load-balancing and server-role behaviour, and lets an authorized backoffice user trigger a job on demand (&quot;Run now&quot;). Discovers both modern IRecurringBackgroundJob implementations and legacy RecurringHostedServiceBase jobs automatically - no per-job wiring. Read-only by default; the only write is the manual trigger, which runs off the request thread, guards against overlap, and records who initiated it.]]></description>
                    <pubDate>Tue, 14 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://cornehoskam.com/posts/how-i-upgraded-umbraco-13-to-17-in-less-than-two-hours</guid>
                    <title>How I upgraded Umbraco 13 to 17 in less than two hours!</title>
                    <link>https://cornehoskam.com/posts/how-i-upgraded-umbraco-13-to-17-in-less-than-two-hours</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Sat, 11 Jul 2026 10:19:00 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/flowcourier.umbraco.ai.agents.translation</guid>
                    <title>Flowcourier.Umbraco.AI.Agents.Translation</title>
                    <link>https://marketplace.umbraco.com/package/flowcourier.umbraco.ai.agents.translation</link>
                    <description><![CDATA[Translate whole Umbraco pages in one click &#x2014; every property, nested block content and SEO fields &#x2014; using the AI provider you already configured through Umbraco AI. Every translation lands as a draft and goes through a human approval flow before anything publishes, with reviewer emails, automatic reminders and a Translation Workflow dashboard inside Umbraco&#x27;s Translation section. Free for Umbraco 17.5&#x2B;, including commercial production use.]]></description>
                    <pubDate>Sat, 11 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/flowcourier.umbraco.ai.agents.seo</guid>
                    <title>Flowcourier.Umbraco.AI.Agents.Seo</title>
                    <link>https://marketplace.umbraco.com/package/flowcourier.umbraco.ai.agents.seo</link>
                    <description><![CDATA[Improve the SEO of any Umbraco page in one click. The SEO Agent reads the open page, works out which properties are SEO and metadata fields &#x2014; even when they have non-standard names &#x2014; and drafts optimised meta titles, descriptions and social fields from the page&#x27;s own content, using the AI provider you already configured through Umbraco AI. Every suggestion is staged into the editor for you to review, edit and Save; nothing is ever written without you. Free for Umbraco 17.5&#x2B;, including commercial production use.]]></description>
                    <pubDate>Sat, 11 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.nevitech.co.uk/blog/migrating-umbraco-13-to-umbraco-17-on-umbraco-cloud/</guid>
                    <title>Migrating Umbraco 13 to Umbraco 17 on Umbraco Cloud</title>
                    <link>https://www.nevitech.co.uk/blog/migrating-umbraco-13-to-umbraco-17-on-umbraco-cloud/</link>
                    <description><![CDATA[A developer guide to upgrading an Umbraco 13 site to Umbraco 17 on Umbraco Cloud by migrating locally and deploying into a fresh Cloud project, covering the full sequence through to a low downtime go live.]]></description>
                    <pubDate>Fri, 10 Jul 2026 23:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://github.com/limbo-works/Limbo.Umbraco.FilterList/releases/tag/v17.0.0-alpha001</guid>
                    <title>Limbo.Umbraco.FilterList 17.0.0-alpha001</title>
                    <link>https://github.com/limbo-works/Limbo.Umbraco.FilterList/releases/tag/v17.0.0-alpha001</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 10 Jul 2026 15:17:02 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://www.nathanielnunes.com/blog/pin-umbraco-docs-version-tampermonkey</guid>
                    <title>Pinning docs.umbraco.com to a Specific Version with Tampermonkey</title>
                    <link>https://www.nathanielnunes.com/blog/pin-umbraco-docs-version-tampermonkey</link>
                    <description><![CDATA[Here is a Tampermonkey userscript that pins docs.umbraco.com to whatever version you are actually working on.]]></description>
                    <pubDate>Fri, 10 Jul 2026 11:30:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://cornehoskam.com/posts/how-i-upgraded-umbraco-13-to-17-in-less-than-two-hours/</guid>
                    <title>How I upgraded Umbraco 13 to 17 in less than two hours!</title>
                    <link>https://cornehoskam.com/posts/how-i-upgraded-umbraco-13-to-17-in-less-than-two-hours/</link>
                    <description><![CDATA[I jumped straight from Umbraco 13 to 17 on Umbraco Cloud in under two hours, TinyMCE to Tiptap and all. Here&#x27;s the full checklist of what I touched.]]></description>
                    <pubDate>Fri, 10 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/our.umbraco.mediamanager</guid>
                    <title>Our.Umbraco.MediaManager</title>
                    <link>https://marketplace.umbraco.com/package/our.umbraco.mediamanager</link>
                    <description><![CDATA[Safe, async media cleanup for Umbraco 16&#x2013;17: find and remove unused media nodes, duplicates, broken nodes and orphaned physical files, guarded by a deep reference scan, with dry-run preview and Recycle Bin safety.]]></description>
                    <pubDate>Fri, 10 Jul 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.ModelsBuilder/releases/tag/v17.0.0-alpha001</guid>
                    <title>Limbo.Umbraco.ModelsBuilder 17.0.0-alpha001</title>
                    <link>https://github.com/limbo-works/Limbo.Umbraco.ModelsBuilder/releases/tag/v17.0.0-alpha001</link>
                    <description><![CDATA[Limbo.Umbraco.ModelsBuilder is a custom models builder for Umbraco that provides extended functionality compared to Umbraco&#x27;s build-in models builder.]]></description>
                    <pubDate>Thu, 09 Jul 2026 08:05:11 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://hayleymarkdigital.co.uk/blog/exploring-umbraco-ai-for-end-users/</guid>
                    <title>Exploring Umbraco AI for end users</title>
                    <link>https://hayleymarkdigital.co.uk/blog/exploring-umbraco-ai-for-end-users/</link>
                    <description><![CDATA[Providing reliable, proactive and personable freelance support for website updates, SEO, lead generation and ongoing marketing strategies.]]></description>
                    <pubDate>Thu, 09 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/geoa.aivisibility</guid>
                    <title>Geoa.AiVisibility</title>
                    <link>https://marketplace.umbraco.com/package/geoa.aivisibility</link>
                    <description><![CDATA[Make your Umbraco site visible to AI answer engines (ChatGPT, Perplexity, Gemini). Geoa injects registry-verified Organization schema (DK / NO / SE / FI), FAQ and Article JSON-LD, and an optional llms.txt file, then scores every page for answer-engine readiness. Track E-E-A-T signals, build citation corroboration (sameAs), and see which AI crawlers visit your site &#x2014; all from a native backoffice dashboard, powered by the Geoa platform.]]></description>
                    <pubDate>Thu, 09 Jul 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.automate.inspector</guid>
                    <title>Umbraco.Community.Automate.Inspector</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.automate.inspector</link>
                    <description><![CDATA[Package Description]]></description>
                    <pubDate>Thu, 09 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.uibuilder.automate</guid>
                    <title>Umbraco.UIBuilder.Automate</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.uibuilder.automate</link>
                    <description><![CDATA[Umbraco UI Builder triggers and actions for Umbraco Automate]]></description>
                    <pubDate>Thu, 09 Jul 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.automate.slack</guid>
                    <title>Umbraco.Automate.Slack</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.automate.slack</link>
                    <description><![CDATA[Slack connection and actions for Umbraco Automate]]></description>
                    <pubDate>Thu, 09 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://umbraco.com/blog/launching-umbraco-automate/</guid>
                    <title>Launching Umbraco Automate</title>
                    <link>https://umbraco.com/blog/launching-umbraco-automate/</link>
                    <description><![CDATA[Streamline your CMS workflows with Umbraco Automate. Create unlimited drag-and-drop automations, triggers, and AI tool integrations in Umbraco 17&#x2B;.]]></description>
                    <pubDate>Thu, 09 Jul 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://owain.codes/blog/2026/july/are-you-okay/</guid>
                    <title>Are you okay</title>
                    <link>https://owain.codes/blog/2026/july/are-you-okay/</link>
                    <description><![CDATA[On men, mental health, and the communities that keep us going, in a job AI is quietly rewriting.]]></description>
                    <pubDate>Thu, 09 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://skttl.dev/blog/go-to-partial/</guid>
                    <title>Make Razor Partials Navigable in VS Code</title>
                    <link>https://skttl.dev/blog/go-to-partial/</link>
                    <description><![CDATA[A small VS Code extension that adds Go to Definition and live diagnostics for Razor partial view references in .cshtml files.]]></description>
                    <pubDate>Thu, 09 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://dev.to/chaudharidevam/why-we-pair-nextjs-with-umbraco-17--842</guid>
                    <title>Why We Pair Next.js with Umbraco 17 ?</title>
                    <link>https://dev.to/chaudharidevam/why-we-pair-nextjs-with-umbraco-17--842</link>
                    <description><![CDATA[&lt;p&gt;When building a content-driven website, there are two goals that are often in tension: give visitors a fast, modern, SEO-friendly site, and give the content team a CMS they can actually use without calling a developer every time a page needs to change.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;Our answer is to split the problem in two and let each half of the stack do what it&#x27;s best at:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Umbraco 17&lt;/strong&gt;, running on &lt;strong&gt;.NET 10&lt;/strong&gt;, as the content backend&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Next.js 16&lt;/strong&gt; with &lt;strong&gt;React 19&lt;/strong&gt;, running on the App Router, as the presentation layer&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;Here&#x27;s why we made that call, and how it plays out in practice.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Two apps, one clean contract&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Rather than bolting a headless CMS onto an existing site, we build the two halves as genuinely independent applications that only talk to each other over HTTP:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The Umbraco installation is the backoffice, the content types, the media library, the database. This is where content editors log in, build pages out of reusable blocks, and manage content like blog posts.&lt;/li&gt;&#xA;&lt;li&gt;The Next.js app is a standalone frontend. It never touches the Umbraco database directly, every piece of content it renders comes from an HTTP call.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;p&gt;That separation is the whole point of a &quot;headless&quot; CMS: the people managing content and the people managing the website&#x27;s code can move independently. CMS upgrades don&#x27;t require a frontend deploy, and frontend releases don&#x27;t require touching the CMS.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  The content pipeline: Umbraco&#x27;s Delivery API&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Umbraco 17 ships with a Content Delivery API a built-in, versioned JSON API that exposes published content without any custom plumbing. We lean on it heavily rather than building a bespoke API from scratch, which saves real development time.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;A page fetch from Next.js looks like this in practice:&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 http&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;GET /umbraco/delivery/api/v2/content/item/home?expand=properties[$all[properties[$all[properties[$all]]]]]&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&#xA;&lt;p&gt;That &lt;code&gt;expand&lt;/code&gt; parameter is doing a lot of work: pages are built by editors dragging and dropping content blocks (hero sections, feature grids, image-and-text panels, calls to action) using Umbraco&#x27;s Block Grid editor, and those blocks can be nested. The expansion query lets us pull an entire page blocks inside blocks inside blocks in a single round trip instead of chasing references with follow-up requests.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;On the Next.js side, a small typed fetch helper wraps every one of these calls, attaches an API key, and lets Next&#x27;s own data cache handle short-lived revalidation. There&#x27;s no GraphQL client, no heavyweight SDK just &lt;code&gt;fetch()&lt;/code&gt;, TypeScript types that mirror the Umbraco content model, and a short cache window so published changes show up almost immediately without hammering the CMS on every request.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Rendering: server-rendered, block by block&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Generic content pages funnel through a single catch-all route that renders server-side on each request. Instead of one big template, rendering is driven by content type: a dispatcher component looks at what kind of block came back from Umbraco a feature section, an image gallery, a testimonial, a two-column layout and hands it off to the matching React component.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;The effect is that adding a new content block is mostly a two-sided change: define the element type in Umbraco, add a matching case in the renderer. Editors get a new building block to compose pages with; developers don&#x27;t have to build new pages from scratch every time a new layout is needed.&lt;/p&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Beyond the CMS defaults&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;The Delivery API covers page content well, but a few features need more than &quot;fetch a page and render it&quot;:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Filtering and search.&lt;/strong&gt; Category pages, tag pages, and &quot;previous/next&quot; navigation are backed by custom API endpoints that walk the content tree directly, and free-text search runs on Umbraco&#x27;s built-in Lucene-based indexer rather than an external search service. That avoids standing up and paying for a separate search product just to let visitors search content.&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Forms.&lt;/strong&gt; Submissions are validated in the browser, sent through a Next.js API route, and stored by a small custom endpoint on the Umbraco side with a lightweight dashboard added to the Umbraco backoffice so the team can review submissions without leaving the CMS they already use every day.&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Media handling.&lt;/strong&gt; Images uploaded into Umbraco&#x27;s media library are served through Next.js&#x27;s image optimizer, so editors don&#x27;t need to think about responsive image sizes or formats that&#x27;s handled automatically on the way out.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  What this stack gets you&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Putting it together, the architecture gives:&lt;/p&gt;&#xA;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;Speed&lt;/strong&gt;, from server rendering and Next.js&#x27;s image and asset optimization&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;SEO control that lives with content&lt;/strong&gt;, since page titles, descriptions, and indexing rules are authored directly in Umbraco and flow straight into page metadata no separate SEO tooling to keep in sync&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;A content team that isn&#x27;t blocked by developers&lt;/strong&gt;, because new pages are built from existing blocks rather than new code&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;strong&gt;A frontend that isn&#x27;t blocked by the CMS release cycle&lt;/strong&gt;, because the two halves deploy independently&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h2&gt;&#xA;  &#xA;  &#xA;  Trade-offs worth naming&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;p&gt;Being candid, this approach isn&#x27;t free. Running on Umbraco 17 and Next.js 16 means running close to the front of both ecosystems fewer battle-tested examples to lean on, but a stack that stays current for years rather than needing a rewrite in one. And a headless setup means CMS preview/draft workflows, sitemaps, and secrets/hosting management all need to be built or configured deliberately they don&#x27;t come for free just because the CMS has them out of the box in a traditional, non-headless setup.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;For a site with a real content operation behind it, splitting &quot;where content lives&quot; from &quot;how it&#x27;s presented&quot; is worth the extra moving part. It lets each side of the team content and engineering work at their own pace, without waiting on each other.&lt;/p&gt;]]></description>
                    <pubDate>Wed, 08 Jul 2026 07:49:11 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://marketplace.umbraco.com/package/umbraco.community.drafts</guid>
                    <title>Umbraco.Community.Drafts</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.drafts</link>
                    <description><![CDATA[Auto-save your work as you go, just like Gmail. Never lose your edits again.]]></description>
                    <pubDate>Wed, 08 Jul 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.linkaudit</guid>
                    <title>Umbraco.Community.LinkAudit</title>
                    <link>https://marketplace.umbraco.com/package/umbraco.community.linkaudit</link>
                    <description><![CDATA[A lightweight, single-purpose link auditor for Umbraco. Scans published content on a schedule (or on demand), reports broken external links and links that point at hosts you would rather keep internal &#x2014; all from a read-only backoffice dashboard. Reads the content cache directly rather than crawling the rendered site.]]></description>
                    <pubDate>Wed, 08 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</category>
                </item>
                <item>
                    <guid>https://www.dynamicdave.nl/blog/umbraco-18-elements/</guid>
                    <title>Umbraco 18 Finally gives reusable content the home it deserves</title>
                    <link>https://www.dynamicdave.nl/blog/umbraco-18-elements/</link>
                    <description><![CDATA[There are flashy features that get everyone excited&#x2014;new editors, AI integrations, shiny dashboards. They look great in a keynote and are fun to show off. But then there are those features that, quietly, just fix long-standing headaches. For me, the new Library and Elements in Umbraco 18 are absolutely in that second group.When I first saw these demoed at Codegarden, I immediately thought, &quot;Here we go. This is definitely going to be one of my favorite updates since a long time.&quot; It&#x27;s not a brand-new idea. In fact, it&#x27;s almost more impressive because it turns something most experienced Umbraco developers have hacked together themselves into an actual, official feature.If you&#x2019;ve built Umbraco websites for any length of time, you&#x2019;ve probably done this: made a &#x201C;Globals &#x201C; of &#x201C;Various Content&#x201D; node and hidden it, set up a Shared Content folder, tossed reusable stuff onto a Settings page, or kept a folder with call-to-actions, testimonials, author profiles, or banners. None of which are even real pages.Did it work? Yeah&#x2026; most of the time. But let&#x27;s be honest&#x2014;it always felt like a kludge.That kind of content never really belonged alongside website pages. This &#x201C;content&#x201D; didn&#x2019;t need URLs; users weren&#x2019;t supposed to visit it. We only structured things this way because editors needed somewhere to manage reusable pieces. For years, we just pretended these were documents because Umbraco left us no other option.With Umbraco 18, the compromise disappears.]]></description>
                    <pubDate>Tue, 07 Jul 2026 22:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://umbracocommunity.social/@UmbHost/116877874250829198</guid>
                    <title>UmbHost GreenStack&#x27;s UK is now live!</title>
                    <link>https://umbracocommunity.social/@UmbHost/116877874250829198</link>
                    <description><![CDATA[&#x1F33F;&#x1F1EC;&#x1F1E7;&#x1F680; GreenStack&#x27;s UK is now live! &#x1F33F;&#x1F1EC;&#x1F1E7;&#x1F680; Our most requested feature since the January launch! Full UK data residency for Umbraco hosting! Files, databases, and backups all stay in the UK, served from our new London infrastructure. All package tiers (Core, Pro, and Scale) are available from day one, with the same pricing as the EU region. If data residency has been holding you back, that barrier is gone &#x1F4A5; https://umbhost.net/blog/2026/07/greenstack-comes-home-uk-region-now-available#Umbraco #Hosting #GreenStack]]></description>
                    <pubDate>Tue, 07 Jul 2026 15:54:09 Z</pubDate>
                        <category>community</category>
                        <category>social</category>
                        <category>mastodon</category>
                </item>
                <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://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://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>Tue, 07 Jul 2026 00:00:00 Z</pubDate>
                        <category>hq</category>
                        <category>blog</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://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://marathonus.com/about/blog/what-umbraco-codegarden-2026-left-on-me-permanently/</guid>
                    <title>What Umbraco Codegarden 2026 Left on Me&amp;#x2014;Permanently | Marathon Consulting</title>
                    <link>https://marathonus.com/about/blog/what-umbraco-codegarden-2026-left-on-me-permanently/</link>
                    <description><![CDATA[Marathon&#x27;s Scott Clevenger reflects on Umbraco Codegarden 2026 &amp;#x2014; an MVP, a tattoo, and a platform that&#x27;s ready for whatever comes next.]]></description>
                    <pubDate>Mon, 06 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.linkedin.com/pulse/ai-signalling-end-cms-we-know-simply-becoming-much-bigger-durrant-z3nme/</guid>
                    <title>Is AI signalling the end of the CMS as we know it? Or is it simply becoming something much bigger?</title>
                    <link>https://www.linkedin.com/pulse/ai-signalling-end-cms-we-know-simply-becoming-much-bigger-durrant-z3nme/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Mon, 06 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://gibe.digital/blog/gibe-goes-to-codegarden-2026-edition/</guid>
                    <title>Gibe goes to Codegarden (2026 edition)</title>
                    <link>https://gibe.digital/blog/gibe-goes-to-codegarden-2026-edition/</link>
                    <description><![CDATA[Gibe reflects on Codegarden 2026, covering the latest Umbraco announcements, standout sessions, community highlights, and our Package Award nomination.]]></description>
                    <pubDate>Mon, 06 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</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://www.nevitech.co.uk/blog/introducing-imagesharp-trimcache-for-umbraco/</guid>
                    <title>Introducing ImageSharp TrimCache for Umbraco</title>
                    <link>https://www.nevitech.co.uk/blog/introducing-imagesharp-trimcache-for-umbraco/</link>
                    <description><![CDATA[A free Umbraco package that trims the ImageSharp.Web image cache by age on a schedule, for both the local physical cache and Azure Blob storage. Stop the media cache growing unbounded on Umbraco Cloud and self hosted sites.]]></description>
                    <pubDate>Fri, 03 Jul 2026 23:00:00 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[I&#x27;ve been maintaining Examine 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.&#xA;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. I&#x27;ve shipped a few releases off the back of it and some of the hot-path improvements are genuinely a bit ridiculous.&#xA;So what are these &quot;agentic workflows&quot;?&#xA;The thing I installed is GitHub Next&#x27;s Agentic Workflows - 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.&#xA;I ended up with a few of them running on Examine:&#xA;&#xA;Perf Improver - runs daily, hunts for performance bottlenecks, writes benchmarks to actually prove the improvement, and opens a draft PR with the before/after numbers.&#xA;Efficiency Improver - its scrappier sibling, focused on the smaller allocation-and-LINQ-state-machine wins that add up over time.&#xA;Daily Issue Triage - goes through untriaged issues, sets types, applies labels, spots duplicates, and leaves a tidy triage report for me.&#xA;Agentic Maintenance - keeps the whole setup ticking along.&#xA;&#xA;Each one is just a markdown file in .github/workflows/ with a description, a schedule, some safe-outputs 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.&#xA;How it actually works day to day&#xA;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.&#xA;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. That&#x27;s the whole loop. I&#x27;m the reviewer, the agent is the workhorse doing the grind I never had time for.&#xA;So what did they actually get done?&#xA;Over roughly the last two months, here&#x27;s what these workflows actually got up to on Examine:&#xA;&#xA;124 successful Perf Improver runs and 9 successful Efficiency Improver runs&#xA;20 successful Daily Issue Triage runs quietly keeping the issue tracker tidy&#xA;24 performance/efficiency PRs reviewed and merged (13 from Perf Improver, 11 from Efficiency Improver) between late May and the end of June&#xA;And the bit that actually matters - three releases shipped off this work: v3.8.0, v3.9.0 and the v4.0.0-beta.7 pre-release&#xA;&#xA;That last point is really the whole thing. This isn&#x27;t a pile of speculative branches rotting in a fork somewhere - it&#x27;s code that went through my review, passed CI, and is now sitting in NuGet packages that real Umbraco sites are running.&#xA;Show me the numbers&#xA;Right, this is the part I actually get excited about. One of my favourite things about the Perf Improver is that its prompt tells it to only attempt improvements it can actually measure - establish a baseline first, make the change, then measure again and document both numbers. For the algorithmic hot-path stuff that means benchmarks, so along the way it built out a proper BenchmarkDotNet 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.&#xA;The full-text search hot path&#xA;ManagedQuery is the 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 stacked up a series of small, individually measured changes: a volatile factory cache in SearchContext.GetFieldValueType, an early return in the extract-terms check, and killing off some redundant ConcurrentDictionary lookups in AddDocument.&#xA;Here&#x27;s the current source vs the most recent 3.3.0 release, on a 1,000-document index:&#xA;&#xA;&#xA;&#xA;Method&#xA;Version&#xA;Mean&#xA;Allocated&#xA;&#xA;&#xA;&#xA;&#xA;ManagedQueryAllFields&#xA;3.3.0&#xA;11.42 ms&#xA;1,323 KB&#xA;&#xA;&#xA;ManagedQueryAllFields&#xA;Source&#xA;2.17 ms&#xA;371 KB&#xA;&#xA;&#xA;&#xA;That&#x27;s about 5.3x faster and roughly 3.6x less memory allocated on the single most travelled code path in the whole library. On the busiest thing Examine does. I&#x27;ll happily take that.&#xA;Building queries&#xA;GroupedAnd / GroupedOr / GroupedNot are the workhorses of the query builder. A little string[] fast-path (skipping a defensive .ToArray() copy when the caller already handed it a string[]) plus some allocation trimming got this:&#xA;&#xA;&#xA;&#xA;Method&#xA;Version&#xA;Mean&#xA;Allocated&#xA;&#xA;&#xA;&#xA;&#xA;CreateQueryOnly&#xA;3.3.0&#xA;3,995 ns&#xA;8.34 KB&#xA;&#xA;&#xA;CreateQueryOnly&#xA;Source&#xA;319 ns&#xA;2.20 KB&#xA;&#xA;&#xA;GroupedAndStringArray&#xA;3.3.0&#xA;21,377 ns&#xA;21.10 KB&#xA;&#xA;&#xA;GroupedAndStringArray&#xA;Source&#xA;16,659 ns&#xA;14.34 KB&#xA;&#xA;&#xA;&#xA;The CreateQuery() 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.&#xA;Constructing a ValueSet&#xA;Every single document you index goes through a ValueSet 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:&#xA;&#xA;&#xA;&#xA;Method&#xA;Version&#xA;Mean&#xA;Allocated&#xA;&#xA;&#xA;&#xA;&#xA;FromDictionary5Fields&#xA;3.3.0&#xA;1,183 ns&#xA;2,200 B&#xA;&#xA;&#xA;FromDictionary5Fields&#xA;Source&#xA;226 ns&#xA;592 B&#xA;&#xA;&#xA;FromDictionary20Fields&#xA;3.3.0&#xA;4,007 ns&#xA;6,544 B&#xA;&#xA;&#xA;FromDictionary20Fields&#xA;Source&#xA;654 ns&#xA;1,520 B&#xA;&#xA;&#xA;&#xA;That&#x27;s roughly 5-6x faster and about 4x less allocated on indexing, and when you&#x27;re rebuilding the index on a large Umbraco site that adds up fast.&#xA;The really nice touch is that these benchmark result tables now live in &lt;remarks&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.&#xA;Was it actually worth it?&#xA;For me the thing that makes it work is 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, run CI, and decide in a couple of minutes. It&#x27;s not zero effort - I still read every change before it goes anywhere near main - 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 I maintain around everything else, that&#x27;s a pretty great deal.&#xA;If you maintain a repo with a backlog you never get to, especially performance work that needs benchmarks to justify it, I&#x27;d recommend giving GitHub Next&#x27;s agentics a go.&#xA;You can see all of it out in the open on the Examine repo - the [perf-improver] and [efficiency-improver] PRs, the benchmark suite, and the releases they fed into. And there&#x27;s a nice bonus here for me too: ExamineX, my managed, cloud-hosted Examine search offering, runs on this exact same internal plumbing. So all this work the agents have been doing to tighten up Examine&#x27;s query and indexing hot paths feeds straight through into ExamineX - 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 your search running as a managed service instead of hosting Lucene indexes on your own servers, that&#x27;s what ExamineX is there for. &#x1F642;]]></description>
                    <pubDate>Fri, 03 Jul 2026 17:45:20 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://github.com/limbo-works/Limbo.Umbraco.Tables/releases/tag/v17.0.0-alpha001</guid>
                    <title>Limbo.Umbraco.Tables 17.0.0-alpha001</title>
                    <link>https://github.com/limbo-works/Limbo.Umbraco.Tables/releases/tag/v17.0.0-alpha001</link>
                    <description><![CDATA[Limbo.Umbraco.Tables is a package for Umbraco featuring property editor for building table based content.]]></description>
                    <pubDate>Fri, 03 Jul 2026 12:56:06 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://medium.com/@ravimotha/umbraco-london-july-meetup-the-write-up-b4ce49a37390?source=rss-8e76be83b03f------2</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-8e76be83b03f------2</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 03 Jul 2026 09:18:14 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://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://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://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://www.dutchumbracoalliance.nl/en</guid>
                    <title>Dutch Umbraco Alliance Festival, a new festival on september 22 in the netherlands.</title>
                    <link>https://www.dutchumbracoalliance.nl/en</link>
                    <description><![CDATA[Dutch Umbraco Alliance Festival, a new festival on september 22 in the netherlands. We like to get a lot of people.]]></description>
                    <pubDate>Thu, 02 Jul 2026 05:29:39 Z</pubDate>
                        <category>community</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://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://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://www.linkedin.com/feed/update/urn:li:ugcPost:7478382465955500033/</guid>
                    <title>How to setup Claude Design &#x2B; the Umbraco UI Library</title>
                    <link>https://www.linkedin.com/feed/update/urn:li:ugcPost:7478382465955500033/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 01 Jul 2026 17:53:35 Z</pubDate>
                        <category>community</category>
                        <category>linkedin</category>
                        <category>social</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://www.dot-see.com/blog/mega-update-dotseediscipline-ui-based-configuration/</guid>
                    <title>Mega update: DotSee.Discipline UI-based configuration</title>
                    <link>https://www.dot-see.com/blog/mega-update-dotseediscipline-ui-based-configuration/</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Wed, 01 Jul 2026 14:26:05 Z</pubDate>
                        <category>blog</category>
                        <category>community</category>
                </item>
                <item>
                    <guid>https://github.com/limbo-works/Limbo.Umbraco.TwentyThree/releases/tag/v17.0.0-alpha001</guid>
                    <title>Limbo.Umbraco.TwentyThree 17.0.0-alpha001</title>
                    <link>https://github.com/limbo-works/Limbo.Umbraco.TwentyThree/releases/tag/v17.0.0-alpha001</link>
                    <description><![CDATA[Video picker for inserting TwentyThree videos in Umbraco.]]></description>
                    <pubDate>Wed, 01 Jul 2026 11:21:15 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://www.cantarus.com/articles/codegarden-2026-open-composable-ai-future/?utm_source=linkedin.com&amp;utm_medium=social&amp;utm_campaign=blog-codegarden-2026-06</guid>
                    <title>Umbraco Codegarden 2026: Open, composable and ready for an AI future</title>
                    <link>https://www.cantarus.com/articles/codegarden-2026-open-composable-ai-future/?utm_source=linkedin.com&amp;utm_medium=social&amp;utm_campaign=blog-codegarden-2026-06</link>
                    <description><![CDATA[Cantarus - Umbraco Codegarden 2026: Open, composable and ready for an AI future | Cantarus]]></description>
                    <pubDate>Wed, 01 Jul 2026 08:59:55 Z</pubDate>
                        <category>blog</category>
                        <category>community</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://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, secure file uploads (stored outside wwwroot, authenticated download), entry export as CSV or ZIP (data &#x2B; uploaded files), and public submit/render APIs. Render any form with a single ViewComponent call. Database-agnostic: runs on SQL Server, SQLite and PostgreSQL.]]></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/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://marketplace.umbraco.com/package/casko.xmlsitemapsforumbraco</guid>
                    <title>Casko.XmlSitemapsForUmbraco</title>
                    <link>https://marketplace.umbraco.com/package/casko.xmlsitemapsforumbraco</link>
                    <description><![CDATA[XML Sitemaps for Umbraco helps Umbraco projects publish XML sitemaps in a structured, configurable way. It is designed for teams that want reliable sitemap delivery for search engines without having to build and maintain the full solution themselves.]]></description>
                    <pubDate>Wed, 01 Jul 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                        <category>marketplace</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>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://skttl.dev/blog/small-ux-details-ai-coding/</guid>
                    <title>Small UX Details Make AI Coding Better</title>
                    <link>https://skttl.dev/blog/small-ux-details-ai-coding/</link>
                    <description><![CDATA[After trying Devin, Windsurf, Codeium, Claude Code, and now the Codex desktop app, I keep coming back to the same thing: small interface details matter a lot when AI is writing code.]]></description>
                    <pubDate>Tue, 30 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</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://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://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/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[Translate Umbraco content across cultures with AI. umContentTranslator walks your content tree, collects translatable values, batches them, and writes the AI translations back into the target languages &#x2014; preserving Block Grid and Block List structure, rich text, Markdown, links, and other editor-specific data. Powered by Claude (Anthropic) or OpenAI, it also translates Umbraco dictionary items and adds a Content Translator section with a translation dialog and a Translation Logs dashboard. Includes a built-in free trial.]]></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://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 23:06:54 Z</pubDate>
                        <category>community</category>
                        <category>youtube</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://anju-dev-notes.hashnode.dev/my-first-codegarden-experience-a-journey-from-india-to-copenhagen</guid>
                    <title>My First Codegarden Experience &#x2014; A Journey from India to Copenhagen</title>
                    <link>https://anju-dev-notes.hashnode.dev/my-first-codegarden-experience-a-journey-from-india-to-copenhagen</link>
                    <description><![CDATA[Attending Codegarden for the first time was truly a milestone moment in my career &#x2014; not just because of the event itself, but because it also became a very personal and memorable journey for me.&#xA;This]]></description>
                    <pubDate>Fri, 26 Jun 2026 10:36:14 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[Add a Force Delete entity action to the Umbraco backoffice, allowing developers and editors to permanently remove 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/</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://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/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://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://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.nurhakkaya.com/2026/06/im-umbraco-mvp-for-fifth-year-running.html</guid>
                    <title>I&#x27;m an Umbraco MVP for the fifth year running!</title>
                    <link>https://www.nurhakkaya.com/2026/06/im-umbraco-mvp-for-fifth-year-running.html</link>
                    <description><![CDATA[Every year, Umbraco recognises the people who have gone above and beyond with their contributions to Umbraco projects and community, and I am pleased to announce that I am honoured to be renewed as an Umbraco MVP for the fifth consecutive year.&amp;nbsp;To celebrate this achievement, I also wrote an article which you can read here.&amp;nbsp;Thank you, Umbraco, and the Umbraco community, for their fantastic support in making this happen once more! #h5yr&amp;nbsp;]]></description>
                    <pubDate>Wed, 24 Jun 2026 14:04:05 Z</pubDate>
                        <category>community</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[In this session from Codegarden, Phil Whittaker explores the strategic vision and practical application of Umbraco in an AI-first world. The discussion details how AI agents and Large Language Models (LLMs) interact with the CMS outside of the traditional backoffice environment using shared best practices.&#xA;&#xA;The presentation covers the architectural shift from a base Model Context Protocol (MCP) server to a chained MCP architecture. By reducing technical friction, developers can enable AI agents to assist directly with content modeling, site deployment, and day-to-day management tasks.&#xA;&#xA;This video is designed for Umbraco developers, digital agencies, and content editors looking to integrate AI orchestration into modern web development. As agentic workflows become standard, learning how to build composable AI skills and deploy deterministic workflows ensures your digital experiences remain maintainable and future-proof.&#xA;&#xA;Key Takeaways:&#xA;- Augmentation over Automation: Focusing on how developers and AI can collaborate effectively rather than replacing human expertise.&#xA;&#xA;- The Open-Source Advantage: Why Umbraco&#x27;s transparent architecture makes it uniquely positioned for efficient AI model training and context comprehension.&#xA;&#xA;- Streamlining the Pitch Phase: Using the Umbraco UI library within design tools to prototype backoffice extensions rapidly.&#xA;&#xA;- The MCP Software Factory: Combining deterministic CLI phases and probabilistic AI phases to scaffold, build, and test custom MCP servers.&#xA;&#xA;- Chained and Remote MCPs: Establishing cross-connector collaboration between external tools (like Google Drive) and Umbraco to manage content at scale.&#xA;&#xA;Timeline Chapters:&#xA;00:00 - Introduction to Umbraco in AI&#xA;01:40 - The Evolution of AI and Agentic Products&#xA;03:03 - Strategy for Reducing Friction with AI Agents&#xA;04:56 - Open Source as an AI Advantage&#xA;06:59 - Leveraging AI in the Product Pitch Phase&#xA;11:56 - Implementing Backoffice Extension Skills&#xA;14:33 - AI in Production: Content Modeling and Implementation&#xA;21:32 - The Role of the Community AI Team&#xA;22:23 - Building Umbraco MCP Servers via Software Factories&#xA;27:07 - Architecture of Chained MCPs&#xA;29:03 - The AI-Accelerated Editor Experience&#xA;33:14 - Practical Prompts and Cross-Connector Collaboration&#xA;36:22 - Hosting Options: Umbraco Cloud and Cloudflare Workers&#xA;38:00 - Custom Editor Workflows and Deterministic Processes&#xA;42:46 - Building for Future Capabilities and Conclusion&#xA;&#xA;Resources and Links&#xA;Umbraco AI Initiatives &amp; Product Pages: https://umbraco.com/products/ai/&#xA;&#xA;Latest Umbraco Product Update: https://umbraco.com/blog/umbraco-product-updatecodegarden-keynote-highlights-q2-2026/ &#xA;&#xA;Umbraco in AI documentation: https://docs.umbraco.com/umbraco-in-ai&#xA;&#xA;Codegarden: https://codegarden.umbraco.com/]]></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://www.linkedin.com/pulse/you-never-know-whatll-stick-briony-mckenzie-2bjie/</guid>
                    <title>You Never Know What&#x27;ll Stick</title>
                    <link>https://www.linkedin.com/pulse/you-never-know-whatll-stick-briony-mckenzie-2bjie/</link>
                    <description><![CDATA[On unconventional career paths, accidental dev tools, and great people. There]]></description>
                    <pubDate>Wed, 24 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</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://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://www.dynamicdave.nl/blog/developer-productivity-hacks/</guid>
                    <title>Boost Your Workflow with Umbraco 17: Developer Productivity Hacks</title>
                    <link>https://www.dynamicdave.nl/blog/developer-productivity-hacks/</link>
                    <description><![CDATA[As developers, we&#x2019;re always searching for ways to get our work done faster. New frameworks roll out and promise to make us blazing fast, AI tools keep booming with talk about writing half our code, and if you&#x2019;ve ever sat through a developer conference lately, you know there&#x2019;s always a session on &#x201C;How to be More Productive.&#x201D; But after working with Umbraco since version 4, I have to be honest: those massive productivity leaps don&#x2019;t really come from the shiny, new, revolutionary tools. It all comes down to friction. And not the dramatic, show-stopping kind. I mean those hundreds of tiny speed bumps scattered all over your day. A few extra clicks in the Umbraco backoffice. Rebuilding the same component again and again. Always double-checking a property alias. Waiting for your solution to spin up. Poring over a monster Razor file, desperately trying to recall where you put that chunk of markup. None of these feel like deal-breakers on their own, but stacked together? Suddenly, you&#x2019;re delivering features at a crawl. What&#x2019;s won me over with the latest Umbraco versions, especially Umbraco 17, is just how much more aligned the platform is with standard .NET development. It feels less like you&#x2019;re wrestling with a quirky CMS and more like you&#x2019;re just building .NET applications. There&#x2019;s a real payoff: less fighting the system means more time solving real business problems.Over the years I&#x2019;ve picked up quite a few habits that speed up Umbraco development and make it less painful&#x2014;some are tied directly to Umbraco 17, while others are just hard-earned lessons from a decade of building websites.&amp;nbsp;Here&#x2019;s what&#x2019;s helped the most for me.]]></description>
                    <pubDate>Tue, 23 Jun 2026 22:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.youtube.com/watch?v=wx7Qiyi2Y90</guid>
                    <title>Kenn Jacobsen, It&#x27;s Elemental; reuse your content!</title>
                    <link>https://www.youtube.com/watch?v=wx7Qiyi2Y90</link>
                    <description><![CDATA[Discover how upcoming updates to the Umbraco CMS introduce a dedicated, native framework for managing reusable components. This session details the architectural transition away from traditional content tree workarounds toward a structured, centralized approach that optimizes backend performance and editorial control.&#xA;&#xA;Learn about the native Library section and Elements feature launching with Umbraco 18, alongside an early look at the comprehensive block editor integrations scheduled for Umbraco 19. The presentation highlights how these framework changes resolve historical challenges regarding schema inflation, content routing security, and context-switching during development.&#xA;&#xA;Who This Video Is For:&#xA;This session is designed for Umbraco developers, solution architects, and technical content editors managing complex, multi-site, or multi-tenant environments. Understanding these architectural changes ensures teams can design leaner schemas and build intuitive, decoupled component libraries for future projects.&#xA;&#xA;Key Takeaways:&#xA;- Built on Existing Frameworks: Elements utilize familiar native systems like Models Builder and IPublishedElement, ensuring a minimal learning curve for developers.&#xA;&#xA;- Leaner Database Schemas: Eliminates the necessity of duplicating document types for local and global contexts, maintaining uniform rendering pipelines regardless of data origin.&#xA;&#xA;- Native Security and Non-Routable Architecture: Centralized elements do not generate independent URLs or templates, removing template-sniffing risks and Delivery API exposure.&#xA;&#xA;- Segmented Permissions: Dedicated configuration layers separate content tree permissions from library access, reducing administration overhead in tenant environments.&#xA;&#xA;- Strict Control Mechanisms: Content libraries remain strictly opt-in on a per-element-type basis, preventing structural clutter from baseline utility compositions.&#xA;&#xA;Video Chapters:&#xA;00:00 - Introduction and Welcome&#xA;00:22 - Traditional Workarounds for Reusable Content&#xA;01:29 - Editor Friction and Content Tree Workflows&#xA;02:32 - Block Structure and JSON Serialization Challenges&#xA;05:32 - Technical Friction: Routing, Delivery API, and Security&#xA;07:04 - Schema Growth and Component Rendering Complexities&#xA;08:42 - Centralizing Content: Arriving in the New Library Section&#xA;09:44 - Architectural Overview: Sourcing Elements vs Local Blocks&#xA;11:55 - Cross-Context Tracking with the Out-of-Context Link Icon&#xA;14:26 - Element Characteristics: Lifecycles, Permissions, and Multi-Tenancy&#xA;16:52 - Managing Library Control via Opt-In Configurations&#xA;17:29 - Future Scope: Consolidating Editorial Features into the Library&#xA;18:16 - Implementation Roadmap: Umbraco 18 and Umbraco 19 Updates&#xA;18:44 - Live Demo: Implementing and Configuring the Element Picker&#xA;21:48 - Managing Lifecycles, Single-Sourced Editing, and Preview Mode&#xA;28:44 - Technical Preview: Future Block Editor Integrations&#xA;34:12 - Advanced Editorial Control: Disconnecting and Transferring Sourced Elements&#xA;40:59 - Strategic Takeaways and Presentation Wrap-Up&#xA;&#xA;Key Resources and Links:&#xA;Umbraco 18 Release Candidate: https://umbraco.com/blog/umbraco-18-release-candidate/ &#xA;&#xA;Umbraco CMS: https://umbraco.com/products/umbraco-cms/]]></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[Umbraco AI Staff Engineer and Lead Developer, Matt Brailsford, goes beneath the surface of out-of-the-box copilot packages to show how developers can extend the core platform. Using a real-world podcast management system as a blueprint, this technical deep dive demonstrates how to leverage native framework architecture to build tailored client solutions.&#xA;&#xA;The presentation walks through practical implementations of programmatic speech-to-text execution, custom LLM profile isolation, and context layering. Matt illustrates how to inject dynamic data from background systems and empower models to run custom execution tools rather than relying on manual, hard-coded prompt strings.&#xA;&#xA;This video is for Umbraco backend developers, solution architects, and engineering leads looking to solve complex business requirements with generative AI. It details how to move away from rigid chat interfaces and toward resilient, goal-oriented AI agents integrated into back-office event handlers and automation pipelines.&#xA;&#xA;What You Will Learn:&#xA;- How to orchestrate background queuing for long-running LLM tasks without blocking the content-saving process.&#xA;&#xA;- The method for building custom context resource types that auto-generate Umbraco back-office UI elements using C# code attributes.&#xA;&#xA;- How to implement custom AI Tools that give LLMs secure access to external data registries like the HubSpot API.&#xA;&#xA;- The architectural benefits of shifting from step-by-step prompting to goal-oriented AI Agent reasoning.&#xA;&#xA;- Techniques for marrying Umbraco AI with Umbraco Automate to manage custom event triggers, workflow conditioning, and token management.&#xA;&#xA;Chapters:&#xA;00:00 - Introduction &amp; The Core Philosophy of Umbraco AI&#xA;01:52 - Demo Overview: Podcast Management Requirements&#xA;03:49 - Setting up a Background Queue &amp; Loop Prevention&#xA;06:41 - Configuring Connections, LLM Profiles, and Brand Context&#xA;08:02 - Step 1: Programmatic Audio Transcription Implementation&#xA;09:47 - Step 2: Generating Episode Summaries &amp; Show Notes&#xA;12:12 - Debugging LLM Behavior via AI Back Office Logs&#xA;14:04 - Extending Context: Building Custom Resource Types&#xA;18:16 - Always Inject vs. On-Demand Context Configurations&#xA;21:48 - Empowering LLMs via Custom AI Tools &amp; HubSpot API&#xA;29:27 - Shifting to AI Agents for Goal-Oriented Reasoning&#xA;34:54 - Analyzing Agent Decision-Making &amp; Conversation Logs&#xA;37:16 - Integrating Umbraco AI with Umbraco Automate&#xA;41:40 - Custom Triggers, Actions, and Automated Notifications&#xA;44:18 - Summary of Extension Points &amp; Closing Remarks&#xA;&#xA;Links &amp; Resources: &#xA;Umbraco, the agent-ready CMS: https://umbraco.com/products/ai/&#xA;&#xA;Umbraco AI Framework Documentation &amp; Developer Guides: https://docs.umbraco.com/ai-in-umbraco&#xA;&#xA;Umbraco Automate product page: https://umbraco.com/products/add-ons/automate/&#xA;&#xA;Codegarden 2026 Session Schedule &amp; Announcements: https://codegarden.umbraco.com/]]></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[Umbraco CMS Product Manager, Bolette Kern, outlines the strategic evolution of content management systems in the era of generative artificial intelligence. Rather than hard-coding trendy, rigid AI features directly into the core platform, Umbraco&#x27;s architecture focuses on establishing an extensible framework built on choice, governance, and structural flexibility.&#xA;&#xA;This session breaks down how organizations can implement AI workflows on their own terms, utilizing localized control profiles, pre-generation data screening, and automated performance testing. It also highlights how the platform is preparing for an ecosystem where external AI agents read, write, and manage content alongside human creators.&#xA;&#xA;This video is for digital agency architects, enterprise development teams, content strategists, and product owners who need to design future-proof content platforms. It provides a technical blueprint for maintaining data privacy, evaluating non-deterministic LLM outputs, and managing concurrent multi-author content changes safely.&#xA;&#xA;What You Will Learn:&#xA;- The structural risks of vendor-locked AI strategies and why platform flexibility acts as a long-term competitive advantage.&#xA;&#xA;- How to configure pre-generation PII guardrails using regular expressions to protect sensitive user data before it reaches external LLMs.&#xA;&#xA;- Methods for quality-checking non-deterministic prompt outputs using automated grading criteria and side-by-side model comparisons.&#xA;&#xA;- The architecture of Model Context Protocol (MCP) servers and open-source agent skills designed to guide AI assistants in writing idiomatic Umbraco code.&#xA;&#xA;- A first look at upcoming core CMS features for real-time editor collaboration, property-level merge resolution, and visual text differentiation within block editors.&#xA;&#xA;Chapters&#xA;00:00 - The Role of a CMS in an Unpredictable Future&#xA;02:04 - Umbraco&#x27;s Two-Track AI Strategy Overview&#xA;03:02 - The Risks of Hard-Coding AI into the CMS Core&#xA;05:15 - Demo: Managing LLM Connections, Profiles, and Contexts&#xA;06:14 - Enforcing PII Guardrails and Content Integrity Rules&#xA;08:36 - Testing and Grading Non-Deterministic AI Prompt Performance&#xA;13:32 - Leveraging the Umbraco AI Foundation for Custom Packages&#xA;15:30 - Track 2: Interfacing with External AI Agents&#xA;17:43 - Open-Source Agent Skills for Best-Practice Code Generation&#xA;22:46 - Model Context Protocol (MCP) Platform Architecture&#xA;26:48 - Demo: Content Orchestration via the Hosted CMS Editor MCP&#xA;31:43 - Automating Content Audits with Global Updates&#xA;35:18 - Core Platform Advantages in a Code-Generation Ecosystem&#xA;38:41 - Roadmap: Property-Level Editor Collaboration &amp; Conflict Resolution&#xA;41:44 - Integrating Visual Diff Views into the Publishing Flow&#xA;&#xA;Links &amp; Resources&#xA;&#xA;Umbraco, the agent-ready CMS: https://umbraco.com/products/ai/the-agent-ready-cms/ &#xA;&#xA;Codegarden: https://codegarden.umbraco.com/]]></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://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://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://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/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://www.linkedin.com/pulse/my-first-codegarden-ai-umbraco-17-18-why-im-excited-build-murthy-3ncxe/</guid>
                    <title>My First CodeGarden: AI, Umbraco 17 and 18, and Why I</title>
                    <link>https://www.linkedin.com/pulse/my-first-codegarden-ai-umbraco-17-18-why-im-excited-build-murthy-3ncxe/</link>
                    <description><![CDATA[This was my first time travelling to Copenhagen, and my first ever CodeGarden, and what a way to start. I went over with Luca Colella and Kat Dixon and we had a brilliant couple of days.]]></description>
                    <pubDate>Tue, 23 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</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[Umbraco Cloud Lead, Bjarke Berg, delivers a technical keynote at Codegarden 2026 detailing the operational realities of hosting web platforms in a shifting threat and traffic landscape. With automated bot scanning and AI-driven probes doubling overall platform requests to 10 billion monthly hits, legacy hosting defaults are no longer sufficient to guarantee stability.&#xA;&#xA;The presentation reviews a year of infrastructure updates driven by a core philosophy of user self-service. Key product rollouts include edge-enriched performance analytics via Cloudflare, custom fallback error pages, granular carbon tracking APIs through direct Azure integration, and dedicated compute load balancing powered by out-of-process Redis caching.&#xA;&#xA;Who This Video Is For:&#xA;This session is designed for technical architects, systems administrators, backend developers, and digital agencies operating Umbraco infrastructure. It provides actionable best practices on platform protection, explains the performance impacts of production runtime mode configurations, and maps out the platform&#x27;s architectural transition to containerized, CI/CD-aligned artifact deployments.&#xA;&#xA;Key Takeaways:&#xA;- How automated bot traffic has shifted platform demands and why edge network DOS mitigation is mandatory.&#xA;&#xA;- The security and performance implications of compiling views using Production Runtime Mode settings.&#xA;&#xA;- How to configure custom fallback pages, localized maintenance windows, and proactive alert rules using webhooks.&#xA;&#xA;- The mechanics of load balancing using out-of-process Redis caching under sticky session configurations.&#xA;&#xA;- The upcoming Artifact Deployment model designed for external CI/CD pipelines and zero-downtime rolling updates.&#xA;&#xA;- Umbraco&#x2019;s long-term infrastructure roadmap moving toward multicloud availability, containerization, and Linux hosting environments.&#xA;&#xA;Chapters:&#xA;00:00 - Introduction &amp; Self-Service Strategy&#xA;02:12 - Traffic &amp; Performance Edge Analytics&#xA;06:11 - Custom Error Pages &amp; Sustainability Dashboards&#xA;08:07 - Load Balancing &amp; Redis Caching Configurations&#xA;10:42 - Scaling Under 2026 Bot &amp; Automated Traffic Pressures&#xA;12:50 - Security Foundations &amp; DOS Mitigation&#xA;15:33 - Maximizing Performance via Production Runtime Mode&#xA;17:22 - Web Application Firewalls &amp; Content Caching Headers&#xA;23:17 - Clean Repositories &amp; Configuration Best Practices&#xA;24:28 - Proactive Uptime Monitoring &amp; Webhook Alert Rules&#xA;27:15 - Scheduled Maintenance Windows by Timezone&#xA;31:07 - Architectural Shift: Introducing Artifact Deployments&#xA;35:10 - Read-Only Schema Controls &amp; Automated Pull Requests&#xA;37:27 - Unlocking Zero-Downtime Rolling Updates&#xA;38:42 - Long-Term Horizon: Multicloud, Containers, and Linux&#xA;&#xA;Links &amp; Resources:&#xA;Umbraco Cloud product page: https://umbraco.com/products/umbraco-cloud/&#xA;&#xA;Umbraco for Enterprise Solutions: https://umbraco.com/products/umbraco-for-enterprise/&#xA;&#xA;Umbraco Product Update q2, 2026: https://umbraco.com/blog/umbraco-product-updatecodegarden-keynote-highlights-q2-2026/ &#xA;&#xA;Codegarden Sessions &amp; Announcements: https://codegarden.umbraco.com/]]></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 Codegarden Keynote, 2026: Mats Persson, Emma Bustow &amp; Filip Bech-Larsen</title>
                    <link>https://www.youtube.com/watch?v=ThgXALBfU-g</link>
                    <description><![CDATA[This keynote kicks off the flagship annual event, Codegarden, bringing together the global community to look back at a milestone year and preview what lies ahead for the ecosystem.&#xA;&#xA;The presentation is hosted by Umbraco CEO Mats Persson, Umbraco CTO Filip Bech-Larsen, and Head of Developer Relations Emma Burstow. Together, they outline recent growth metrics, international initiatives, and shifting developer dynamics across the ecosystem.&#xA;&#xA;The keynote is split into distinct parts. First, Emma and Mats cover community milestones, international office expansion, and business achievements. Following their segment, Filip steps into a solo keynote presentation focusing on core technical updates, massive platform architecture updates, and major product announcements.&#xA;&#xA;WHO THIS VIDEO IS FOR&#xA;This video is essential viewing for Umbraco developers, solutions architects, agency partners, open-source contributors, and technology leaders. Staying aligned with the platform&#x2019;s core engineering choices ensures your teams can plan upgrades accurately, adopt native AI capabilities securely, and design future-proof, composable architectures.&#xA;&#xA;TIMESTAMPS&#xA;Part 1: Community &amp; Business Milestones (Mats &amp; Emma)&#xA;00:00 - Welcome to Codegarden 2026 &amp; Opening Remarks&#xA;&#xA;01:00 - Speaker Introductions &amp; Record-Breaking Attendance Figures&#xA;&#xA;02:02 - The Infamous Pre-Conference Social Bike Ride Recap&#xA;&#xA;04:40 - Global Footprint: Meetups, Festivals, and the New Melbourne Office&#xA;&#xA;07:20 - AI Hackathons &amp; &quot;Vibe Coding&quot; Innovation Era&#xA;&#xA;15:08 - Guest Segment: Top Hackathon Packages Showcase with Lottie Pitcher&#xA;&#xA;19:08 - Maturing the Marketplace: Platform Strategy, Search, and Vendor Trust&#xA;&#xA;26:23 - Breakout Sessions &amp; Community Roadmap Overview&#xA;&#xA;29:55 - Community Teams &amp; Feedback-Driven Development&#xA;&#xA;32:28 - 2026 Most Valuable People (MVP) Awards Ceremony&#xA;&#xA;Part 2: Product Keynote &amp; Technical Announcements (Filip)&#xA;39:35 - Part 2 Intro: Balancing Developer Love with Business Trust&#xA;&#xA;42:05 - Enterprise Security: ISO 27001 Certification &amp; Cloud 100% SLA Policies&#xA;&#xA;43:25 - CMS Core: Umbraco 17 LTS Overview &amp; Umbraco 13 EOL Timeline&#xA;&#xA;45:16 - Architectural Shifts: Entity Framework (EF Core) &amp; Search Abstraction 1.0&#xA;&#xA;46:50 - Content Modeling: Introducing Native &quot;Elements&quot; &amp; Feature Demo&#xA;&#xA;51:50 - The Umbraco AI Framework: Guiding Principles &amp; Architecture&#xA;&#xA;55:15 - Model Context Protocol (MCP) Server &amp; Hosted Remote MCP for Cloud (Beta)&#xA;&#xA;58:10 - Data Privacy &amp; Testing: Microsoft Extensions AI, Guardrails, and Base Models&#xA;&#xA;1:03:05 - Community Innovation: AI Log Analyzer Feature Demo&#xA;&#xA;1:04:52 - Extending the UI: Semantic AI Search, Voice Mode, and Copilot Upgrades&#xA;&#xA;1:08:10 - Major Announcement: Native Workflow Engine (&quot;Umbraco Automate&quot;)&#xA;&#xA;1:16:32 - Composable Architecture: Umbraco Compose &amp; Injection Upgrades&#xA;&#xA;1:21:56 - Platform Add-ons: Engage Personalization, Forms Analytics, and Commerce Scale&#xA;&#xA;1:25:44 - Cloud Portal Infrastructure: Live Edge Insights &amp; Gamified Recommendations&#xA;&#xA;1:31:26 - Major Announcement: Direct Architecture Load Balancing on Umbraco Cloud&#xA;&#xA;KEY TAKEAWAYS&#xA;A New Class of Content: The debut of &quot;Elements&quot; as a fourth native type introduces clean, non-routable, reusable content models managed via a central Library Section, drastically improving author workflows.&#xA;&#xA;Umbraco Automate: The release of built-in low-code workflow automation allows developers and editors to map triggers (like saving content or uploading media) directly to chain-linked actions, API webhooks, and AI pipelines.&#xA;&#xA;Remote MCP Integration: The Model Context Protocol is shifting to a fully hosted cloud structure this summer, granting secure backend developer contexts to AI tools without complex local token installations.&#xA;&#xA;Direct Cloud Load Balancing: Starting July 1st, Umbraco Cloud will support single-click multi-instance scaling backed by dedicated Redis caching tiers to ensure infrastructure elasticity.&#xA;&#xA;OFFICIAL LINKS &amp; RESOURCES&#xA;Umbraco Product Homepage: www.umbraco.com&#xA;&#xA;Codegarden 2026 keynote highlight Blog Post: https://umbraco.com/blog/umbraco-product-updatecodegarden-keynote-highlights-q2-2026/ &#xA;&#xA;Explore the Umbraco Marketplace: https://marketplace.umbraco.com/ &#xA;&#xA;Community Announcements &amp; Upcoming Events: https://community.umbraco.com/&#xA;&#xA;Codegarden website: https://codegarden.umbraco.com/ &#xA;&#xA;Read the Umbraco Code of Conduct: [Insert Link]]]></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[Umbraco Head of Business Development, Arnold Visser, discusses the operational evolution of managing large client portfolios. While digital agencies have traditionally excelled at building individual Umbraco projects, long-term success requires a shift toward managing, supporting, and scaling those assets as business-critical platforms.&#xA;&#xA;This presentation details how Umbraco Cloud and the Umbraco Enterprise offering are changing to support agencies beyond the initial launch phase. By introducing deeper runtime diagnostics, isolated dedicated tiers at lower price points, and flexible licensing options, the ecosystem aims to minimize the hours development teams spend on infrastructure maintenance and deployment coordination.&#xA;&#xA;This video is for digital agency executives, account managers, technical architects, and project managers handling multiple live Umbraco environments. It provides a strategic look at moving away from reactive server management toward a mature, portfolio-wide operational framework that protects client uptime and uncovers ongoing growth opportunities.&#xA;&#xA;What You Will Learn:&#xA;&#xA;- The operational inflection points that occur when an agency scales from 5 to more than 50 active projects.&#xA;&#xA;- Core updates to Umbraco Cloud, including Load Balancing, 90 days of edge traffic insights, custom branded maintenance pages, and ISO 27001 compliance.&#xA;&#xA;- Commercial adjustments to the platform, such as lower-cost entry tiers for dedicated resources and the introduction of an agency-wide Umbraco Deploy license.&#xA;&#xA;- The mid-term technical roadmap covering proactive health alerting via webhooks, automated scaling, and customizable maintenance windows.&#xA;&#xA;- How to leverage artifact deployments and container-based infrastructure to execute rolling updates without client site downtime.&#xA;&#xA;Chapters:&#xA;00:00 - Introduction: The Portfolio Gap&#xA;01:42 - The Shift from Building to Operating Platforms&#xA;02:52 - Build vs. Scale vs. Grow Framework&#xA;04:45 - The Tribal Knowledge Trap at 50&#x2B; Projects&#xA;05:45 - The Role of Umbraco Cloud Infrastructure&#xA;06:57 - Umbraco for Enterprise Overview&#xA;08:48 - Solving Common Operational Challenges&#xA;11:01 - Addressing Partner Feedback on Visibility and Costs&#xA;12:38 - Traffic Performance Insights and Runtime Data&#xA;14:04 - Plan Extensions and Custom Maintenance Pages&#xA;17:01 - New Dedicated Scaling Options and Lower Pricing&#xA;19:46 - Umbraco Deploy Agency Licensing&#xA;21:11 - The Unified Umbraco Partner Portal&#xA;23:08 - Operational Roadmap: Alerting, Webhooks, and Metrics&#xA;26:21 - Artifact Deployment, Rolling Updates, and Containers&#xA;&#xA;Links &amp; Resources:&#xA;Umbraco Cloud product page: https://umbraco.com/products/umbraco-cloud/&#xA;&#xA;Umbraco for Enterprise Solutions: https://umbraco.com/products/umbraco-for-enterprise/&#xA;&#xA;Umbraco Product Update q2, 2026: https://umbraco.com/blog/umbraco-product-updatecodegarden-keynote-highlights-q2-2026/ &#xA;&#xA;Codegarden Sessions &amp; Announcements: https://codegarden.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[Umbraco Head of CMS, Andy Butland, shares a comprehensive update on the CMS platform ecosystem. This session highlights the post-launch reception of the Umbraco 17 LTS release and provides a technical overview of what to expect in the Umbraco 18 launch.&#xA;&#xA;The presentation details how the development team balances new feature work with core platform performance. Key focus areas include back-office rendering optimizations, advanced caching strategies, and foundational upgrades designed to streamline both the developer and content editor experience.&#xA;&#xA;This video is for Umbraco developers, architects, and content managers who want to understand the platform&#x27;s current trajectory. It offers practical technical insights into optimization configurations like Production Runtime Mode and maps out structural shifts for future major releases.&#xA;&#xA;What You Will Learn&#xA;&#xA;- The core capabilities of reusable content elements and type-safe schemas in Umbraco 18.&#xA;&#xA;- How recent performance tuning reduced backend requests by 40% and cut high-latency load times.&#xA;&#xA;- Best practices for configuring Production Runtime Mode and smart Output Caching.&#xA;&#xA;- Ongoing architectural migrations, including the transition to EF Core and Examine search updates.&#xA;&#xA;- Future roadmap goals for variant media, block personalization, and multi-editor collaboration safety.&#xA;&#xA;Chapters&#xA;00:00 - Introduction &amp; Umbraco 18 Overview&#xA;00:26 - Reusable Content Elements in v18&#xA;02:01 - Delivery API &amp; Type-Safe Schemas&#xA;02:44 - Upgrading to v18 &amp; OpenAPI Changes&#xA;04:52 - Umbraco 17 LTS Updates &amp; Adoption&#xA;05:45 - Back Office Request &amp; Loading Performance&#xA;09:14 - Server Operations &amp; Cache Optimizations&#xA;12:50 - Production Runtime Mode Best Practices&#xA;14:28 - Smart Output Caching &amp; Customization&#xA;17:38 - Lightweight External Members for High Concurrency&#xA;20:47 - Quality of Life Wins for Editors &amp; Developers&#xA;27:08 - AI-Assisted Coding &amp; Code Quality Management&#xA;34:09 - Roadmap: Elements Phase 2 &amp; Library Upgrades&#xA;35:20 - Technical Shift: Migration to EF Core&#xA;38:15 - Future Features: Variant Media &amp; Collaboration&#xA;&#xA;Links &amp; Resources&#xA;&#xA;Umbraco CMS: https://umbraco.com/products/umbraco-cms/&#xA;&#xA;Umbraco Product Update Q2: https://umbraco.com/blog/umbraco-product-updatecodegarden-keynote-highlights-q2-2026/&#xA;&#xA;Umbraco CMS documentation: https://docs.umbraco.com/umbraco-cms &#xA;&#xA;Examine Search Abstraction Package: [Insert Link]&#xA;&#xA;Umbraco Documentation &amp; Latest Releases: [Insert Link]]]></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://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://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://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://umbuntu.uk/blog/codegarden-2026-ubuntu/</guid>
                    <title>Codegarden 2026: Ubuntu</title>
                    <link>https://umbuntu.uk/blog/codegarden-2026-ubuntu/</link>
                    <description><![CDATA[&quot;I am because we are&quot;]]></description>
                    <pubDate>Mon, 22 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</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[What I learned building an AI-assisted pipeline that maps existing sites into reusable Umbraco components.]]></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[Clone and try our four-hour Codegarden workshop on extending Umbraco&#x27;s extensions: an escape room of coding quests across Engage, Workflow and Deploy.]]></description>
                    <pubDate>Mon, 22 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.linkedin.com/pulse/most-interesting-thing-codegarden-wasnt-feature-adam-shallcross-cmxwe/</guid>
                    <title>The most interesting thing at CodeGarden wasn</title>
                    <link>https://www.linkedin.com/pulse/most-interesting-thing-codegarden-wasnt-feature-adam-shallcross-cmxwe/</link>
                    <description><![CDATA[There were plenty of shiny things to look at this year. New content types, a workflow engine, hosted servers you can spin up in minutes.]]></description>
                    <pubDate>Mon, 22 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</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/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://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://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.shoutdigital.com/insights/codegarden-2026-and-the-next-chapter-for-umbraco/</guid>
                    <title>Codegarden 2026 and the next chapter for Umbraco | Shout Digital</title>
                    <link>https://www.shoutdigital.com/insights/codegarden-2026-and-the-next-chapter-for-umbraco/</link>
                    <description><![CDATA[AI, automation, community - Umbraco MVP Ian Grieve talks about his key takeaways from Copenhagen.]]></description>
                    <pubDate>Fri, 19 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</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.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[My first year as an Umbraco MVP: receiving the award at Codegarden 2026 in Copenhagen, the MVP Summit, the sessions, the people, and the moments between.]]></description>
                    <pubDate>Thu, 18 Jun 2026 11:30:00 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://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://frytom.org/2026/06/13/tilbake-fra-kobenhavn-og-umbraco-codegarden-2026-%F0%9F%87%A9%F0%9F%87%B0/</guid>
                    <title>Tilbake fra K&#xF8;benhavn og Umbraco Codegarden 2026! &#x1F1E9;&#x1F1F0;</title>
                    <link>https://frytom.org/2026/06/13/tilbake-fra-kobenhavn-og-umbraco-codegarden-2026-%F0%9F%87%A9%F0%9F%87%B0/</link>
                    <description><![CDATA[Noen dager fylt med faglig p&#xE5;fyll, gode samtaler og sterke relasjoner &#x2014; det er alltid noe eget med Codegarden. Umbraco-communityet er ikke en kult, men&amp;#8230; det er kanskje det n&#xE6;rmeste vi kommer &#x2026;]]></description>
                    <pubDate>Thu, 18 Jun 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.linkedin.com/pulse/my-first-umbraco-codegarden-more-than-stickers-t-shirts-dave-jonker-tew6e/?trackingId=QknJFmSATw6wxaZj0VosrA%3D%3D</guid>
                    <title>My First Umbraco Codegarden: More Than Stickers and T-Shirts</title>
                    <link>https://www.linkedin.com/pulse/my-first-umbraco-codegarden-more-than-stickers-t-shirts-dave-jonker-tew6e/?trackingId=QknJFmSATw6wxaZj0VosrA%3D%3D</link>
                    <description><![CDATA[After my blog was recently featured on umb.fyi &#x2014; thanks to Matt Brailsford for that &#x2014; I felt like I also owed the community a proper write-up about my very first Codegarden experience.]]></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://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://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://medium.com/@ravimotha/codegarden-26-a-review-aa35c60e3b08?source=rss-8e76be83b03f------2</guid>
                    <title>Codegarden 26 : a review</title>
                    <link>https://medium.com/@ravimotha/codegarden-26-a-review-aa35c60e3b08?source=rss-8e76be83b03f------2</link>
                    <description><![CDATA[]]></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[A summary of my Codegarden 2026 highlights.]]></description>
                    <pubDate>Wed, 17 Jun 2026 14:26:59 Z</pubDate>
                        <category>community</category>
                        <category>blog</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://www.blendinteractive.com/thoughts/codegarden-2026/</guid>
                    <title>Codegarden 2026 Road Report: Umbraco&#x2019;s Bet on AI and Reusable Content | Blend Interactive</title>
                    <link>https://www.blendinteractive.com/thoughts/codegarden-2026/</link>
                    <description><![CDATA[A road report from Codegarden 2026 &amp;mdash; Umbraco]]></description>
                    <pubDate>Wed, 17 Jun 2026 00: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/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://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://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. Continue reading]]></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://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://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://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://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://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://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[Justin reflects on an unforgettable week at Codegarden 2026 in Copenhagen, where he was recognised as an Umbraco MVP, invited on stage during the keynote to demo his AI Log Analyser package, and won the AI Package Award.]]></description>
                    <pubDate>Sun, 14 Jun 2026 23:00:00 Z</pubDate>
                        <category>community</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.dynamicdave.nl/blog/my-first-umbraco-codegarden/</guid>
                    <title>My First Umbraco Codegarden: More Than Stickers and T-Shirts</title>
                    <link>https://www.dynamicdave.nl/blog/my-first-umbraco-codegarden/</link>
                    <description><![CDATA[After my blog was recently featured on umb.fyi &#x2014; thanks to Matt Brailsford for that &#x2014; I felt like I also owed the community a proper write-up about my very first Codegarden experience.Because honestly, after finally attending for the first time, I completely understand why people keep talking about it long after the event is over.I&#x2019;ve been building with Umbraco since version 4&#x2014;that takes me back to 2012 or maybe 2013. After all those years, I finally made the pilgrimage: my first Codegarden. And wow, I get it now. I see why people talk about this thing like it&#x2019;s some annual family reunion you can&#x2019;t miss, not just a conference. All the stories you hear&#x2014;about the talks, the people, those late nights that blur into early mornings&#x2014;they&#x27;re all real. Still, the heart of it isn&#x2019;t just scavenging for stickers or filling your suitcase with t-shirts. It&#x2019;s something deeper.What really struck me&#x2014;and it hit pretty much as soon as I walked through the doors&#x2014;is that sense of belonging. Suddenly you realize you&#x2019;re a piece of something much bigger than just a CMS, a project, or a logo. You&#x2019;re dropped right into the Umbraco community, and it&#x2019;s almost impossible not to get swept up in that feeling.]]></description>
                    <pubDate>Fri, 12 Jun 2026 22:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</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>Fri, 12 Jun 2026 02:29:10 Z</pubDate>
                        <category>community</category>
                        <category>youtube</category>
                </item>
                <item>
                    <guid>https://www.wearediagram.com/blog/diagram-wins-2026-umbraco-award-best-enterprise-solution</guid>
                    <title>Diagram and NATP Win Best Enterprise Solution at the 2026 Umbraco Awards</title>
                    <link>https://www.wearediagram.com/blog/diagram-wins-2026-umbraco-award-best-enterprise-solution</link>
                    <description><![CDATA[We&#x2019;re excited to share that the National Association of Tax Professionals (NATP) website, designed and developed by Diagram, has been named Best Enterprise Solution at the &#xA; 2026 Umbraco Awards.&amp;nbsp;]]></description>
                    <pubDate>Thu, 11 Jun 2026 20:46:10 Z</pubDate>
                        <category>community</category>
                        <category>blog</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://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/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/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/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://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/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://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://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://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://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://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/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://www.dynamicdave.nl/blog/nominated-for-an-umbraco-solution-award/</guid>
                    <title>Nominated for an Umbraco Solution Award</title>
                    <link>https://www.dynamicdave.nl/blog/nominated-for-an-umbraco-solution-award/</link>
                    <description><![CDATA[Feeling incredibly proud to have been nominated for an Umbraco Solution Award this year!]]></description>
                    <pubDate>Tue, 09 Jun 2026 22:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</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[I recently spent some time looking closer at the new HybridCache implementation in Umbraco to prepare for my presentation at CodeGarden 2026, and the short version is this: it changes more than just the cache layer.&#xA;&#xA;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.&#xA;With HybridCache, that mental model changes. The cache is still there, but not everything necessarily lives in memory all the time.&#xA;The big win is scalability&#xA;The reason for this change is very easy to understand when looking at large Umbraco installations.&#xA;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.&#xA;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.&#xA;The cost did not disappear&#xA;The interesting part, at least for me as a developer, is that the cost did not vanish. It moved.&#xA;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.&#xA;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.&#xA;&#xA;Use the right tool for the job&#xA;One of my main takeaways is that we should stop treating the published content cache as the answer to everything.&#xA;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.&#xA;So the practical message is simple: measure, observe, and choose the right approach based on what the page actually needs to do.&#xA;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.&#xA;Download the slides&#xA;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.&#xA;Download the slides]]></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://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://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.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.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.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.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.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.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.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.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.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.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://www.jeroenbreuer.nl/blog/umbraco-openid-connect-example-with-lightweight-external-members/</guid>
                    <title>Umbraco OpenID Connect example with lightweight external members</title>
                    <link>https://www.jeroenbreuer.nl/blog/umbraco-openid-connect-example-with-lightweight-external-members/</link>
                    <description><![CDATA[The Umbraco OpenID Connect example has been updated to Umbraco 17.4.2 with support for lightweight external members . This stores members from an external provider as a minimal record instead of a full content entity.]]></description>
                    <pubDate>Tue, 02 Jun 2026 17:37:28 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.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.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/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://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://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://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.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://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.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.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/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://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://www.dynamicdave.nl/blog/why-2026-is-finally-the-year-i-m-going-to-codegarden/</guid>
                    <title>Why 2026 Is Finally the Year I&#x27;m Going to Codegarden</title>
                    <link>https://www.dynamicdave.nl/blog/why-2026-is-finally-the-year-i-m-going-to-codegarden/</link>
                    <description><![CDATA[Some things just hang around on your bucket list forever. You tell yourself, &#x201C;maybe next year,&#x201D; but you never actually get around to it. For me, that&#x2019;s always been Codegarden.I&#x2019;ve been working with Umbraco since version 4&#x2014;so, we&#x2019;re talking 2012 or 2013. That&#x2019;s over a decade of projects, bug fixes, and late-night &#x201C;why is this still broken?&#x201D; moments. But I&#x2019;ve never packed a bag and headed to Copenhagen for the biggest Umbraco event on the planet. Not once. Until now.]]></description>
                    <pubDate>Mon, 01 Jun 2026 22:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</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://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://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://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://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://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;- Skrift: https://skrift.io/issues/?utm_source=umbfyi&amp;utm_medium=web#127&#xA;- https://umbraad.com/&#xA;- Bootstrap 3 bye bye from Forms: https://github.com/umbraco/Announcements/issues/35&#xA;- AI Agents everywhere&#x2026;&#xA;- https://codeshare.co.uk/blog/designing-an-ai-agent-skill-for-adding-a-page-type-to-umbraco/&#xA;- Adam&#x2019;s demo? https://marketplace.umbraco.com/package/agentrun.umbraco&#xA;- AI search: https://examinex.online/2026/04/16/ai-semantic-ranking-for-azure-search&#xA;- Logs in Kudu: https://skttl.dev/blog/browsing-umbraco-logs-in-kudu/&#xA;- Personalisation: https://kjac.dev/posts/personalisation-groups-as-segments/&#xA;- Search future: https://www.youtube.com/watch?v=wwQBvBDGhPE&#xA;- Events: https://umbraco.com/events/]]></description>
                    <pubDate>Sat, 30 May 2026 00:06:57 Z</pubDate>
                        <category>community</category>
                        <category>youtube</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-419ff102baa5------2</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-419ff102baa5------2</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 29 May 2026 18:47:06 Z</pubDate>
                        <category>community</category>
                        <category>blog</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://medium.com/@nomansiddiquins1/integrating-amazon-s3-media-storage-hashicorp-vault-secrets-into-umbraco-v17-c2a36410b0a2?source=rss-419ff102baa5------2</guid>
                    <title>Integrating Amazon S3 Media Storage &amp; HashiCorp Vault Secrets into Umbraco v17</title>
                    <link>https://medium.com/@nomansiddiquins1/integrating-amazon-s3-media-storage-hashicorp-vault-secrets-into-umbraco-v17-c2a36410b0a2?source=rss-419ff102baa5------2</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Fri, 29 May 2026 13:45:02 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.jeroenbreuer.nl/blog/umbraco-mvp-2026/</guid>
                    <title>Umbraco MVP 2026!</title>
                    <link>https://www.jeroenbreuer.nl/blog/umbraco-mvp-2026/</link>
                    <description><![CDATA[Woohoo! Proud to receive my seventh Umbraco MVP award in 2026, marking another year of sharing, building, and community-driven progress.]]></description>
                    <pubDate>Fri, 29 May 2026 11:41:10 Z</pubDate>
                        <category>community</category>
                        <category>blog</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://medium.com/@ravimotha/codegarden26-a-guide-1ad134dad6b1?source=rss-8e76be83b03f------2</guid>
                    <title>CodeGarden26 : a guide</title>
                    <link>https://medium.com/@ravimotha/codegarden26-a-guide-1ad134dad6b1?source=rss-8e76be83b03f------2</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Thu, 28 May 2026 16:53:23 Z</pubDate>
                        <category>community</category>
                        <category>blog</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.nevitech.co.uk/blog/noisy-imagesharp-logs-in-umbraco/</guid>
                    <title>Noisy ImageSharp Logs in Umbraco</title>
                    <link>https://www.nevitech.co.uk/blog/noisy-imagesharp-logs-in-umbraco/</link>
                    <description><![CDATA[ImageSharp logs every image request at INFO level, quietly filling your Umbraco logs until the backoffice viewer hits its 100 MB limit and refuses to open them. Here&#x27;s the one line Serilog fix, plus why a CDN helps.]]></description>
                    <pubDate>Wed, 27 May 2026 23:00:00 Z</pubDate>
                        <category>community</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[I wanted to build an Azure Search provider for Umbraco and let Cursor do the heavy lifting. This is what that looked like from the first prompt to the final commit.]]></description>
                    <pubDate>Wed, 27 May 2026 09:21:27 Z</pubDate>
                        <category>community</category>
                        <category>blog</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://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://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://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://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://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://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[A new userscript that brings a proper Serilog log viewer into the Kudu interface: file picker, expression search, saved queries, and a momentum graph, all with no build step required.]]></description>
                    <pubDate>Tue, 26 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://github.com/skybrud/Skybrud.Umbraco.Redirects/releases/tag/v17.0.5</guid>
                    <title>Skybrud.Umbraco.Redirects 17.0.5</title>
                    <link>https://github.com/skybrud/Skybrud.Umbraco.Redirects/releases/tag/v17.0.5</link>
                    <description><![CDATA[Award winning redirects manager for Umbraco.]]></description>
                    <pubDate>Mon, 25 May 2026 20:08:42 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://anju-dev-notes.hashnode.dev/azure-key-vault-configuration-using-rbac-in-azure-app-service</guid>
                    <title>Azure Key Vault Configuration Using RBAC in Azure App Service</title>
                    <link>https://anju-dev-notes.hashnode.dev/azure-key-vault-configuration-using-rbac-in-azure-app-service</link>
                    <description><![CDATA[Managing secrets securely is one of the most important aspects of modern cloud applications. Instead of storing sensitive values like connection strings, API keys, or passwords directly inside applica]]></description>
                    <pubDate>Mon, 25 May 2026 11:51:18 Z</pubDate>
                        <category>community</category>
                        <category>blog</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://skttl.dev/blog/smarter-redirects-when-editors-trash-content-in-umbraco/</guid>
                    <title>Smarter redirects when editors trash content in Umbraco</title>
                    <link>https://skttl.dev/blog/smarter-redirects-when-editors-trash-content-in-umbraco/</link>
                    <description><![CDATA[A new Umbraco package that replaces the default trash action. It captures the URLs of doomed content first, then suggests redirect targets using Umbraco.AI.Search, with a non-AI fallback for bulk trashes.]]></description>
                    <pubDate>Thu, 21 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</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://github.com/limbo-works/Limbo.Umbraco.FilterList/releases/tag/v13.0.0-alpha004</guid>
                    <title>Limbo.Umbraco.FilterList 13.0.0-alpha004</title>
                    <link>https://github.com/limbo-works/Limbo.Umbraco.FilterList/releases/tag/v13.0.0-alpha004</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Tue, 19 May 2026 10:55:08 Z</pubDate>
                        <category>community</category>
                        <category>package</category>
                </item>
                <item>
                    <guid>https://github.com/limbo-works/Limbo.Umbraco.FilterList/releases/tag/v13.0.0-alpha003</guid>
                    <title>Limbo.Umbraco.FilterList 13.0.0-alpha003</title>
                    <link>https://github.com/limbo-works/Limbo.Umbraco.FilterList/releases/tag/v13.0.0-alpha003</link>
                    <description><![CDATA[]]></description>
                    <pubDate>Tue, 19 May 2026 10:33:05 Z</pubDate>
                        <category>community</category>
                        <category>package</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.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://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://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[What&#x27;s new in version 17.0.0 of the Image Hotspot property editor: Umbraco 17 support, block editor fixes, localization in 29 languages, and a new versioning scheme.]]></description>
                    <pubDate>Mon, 18 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</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.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/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/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[The rest of this post was written with Claude AI. Here&#x27;s the simple problem I seem to get myself into often: &#xA;&#xA;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. dotnet run just fails &#x1F631; But I need to get into the backoffice to generate the models; difficult when Umbraco doesn&#x27;t even run.&#xA;&#xA;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:&#xA;&#xA;&#xA;&#xA;&#xA;Dropped a set of strongly-typed views (home.cshtml, Author.cshtml, etc.) into a fresh Umbraco site and ran straight into the chicken-and-egg problem every Umbraco developer eventually meets:&#xA;&#xA;&#xA;The views reference Umbraco.Cms.Web.Common.PublishedModels.Home (and friends).&#xA;Those classes are generated by ModelsBuilder from document types that live in the database.&#xA;The database is empty until the site has run at least once.&#xA;The site won&#x27;t build because the views don&#x27;t compile, so it can&#x27;t run.&#xA;&#xA;&#xA;Here&#x27;s the little dance to break the cycle.&#xA;&#xA;&#xA;  &#xA;  &#xA;  1. Turn off Razor compile-on-build&#xA;&#xA;&#xA;In the .csproj:&#xA;&#xA;&#xA;&#xA;&lt;RazorCompileOnBuild&gt;false&lt;/RazorCompileOnBuild&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;The build now skips the views entirely instead of failing on the missing PublishedModels.* types.&#xA;&#xA;&#xA;  &#xA;  &#xA;  2. Switch ModelsBuilder to manual mode&#xA;&#xA;&#xA;In appsettings.json:&#xA;&#xA;&#xA;&#xA;&quot;ModelsBuilder&quot;: {&#xA;  &quot;ModelsMode&quot;: &quot;SourceCodeManual&quot;&#xA;}&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;SourceCodeManual is the only mode that gives you a Generate models button in the backoffice. The other three:&#xA;&#xA;&#xA;&#xA;&#xA;Mode&#xA;Files?&#xA;Trigger&#xA;&#xA;&#xA;&#xA;&#xA;Nothing&#xA;none&#xA;&#x2014;&#xA;&#xA;&#xA;InMemoryAuto&#xA;in-memory only&#xA;auto&#xA;&#xA;&#xA;SourceCodeManual&#xA;~/umbraco/models/*.cs&#xA;button&#xA;&#xA;&#xA;SourceCodeAuto&#xA;~/umbraco/models/*.cs&#xA;auto on schema change&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;  &#xA;  &#xA;  3. Start the site&#xA;&#xA;&#xA;dotnet run. 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.&#xA;&#xA;&#xA;  &#xA;  &#xA;  4. Click the button&#xA;&#xA;&#xA;Backoffice &#x2192; Settings &#x2192; Models Builder &#x2192; Generate models.&#xA;&#xA;.cs files appear in umbraco/models/ &#x2014; one per document type. These are the classes the views were waiting on.&#xA;&#xA;&#xA;  &#xA;  &#xA;  5. Stop the site&#xA;&#xA;&#xA;Ctrl&#x2B;C.&#xA;&#xA;&#xA;  &#xA;  &#xA;  6. Re-enable Razor compile-on-build&#xA;&#xA;&#xA;Remove the line we added in step 1:&#xA;&#xA;&#xA;&#xA;&lt;!-- &lt;RazorCompileOnBuild&gt;false&lt;/RazorCompileOnBuild&gt;  &#x2190; delete this --&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;  &#xA;  &#xA;  7. Start the site again&#xA;&#xA;&#xA;dotnet run. Build picks up the generated models, compiles the views against them, the home page renders.&#xA;&#xA;&#xA;  &#xA;  &#xA;  Why the dance is needed&#xA;&#xA;&#xA;RazorCompileOnBuild=false 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:&#xA;&#xA;&#xA;&#xA;&quot;No physical template file was found for template home&quot;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;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.&#xA;&#xA;Once the models are committed to source control, none of this matters &#x2014; the next clone builds clean from the start.]]></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/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://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://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>New package: Advanced User Group Permissions for Umbraco</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 where projects often involve multiple editors, multiple user groups, and more complex content structures. That experience shaped what I value: features that give teams enough control without making day-to-day editing harder.&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 I do think it becomes too limited once projects grow in complexity. In my opinion, this is an area where Umbraco could &#x2014; and should &#x2014; offer more flexibility.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;For now, this package is my attempt to solve that problem in a practical way. Advanced Permissions for Umbraco is designed for situations where the built-in permission model does not give you enough 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 the built-in permission model starts to feel too restrictive&#x2014;multiple teams with overlapping responsibilities, permissions that need to vary significantly across your content tree, or content structures that don&#x27;t fit neatly into the standard model.&lt;/p&gt;&#xA;&#xA;&lt;p&gt;For simple scenarios, Umbraco&#x27;s built-in permissions may be enough. But when you need more control over how permissions are inherited, combined, allowed, or denied, Advanced Permissions gives you a more flexible model to work with.&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; today!&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://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://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://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://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 wizard CLIs that pull a fresh database and media folder from Umbraco Cloud straight into your local dev project - spinoffs from the archiver, useful on their own.]]></description>
                    <pubDate>Mon, 04 May 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.dynamicdave.nl/blog/accessibility-on-the-web/</guid>
                    <title>Accessibility on the Web: Why It&#x27;s Mission-Critical, Not Just Another Task to Tick Off</title>
                    <link>https://www.dynamicdave.nl/blog/accessibility-on-the-web/</link>
                    <description><![CDATA[Let&#x2019;s be honest&#x2014;most teams know that accessibility matters. Everybody nods along when it comes up. But as deadlines creep closer and pressure ramps up, accessibility quietly slides out of focus, landing in the &#x201C;we&#x2019;ll get to it later&#x201D; pile. And we all know how rare it is to dig into that pile once the release goes live.Ignoring accessibility during development is a costly shortcut. You can&#x2019;t tack it on at the last minute and hope for a smooth outcome. It&#x2019;s more like the foundation&#x2014;get it wrong and everything on top is unstable. Accessibility shapes how you organize your content, how you design and build components, and how users actually use your site. Put it off, and you&#x2019;re not just risking some awkward code rewrites later. You&#x2019;re almost guaranteed to exclude real people&#x2014;people who just want to use your site like anyone else.If you&#x2019;re working with Umbraco 17, you&#x2019;ve got a solid foundation for accessibility. The platform itself doesn&#x2019;t hold you back. But it&#x2019;s your choices&#x2014;the way you structure content and the standards you enforce&#x2014;that make or break the user experience.]]></description>
                    <pubDate>Sun, 03 May 2026 22: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[I&#x27;m working with a migration of the website for my Umbraco-package Newsletter Studio, from Umbraco 8 to Umbraco 17.&#xA;I use Umbraco Members to allow customers to login and manage their licenses, update information and download receipts.&#xA;New password = Member logged out&#xA;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.&#xA;The Member was throw out both:&#xA;&#xA;When they change password them selfs&#xA;When the password was changed in from the backoffice&#xA;&#xA;I searched around for this, and it turns out that this is security feature.&#xA;Umbraco has introduce settings around concurrent logins both for Users and Members, in appsettings.json one can configure these&#xA;&amp;#xD;&#xA;&quot;Umbraco&quot;: {&#xA;    &quot;CMS&quot;: {      &#xA;        &quot;Security&quot;: {&#xA;            &quot;AllowConcurrentLogins&quot;: false&#xA;            &quot;MemberAllowConcurrentLogins&quot;: false&#xA;        }&#xA;    }&#xA;}&amp;#xD;&#xA;&amp;#xD;&#xA;&amp;#xD;&#xA;&#xA;According to the documentation, MemberAllowConcurrentLogins will fallback to the value of AllowConcurrentLogins, which is set to false by default.&#xA;What happened?&#xA;When the user changed the password, it looked like a new login, since this was not allowed the user was thrown out.&#xA;There is two ways around this, one could refresh the users login cookie by calling _memberSignInManager.SignInAsync() after the password change.&#xA;&amp;#xD;&#xA;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, &quot;&quot;);&amp;#xD;&#xA;&amp;#xD;&#xA;&amp;#xD;&#xA;&#xA;&#xA0;Or, one could set AllowConcurrentLogins to true.]]></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://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://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://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://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://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[When a client upgrade meant retiring an old Umbraco Cloud project, I wanted a complete local archive before pulling the plug. So I built a wizard CLI to do it.]]></description>
                    <pubDate>Wed, 29 Apr 2026 00:00:00 Z</pubDate>
                        <category>community</category>
                        <category>blog</category>
                </item>
                <item>
                    <guid>https://www.nevitech.co.uk/blog/fixing-the-maxviewitems-limit-in-umbraco-cloud-kudu/</guid>
                    <title>Fixing the &quot;maxViewItems&quot; Limit in Umbraco Cloud Kudu</title>
                    <link>https://www.nevitech.co.uk/blog/fixing-the-maxviewitems-limit-in-umbraco-cloud-kudu/</link>
                    <description><![CDATA[Hitting the &quot;maxViewItems is set to 299&quot; message in Umbraco Cloud&#x27;s Kudu console? Here&#x27;s the one-line fix in DevTools which I always forget!]]></description>
                    <pubDate>Tue, 28 Apr 2026 23: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.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/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.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://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://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://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;- AI Community Team &amp; Advisory Board: https://umbraco.com/blog/announcing-the-umbraco-in-ai-community-team-the-ai-in-umbraco-advisory-board/&#xA;- AI in Umbraco&#xA;  - Docs: https://docs.umbraco.com/ai-in-umbraco&#xA;  - AI Search&#xA;  - File Uploads Umbraco.AI&#xA;  - Other?&#xA;  - https://mattbrailsford.dev/&#xA;- Umbraco Awards nominees announced: https://umbraco.com/blog/announcing-the-2026-umbraco-awards-nominees/&#xA;- New Skrift issue: https://skrift.io/issues/&#xA;- uProfile April: https://umbraco.com/blog/uprofile-april-2026-will-steed&#xA;- Events and new, reimagined UK Conference: https://www.linkedin.com/posts/umbukfdn_umbraco-uk-conference-teaser-activity-7447919930936590336-UgQs/]]></description>
                    <pubDate>Fri, 24 Apr 2026 23:21:58 Z</pubDate>
                        <category>community</category>
                        <category>youtube</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://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://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. Continue reading]]></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://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://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://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://medium.com/@girish.sasikumar.kl33/complete-guide-to-upgrading-umbraco-from-version-13-to-17-f02f0e40237d?source=rss-c42909184141------2</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-c42909184141------2</link>
                    <description><![CDATA[]]></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/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/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/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://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://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://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://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://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://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[Skip manual registration and let your project automatically discover which blocks should have preview enabled based on existing views.]]></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/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://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://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/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://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://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://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://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://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.dynamicdave.nl/blog/from-zero-to-production/</guid>
                    <title>From Zero to Production: A no-nonsense Umbraco 17 setup (that won&#x27;t age poorly)</title>
                    <link>https://www.dynamicdave.nl/blog/from-zero-to-production/</link>
                    <description><![CDATA[Most Umbraco Setups Don&#x2019;t Fail Immediately&#x2014;They Fail LaterEvery new Umbraco project usually starts the same&#x2014;fresh solution, everyone energized and maybe even a nice architecture diagram. For a couple weeks, life&#x2019;s good. Everything moves quick, flows logically, and things feel buttoned-up.Then the real world shows up.Configuration starts drifting. What worked on your laptop doesn&#x2019;t quite click on staging. Naming conventions get creative&#x2014;sometimes even a little poetic&#x2014;with no one quite sure which approach is the right one anymore. Deployment turns into a one-person magic show, full of rituals and half-remembered steps. Suddenly, what felt solid starts to make you nervous whenever someone asks for a change.Let&#x2019;s be honest: Umbraco projects rarely blow up in the first week. Most problems show up months later, buried in the details.What does it take to build a setup that actually survives? Not just in someone&#x2019;s imagination, but in production, with real clients pounding on it, editors making changes, deadlines looming. We&#x2019;re talking about a setup that stays reliable and feels right six months&#x2014;or even a year&#x2014;down the road.Let&#x2019;s dive into a straightforward, practical approach for an Umbraco 17 project that won&#x2019;t fall apart just when you need it most.]]></description>
                    <pubDate>Sun, 12 Apr 2026 22:00:00 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://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://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://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://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/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://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://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://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://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://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://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.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.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://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://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/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://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/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://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/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/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/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://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://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://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://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://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://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://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://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://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/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/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://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://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;&#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;&#xA;&lt;/div&gt;&#xA;&#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://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://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://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://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://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-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://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://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://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://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://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://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://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://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/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://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://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://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://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://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://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://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/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://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/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://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.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://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.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://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/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/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/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://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://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://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://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://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.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://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://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.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://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://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://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/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.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.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.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://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://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://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.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://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.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://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://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://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://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/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://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://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.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>
    </channel>
</rss>