Thursday, 13 August 2026

Optimizely XML Resource Builder: A Visual Studio Extension for Language Resource Files

Anyone who has worked on a larger Optimizely solution will know the feeling. You add or update a page type, block type, or shared base class, and then need to keep the language resource XML in sync. It is not difficult work, but it is repetitive, easy to miss, and becomes more painful as the number of content types grows.

This started as a small pet project for my own convenience. I wanted a quick way to generate a starting point for Optimizely language resource files directly from the content type code already in a project. Once it was useful in day-to-day work, I thought it could also benefit the wider Optimizely community if I packaged it properly and made it publicly available.

That is where Optimizely XML Resource Builder came from.

What it does

Optimizely XML Resource Builder is a Visual Studio extension that scans the project you select and generates an Optimizely language resource file from its C# content type definitions.

It reads content type attributes such as ContentType and SiteContentType, then creates the XML entries for the content type name, description, properties, captions, and help text.

The default output is:

Resources\Translations\ContentTypes-en.xml

You can change both the language code and output folder from the extension dialog.

Why I built it

Language resource files are useful for keeping the Optimizely editor UI clean and consistent, especially when you are working across several languages. The challenge is that the information is usually already present in code:

[ContentType(DisplayName = "Article Page")]
public class ArticlePage : SitePageData
{
    [Display(Name = "Heading", Description = "The main page heading")]
    public virtual string Heading { get; set; }
}

Copying those values into XML by hand adds another maintenance step. The extension uses the information already available in the attributes and gives you a generated file to review, commit, and translate.

Key features

  • Project-level command: right-click an Optimizely project in Solution Explorer to generate the resource XML.
  • Flexible content type detection: scan for SiteContentType, ContentType, or any additional attributes you configure.
  • Configurable generation dialog: choose a comma-separated attribute list, language code, excluded property prefixes, and output folder before generating the file.
  • Caption casing control: keep the original display-name case or convert captions to sentence case while preserving uppercase acronyms.
  • Overwrite control: choose whether to replace the existing XML file or safely add only missing entries.
  • Useful XML generated from code: create content type names, descriptions, property captions, and help text from the attributes already defined in C#.
  • Shared base-class support: find properties on custom base classes and add them under icontentdata.
  • Safe updates: add only missing XML entries by default, preserving existing translations and custom values. Enable overwrite only when you want a fresh file.
  • Solution-specific preferences: save settings per solution, rather than using one global set of values across every project.

How to use it

  1. Install the extension.
  2. Open an Optimizely solution in Visual Studio.
  3. In Solution Explorer, right-click the project that contains the content type classes.
  4. Select Build Optimizely XML Resource File.
  5. Set the attribute list, language code, output folder, and any exclusions.
  6. Select OK.

If no matching content types are found, the extension shows a warning and does not create an empty XML file.

Example output

<contenttypes>
  <icontentdata>
    <properties>
      <metadescription>
        <caption>Meta description</caption>
      </metadescription>
    </properties>
  </icontentdata>
  <articlepage>
    <name>Article Page</name>
    <properties>
      <heading>
        <caption>Heading</caption>
        <help>The main page heading</help>
      </heading>
    </properties>
  </articlepage>
</contenttypes>

Compatibility

The extension supports Visual Studio 2022 and later.

Links

I hope it saves other Optimizely developers the same repetitive work it saves me. If you try it, feedback and contributions are very welcome.

August 13, 2026

Tuesday, 3 March 2026

OpenAI-Driven AI Assistant for TinyMCE in Optimizely CMS 12

The Tiny.AI add-on enhances Optimizely CMS 12 by seamlessly integrating OpenAI directly into the TinyMCE editor. It empowers editors to rewrite, improve, summarize, expand, or translate selected content without leaving the CMS. Instead of copying content into external AI tools and risking formatting issues, Tiny.AI processes HTML safely and returns clean, CMS-ready output.

Installation

The command below will install the add-on in your Optimizely project.

dotnet add package A2Z.Optimizely.Tiny.AI

Configuration

Add your OpenAI configuration inside appsettings.json. The model value below is an example and can be updated to a supported model that fits your setup.

{
  "OpenAI": {
    "ApiKey": "YOUR_API_KEY",
    "Model": "gpt-4o-mini"
  }
}

