Skip to content

Instantly share code, notes, and snippets.

View AndyButland's full-sized avatar

Andy Butland AndyButland

View GitHub Profile
@AndyButland
AndyButland / ChangeLanguageCultureController.cs
Last active June 17, 2026 06:16
Sample controller that can be used to change an Umbraco language from one ISO code to another (see https://github.com/umbraco/Umbraco-CMS/issues/20674). Use at your own risk and with care (backup database before using).
// ---------------------------------------------------------------------------------------------------
// Change a language's ISO code (culture) and re-align the data that references it by culture string.
//
// Issue: https://github.com/umbraco/Umbraco-CMS/issues/20674
// Version: Written against Umbraco 17.5.
// Access: Gated by a shared secret. Set a long random value in configuration and send the same value
// in the X-Maintenance-Key header; the endpoint returns 401 unless the key is configured AND
// the header matches it:
// "Umbraco": { CMS: { "Maintenance": { "ChangeLanguageCultureKey": "<long-random-secret>" } } }
// Delete this file once the fix has been applied.
@AndyButland
AndyButland / statusline-command.sh
Created April 13, 2026 05:13
Status line for Claude Code
#!/usr/bin/env bash
input=$(cat)
# Parse JSON with grep/sed since jq may not be available
extract() {
echo "$input" | grep -o "\"$1\":[^,}]*" | head -1 | sed 's/^"[^"]*"://; s/^[ ]*//; s/"//g; s/[ ]*$//'
}
cwd=$(extract "current_dir")
model=$(extract "display_name")
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Routing;
namespace Umbraco.Cms.Web.UI.Composers;
public class SoftwarePageUrlsComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
builder.UrlProviders().Insert<SoftwarePageUrlProvider>();
namespace MyProject.Web.Customization;
public static class SoftwarePageUrlHelper
{
public static bool IsSoftwarePage(string contentTypeAlias, string? contentName) =>
contentTypeAlias == "testPage" &&
!string.IsNullOrEmpty(contentName) &&
contentName.EndsWith(" Software");
}
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Strings;
namespace MyProject.Web.Customization;
public class SoftwarePageUrlSegmentProvider : IUrlSegmentProvider
{
private readonly IUrlSegmentProvider _provider;
public SoftwarePageUrlSegmentProvider(IShortStringHelper stringHelper) => _provider = new DefaultUrlSegmentProvider(stringHelper);
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
namespace MyProject.Web.Customization;
public class SoftwarePageContentFinder : IContentFinder
{
private readonly IDocumentUrlService _documentUrlService;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Core.Web;
var commands = new List<ImageUrlGenerationOptions>();
imageUrlGeneratorMock.Verify(x => x.GetImageUrl(Capture.In(commands, cmd => true)));
foreach (ImageUrlGenerationOptions command in commands)
{
System.Diagnostics.Debug.WriteLine(command.Height);
}
imageUrlGeneratorMock
.Setup(x => x.GetImageUrl(It.IsAny<ImageUrlGenerationOptions>()))
.Returns("/test.png");
imageUrlGeneratorMock
.Setup(x => x.GetImageUrl(It.Is<ImageUrlGenerationOptions>(y => y.Height == Height)))
.Returns("/test.png");