The module automatically registers required services, the API controller, and the TinyMCE plugin.

Service Registration

The package registers the OpenAI service, circuit breaker, and authorization services automatically through an initialization module.

[ModuleDependency(typeof(InitializationModule))]
public class AiInitialization : IConfigurableModule
{
    public void ConfigureContainer(ServiceConfigurationContext context)
    {
        context.Services.AddHttpClient<IOpenAiService, OpenAiService>();
        context.Services.AddSingleton<EditorAuthorizationService>();
        context.Services.AddSingleton<SimpleCircuitBreaker>();
    }
}

Usage

Once installed and configured, editors will see a new AI Assistant button inside the TinyMCE toolbar.

TinyAI Icon

How it works:

  1. Select content inside the TinyMCE editor.
  2. Click the AI Assistant button.

  3. Choose an action (Rewrite, Improve, Summarize, Expand, Translate).

  4. Optionally specify a language.
  5. Apply changes and the HTML is replaced instantly.

The AI processes the selected HTML and returns valid HTML only, preserving links and formatting.

Security

Access to Tiny.AI is restricted to users in the following roles:

  • CmsEditors
  • Administrators

Authorization is validated server-side to ensure only permitted users can invoke AI functionality.

Resilience & Performance

Tiny.AI is built for production environments and includes:

  • Retry logic for transient API failures
  • Exponential backoff for rate limiting (429 responses)
  • Circuit breaker protection after repeated failures
  • Structured logging for monitoring
  • Token usage tracking
  • Estimated cost calculation per request

If multiple consecutive failures occur, the circuit breaker temporarily disables AI calls to protect system stability.

Cost Transparency

Each request returns:

  • Prompt tokens
  • Completion tokens
  • Total tokens
  • Estimated cost

This provides visibility into AI usage and allows teams to monitor spending effectively.

API Endpoint

POST /api/editor/ai/action

Example request:

{
  "action": "rewrite",
  "html": "<p>Some content</p>",
  "language": "en"
}

Example response:

{
  "html": "<p>Rewritten content...</p>",
  "tokens": 512,
  "cost": 0.0003
}

Compatibility

Tiny.AI currently supports Optimizely CMS 12 only. Check the GitHub repository or package page for the latest updates and version support.

Why Tiny.AI?

AI is becoming an essential productivity tool for content teams. Tiny.AI integrates OpenAI directly into Optimizely CMS workflows while maintaining security, HTML integrity, and operational resilience.

It eliminates the need for external tools and keeps the editorial workflow fast, clean, and fully integrated.

You can access the code and documentation for Tiny.AI on its GitHub repository.

March 03, 2026

Thursday, 12 February 2026

Advanced Form Submissions for Optimizely CMS

Advanced Form Submissions is an alternative submissions dashboard for Optimizely CMS 12 built for teams that need better control over Optimizely Forms data. It improves the default submission view with stronger filtering, export tools, bulk actions, and a more practical review experience for editors and administrators.

In larger Optimizely solutions, form data quickly becomes harder to manage across multiple sites, languages, and forms. This add-on gives teams a faster and more flexible way to review submissions without relying on the default interface alone.

Why use Advanced Form Submissions

  • Filter submissions by site, language, and form.
  • Search across submission content and apply date range filters.
  • Export filtered data as CSV, XML, or JSON.
  • Delete submissions more efficiently.
  • Open the original form directly from the dashboard.
  • Preview a submission on the original page with form hydration.

Key features

Personalized dashboard

The dashboard is designed for day-to-day editorial use and supports a more flexible review workflow.

  • Reorder columns to fit your needs.
  • Hide fields that are not useful for your review process.
  • Save settings per user, form, and language.
  • Use paged data loading for better performance on large datasets.

Advanced filtering and search

Submissions can be narrowed down quickly with filters for site, language, and form, plus free-text search and from/to date filtering.

Export and management tools

  • Export filtered submissions as CSV, XML, or JSON.
  • Delete selected or filtered submissions.
  • Jump directly to the related Form Container Block in CMS.

Better data display

  • File upload values are shown as clickable links.
  • Selection fields such as checkboxes, radio buttons, and dropdowns are rendered more clearly during review.

Quick view of an Optimizely form submission in Advanced Form Submissions

View submission on page

The add-on supports form hydration, which lets authorized users open a submitted form directly on the original page with the submitted values prefilled.

  • Open a submission in its original page context.
  • Review how the form looked when it was submitted.
  • Keep the workflow permission-aware and security-aware.

Advanced Form Submissions dashboard in Optimizely CMS

Advanced Form Submissions access from the Optimizely CMS form block

How to access it

The dashboard is available in two ways:

  • From the CMS global menu as Form Submissions.
  • From a Form Container Block through the custom Advanced Form Submissions view.

Installation

Install the package from the Optimizely NuGet feed:

dotnet add package A2Z.Optimizely.AdvancedFormSubmissions

Register the add-on during application startup:

using AdvancedFormSubmissions;

builder.Services.AddAdvancedFormSubmissions();

This registration adds the module, protected resources, CMS integration, and the default authorization policy.

Authorization and security

The add-on uses a dedicated authorization policy: form:submissions.

By default, access is granted to:

  • CmsAdmins
  • WebAdmins
  • Administrators

The same policy protects menu visibility, dashboard access, and form hydration behavior.

Compatibility

As of July 24, 2026, this add-on supports Optimizely CMS 12.

Limitations

Encrypted Optimizely Forms fields are intentionally not supported for dashboard display or hydration.

  • Encrypted values cannot be read through public APIs.
  • Encrypted fields are not hydrated on the front end.
  • Exports may show empty or masked values for encrypted fields.

Links

GitHub repository
README
NuGet package

FAQ

Does this replace Optimizely Forms?
No. It improves how submissions are reviewed and managed after forms are submitted.

Can editors preview submissions on the original page?
Yes. Authorized users can use form hydration to open a submitted form in its original page context.

Does it support encrypted fields?
No. Encrypted fields are intentionally excluded from hydration and display.

February 12, 2026

Wednesday, 24 September 2025

Master Language Switcher for Optimizely CMS

Master Language Switcher is an admin tool for Optimizely CMS 12 and 13 that helps teams change the master language of multilingual content more safely. It is designed for cases where you need to promote an existing language branch or convert the current master language to a new target language without manually working through content item by item.

For multilingual Optimizely solutions, this can save a significant amount of time and reduce the risk of mistakes when working across large content trees.

Why use Master Language Switcher

  • Switch - If the target language branch already exists, it becomes the new master language.
  • Convert - If the target branch does not exist, the current master language is converted and promoted to the target language.
  • Batch processing - Large content trees are processed in smaller batches for more controlled execution.
  • Clear feedback - Editors and administrators can review item-by-item results directly in the UI.

Supported content types

The tool can process the following content:

  • Pages - The selected root page and, optionally, its descendants.
  • Blocks - Blocks used inside page content areas.
  • Media - Media items when selected as the root or included through recursive hierarchy processing.

Important considerations

Important:
  • This tool updates content at database level and bypasses normal CMS editing safeguards.
  • Large operations may cause timeouts or database locks.
  • Run it during off-peak hours and always take a database backup first.
  • If changes do not appear immediately, clear any CDN or application cache and restart the site if needed.
  • If you use Optimizely Search & Navigation, reindex the content after the operation so search reflects the new master language.

Installation

Install the package from the Optimizely NuGet feed with:

dotnet add package A2Z.Optimizely.MasterLanguageSwitcher

How to use it

  1. Go to Admin > Tools > Master Language Switcher.
  2. Select the page or content root you want to process.
  3. Choose the target language.
  4. Optionally enable recursive processing to include child content.
  5. Click Change Language and review the live results in the UI.

Result feedback

The tool shows a clear results table after execution:

  • Each page, block, and media item is listed with its action and status.
  • Rows make it easier to spot switched, converted, skipped, or failed items.
  • A summary section shows totals for each result type.

Compatibility

This tool supports Optimizely CMS 12 and CMS 13. Check the package page and GitHub repository for the latest version details and updates.

Links

GitHub repository
NuGet package

FAQ

What is the difference between switch and convert?
Switch promotes an existing target language branch to master. Convert changes the current master language to the selected target language when that target branch does not already exist.

Is this safe for large trees?
It is designed to handle larger operations in batches, but you should still run it carefully, during quieter periods, and only after taking a backup.

Do I need to reindex after running it?
Yes, if you use Optimizely Search & Navigation, reindexing is recommended after the master language changes.

September 24, 2025

Friday, 19 April 2024

Mailchimp Marketing Automation Connector for Optimizely Forms

The A2Z.EPiServer.MarketingAutomationIntegration.Mailchimp add-on connects Optimizely Forms directly to Mailchimp so teams can send form submissions into mailing lists without relying on embedded Mailchimp forms. It gives developers and marketers a cleaner way to manage audience capture and marketing automation inside the Optimizely editing workflow.

This add-on is especially useful when you want editors to keep using Optimizely Forms while still pushing data into Mailchimp lists and interests through the Mailchimp API.

Note: This add-on draws inspiration from a blog post by Joshua Folkerts.

Why use this connector

  • Keep using Optimizely Forms instead of switching to embedded Mailchimp forms.
  • Map form fields directly to Mailchimp audience fields.
  • Support required and optional Mailchimp interests.
  • Give editors a simpler workflow for audience capture and list mapping.

Installation

Install the package in your Optimizely CMS project with:

dotnet add package A2Z.EPiServer.MarketingAutomationIntegration.Mailchimp

Configuration

Add the Mailchimp integration in Startup.cs inside ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMarketingAutomationMailchimp(o =>
    {
        o.MailChimpApiKey = "ApiKey";
        o.RequiredInterests = new List<string> { "b5423646b8", "f24a1b729b" };
        o.OptionalInterests = new List<OptionalInterest>
        {
            new()
            {
                Key = "Alloy News",
                Value = "a5423146b8"
            },
            new()
            {
                Key = "Alloy Announcements",
                Value = "d24e1f719b"
            }
        };
    });
}

You can also configure the add-on in appsettings.json:

"A2Z": {
  "AddMarketingAutomationMailchimp": {
    "MailChimpApiKey": "ApiKey",
    "RequiredInterests": ["a5423146b8", "d24e1f719b"],
    "OptionalInterests": [
      {
        "Key": "Alloy News",
        "Value": "a5423146b8"
      },
      {
        "Key": "Alloy Announcements",
        "Value": "d24e1f719b"
      }
    ]
  }
}

If the same settings exist in both places, the values in appsettings.json take precedence.

Scheduled job for caching

The package includes a scheduled job called [A2Z] Mailchimp Cache Manager. Its purpose is to preload Mailchimp lists and fields so editors do not experience the initial delay that can happen when data is fetched on demand for the first time.

This scheduled job improves the editor experience by caching Mailchimp data in advance, making form setup faster and smoother.

How editors use it

Start by creating a form in Optimizely Forms. In this example, the form contains three text fields: First Name, Last Name, and Email Address.

Example Optimizely form used with the Mailchimp connector

Editors will then see a new Mappings tab inside the form container block, where they can connect the form to a Mailchimp list.

Mailchimp list selection inside the Optimizely form mapping tab

After selecting a Mailchimp list, editors can map Optimizely form fields to the corresponding Mailchimp fields.

Field mapping between Optimizely Forms and Mailchimp fields

Mailchimp requires an Email field, so that field must always be mapped correctly. In most cases, you will also map fields such as first name and last name depending on the list setup.

Working with interests

Mailchimp interests cannot be mapped like normal text fields. They are designed to work with Multiple or single choice form elements in Optimizely Forms.

Mailchimp interest configuration in the Optimizely connector

Interest values such as d24e1f719b come from Mailchimp and can be configured as either Required or Optional.

  • Required interests are sent with every form submission.
  • Optional interests are sent only when the visitor selects the related option in the form.

Optional and required Mailchimp interest field setup

Compatibility

This add-on currently supports Optimizely CMS 12. Check the package page or GitHub repository for the latest updates and version support.

When this is useful

  • When you want to keep using Optimizely Forms instead of external Mailchimp forms.
  • When marketers need form submissions pushed directly into Mailchimp audiences.
  • When editors need a simpler way to connect forms to lists and interests.
  • When performance matters and cached Mailchimp metadata improves the setup experience.

Links

Full documentation and source code:

GitHub repository

NuGet package

FAQ

Does this replace Optimizely Forms?
No. It extends Optimizely Forms by sending submissions to Mailchimp.

Do editors need to map fields manually?
Yes. Editors select the Mailchimp list and map Optimizely form fields to the matching Mailchimp fields.

Does it support Mailchimp interests?
Yes. The connector supports both required and optional interests.

April 19, 2024

Thursday, 18 April 2024

Visitor Groups Usage Report for Optimizely CMS

This add-on helps Optimizely teams audit how Visitor Groups are used across the site so editors, marketers, and developers can review personalization rules with more confidence. Instead of guessing which groups are still active, you can quickly see where they are used and make better decisions around cleanup, optimization, and content targeting.

Originally, I wanted this to appear alongside Optimizely's built-in reports. In CMS 12, that is no longer possible because the GuiPlugIn attribute was removed, so I built it as a dedicated add-on with its own menu entry.

Why this report matters

Visitor Groups often grow over time and become difficult to track, especially across larger Optimizely solutions. This report gives you clearer visibility into where groups are being used, helping teams review personalization rules before changing or removing them.

  • See where Visitor Groups are used across site content.
  • Review personalization rules before cleanup or restructuring.
  • Support safer maintenance of older Optimizely solutions.
  • Give editors and admins better visibility into targeting setup.

Installation

Install the package in your Optimizely CMS project with:

dotnet add package A2Z.VisitorGroupsUsage

How to use it

After installation, open Add-ons > Visitor Groups Usage in the Optimizely admin interface to access the report.

Visitor Groups Usage report in Optimizely CMS

Typical use cases

  • Audit old or unused Visitor Groups before cleanup.
  • Validate where personalization is active across content.
  • Support content reviews during optimization or migration work.
  • Help editors and developers align on how targeting is being used.

Compatibility

This add-on is available for Optimizely CMS 12 and CMS 13. Check the package page or GitHub repository for the latest version details, installation steps, and updates.

Links

Full documentation and source code:

GitHub repository

NuGet package

FAQ

Does this replace Optimizely's built-in reports?
No. It adds a dedicated report page focused specifically on Visitor Group usage.

Who is this useful for?
It is useful for editors, marketers, administrators, and developers who maintain personalization across an Optimizely site.

April 18, 2024

Thursday, 11 April 2024

Plugin for Identifying and Bulk Deleting Orphaned Properties in Optimizely CMS

Orphaned Properties is an admin tool for Optimizely CMS 12 and CMS 13 that helps teams find and remove properties that no longer exist in code but still remain in the CMS. It gives administrators a faster and safer way to clean up missing properties without relying on repetitive manual checks.

Why orphaned properties happen

When a property is renamed or removed from a content type in code, Optimizely can automatically clean it up only if no data is stored against it. If data still exists, the property is left behind and appears as missing from code.

These missing properties can continue to appear in the admin area, creating clutter and making long-term maintenance harder. In larger solutions, reviewing them one by one becomes time-consuming and easy to miss.

What this tool does

This add-on was built to make that cleanup process easier for administrators.

  • Identify orphaned or missing properties that are no longer defined in code.
  • Review them in one place instead of checking content types individually.
  • Bulk delete outdated properties more efficiently.
  • Reduce the risk of overlooking legacy data during cleanup work.

Installation

Install the package in your Optimizely project with:

dotnet add package A2Z.OrphanedProperties

How to use it

After installation, open Admin > Orphaned Properties to review properties that are missing from code and manage cleanup from one place.

Orphaned Properties tool in Optimizely CMS

When this is useful

  • After refactoring content models.
  • During Optimizely upgrades or solution cleanup work.
  • When removing old properties from pages, blocks, or shared base classes.
  • When auditing legacy data left behind in long-running CMS solutions.

Compatibility

This tool supports Optimizely CMS 12 and CMS 13. Check the package page or GitHub repository for the latest updates and implementation details.

Links

Full documentation and source code:

GitHub repository

NuGet package

FAQ

Does this remove properties automatically?
No. It gives administrators a dedicated place to review and bulk remove orphaned properties more safely.

Who is this tool for?
It is mainly for Optimizely administrators and developers responsible for content model cleanup and long-term CMS maintenance.

April 11, 2024