From ae0c5f02a1dcb8b17dd97fb873b8c6f8dd11ef6f Mon Sep 17 00:00:00 2001 From: NathanWoulfe Date: Wed, 19 Nov 2025 14:03:46 +1000 Subject: [PATCH 1/3] update extension docs for Engage --- .../assets/External-profile-data-tab-v16.png | Bin 15050 -> 16365 bytes .../implement-your-own-segment-parameters.md | 240 ++++++++---------- .../profiling/external-profile-data.md | 65 +++-- 3 files changed, 141 insertions(+), 164 deletions(-) diff --git a/16/umbraco-engage/.gitbook/assets/External-profile-data-tab-v16.png b/16/umbraco-engage/.gitbook/assets/External-profile-data-tab-v16.png index f6390a1f002d80fe420836408d496abf587a1bba..03ded120c28bf239472b1899c9c1a32fef66988f 100644 GIT binary patch literal 16365 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 - Discover how to create and manage custom segments. + Discover how to create and manage custom segments. --- # Implement your own segment parameters -Umbraco Engage comes with built-in parameters to build a segment, such as "Customer Journey" and "Time of Day". -However, segments can also be built with custom rules that are not included in Engage by default by adding custom segment parameters. +Umbraco Engage comes with built-in parameters to build a segment, such as "Customer Journey" and "Time of Day". +However, custom segments can be built by providing your own segment parameters. The following guide explains how to achieve this. It is aimed at developers. There are three steps, two are mandatory, and the last one is optional: @@ -24,18 +24,18 @@ In code, a segment parameter is referred to as a "segment rule". A segment rule is not much more than this: -* A unique rule identifier, e.g. "DayOfWeek". -* A configuration object, e.g. "{ dayOfWeek: "Monday" }" - * This is optional, but most rules will have some sort of configuration that the user can alter in the Segment Builder. In our example, the user can configure the specific day of the week. -* A method that specifies whether the rule is satisfied by the current pageview. +- A unique rule identifier, e.g. "DayOfWeek". +- A configuration object, e.g. "{ dayOfWeek: "Monday" }" + - This is optional, but most rules will have some sort of configuration that the user can alter in the Segment Builder. In our example, the user can configure the specific day of the week. +- A method that specifies whether the rule is satisfied by the current pageview. You will have to implement the following interfaces for a new custom parameter: -* `Umbraco.Engage.Infrastructure.Personalization.Segments.ISegmentRule` - * You can extend the existing `BaseSegmentRule` to simplify the implementation. - * The most important part to implement is the `bool IsSatisfied(IPersonalizationProfile context)` method. -* `Umbraco.Engage.Infrastructure.Personalization.Segments.Rules.ISegmentRuleFactory` - * Register your implementation of the segment rule factory with `Lifetime.Transient` in a composer. -For the "Day of week" example, the code looks like this: + +- `Umbraco.Engage.Infrastructure.Personalization.Segments.ISegmentRule` + - You can extend the existing `BaseSegmentRule` to simplify the implementation. + - The most important part to implement is the `bool IsSatisfied(IPersonalizationProfile context)` method. +- `Umbraco.Engage.Infrastructure.Personalization.Segments.Rules.ISegmentRuleFactory` \* Register your implementation of the segment rule factory with `Lifetime.Transient` in a composer. + For the "Day of week" example, the code looks like this: ```c# public class DayOfWeekSegmentRule : BaseSegmentRule @@ -56,138 +56,136 @@ public class DayOfWeekSegmentRule : BaseSegmentRule And the factory which is used to create an instance of this rule: ```c# -//The segment rule factory needs to be registered so Engage can use it. -[RegisterService(ServiceLifetime.Transient)] public class DayOfWeekSegmentRuleFactory : ISegmentRuleFactory { public string RuleType { get; } = "DayOfWeek"; public ISegmentRule CreateRule(string config, bool isNegation, long id, Guid key, long segmentId, DateTime created, DateTime? updated) { - var typedConfig = JsonConvert.DeserializeObject(config); + var typedConfig = JsonSerializer.Deserialize(config) + ?? throw new InvalidOperationException("Failed to deserialize DayOfWeekSegmentRuleConfig"); + return new DayOfWeekSegmentRule(id, key, segmentId, RuleType, config, isNegation, created, updated, typedConfig); } } ``` -The class `DayOfWeekSegmentRuleConfig` is used to represent the rule configuration. This is not strictly necessary, but it makes it easier. +The class `DayOfWeekSegmentRuleConfig` is used to represent the rule configuration. This is not strictly necessary, but it makes it easier. The configuration is stored as a string in the database. In code, Intellisense is enabled to parse the stored configuration to this class: ```c# -//Generating config schema on client side. -[GenerateEngageSchema] public class DayOfWeekSegmentRuleConfig { public DayOfWeek DayOfWeek { get; set; } } ``` -That's the C# part of the custom segment parameter. - ## 2. Web component definition -The business logic for the segment parameter has been implemented, but the parameter cannot yet be used in the backoffice. In this step, a web component will be added to render the new rule in the Engage segment builder. -The following steps provide code samples for the demo parameter "Day of week". -You can create a folder to manage new files. Those files look like this: -* `segment-rule-base.ts` - * Type declaration for `UeSegmentRuleBaseElement` from Umbraco Engage. This is a temporary declaration until Umbraco Engage provides an npm package. -* `segment-rule-day-of-week.ts` - * Declaration for the web component using Lit. -* `index.ts` - * Exporting all elements. -* `manifest.ts` - * Declares the element as a backoffice extension and registers it in the Extension Registry. Read more in the [Extension Manifest documentation](https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-registry/extension-manifest). - -First, re-generate the `DayOfWeek` config type on the client side using the below command: +{% hint style="info" %} +Check the [Creating your first extension](/umbraco-cms/tutorials/creating-your-first-extension) and [Vite Package Setup](/umbraco-cms/customizing/development-flow/vite-package-setup) articles for detailed extension-building tutorials. +{% endhint %} -```text -npm run generate:api -``` - -**segment-rule-base.ts** - -```typescript -enum RuleDirection { - INCLUDE = "include", - EXCLUDE = "exclude", -} +The business logic for the segment parameter has been implemented, but the parameter cannot yet be used in the backoffice. In this step, a web component will be added to render the new rule in the Engage segment builder. -export interface UeSegmentRuleParameterConfig { - isNegation: boolean; - config: ValueType; -} +This demo assumes you are creating multiple custom rules, which are then provided as a bundle in the backoffice. -export class UeSegmentRuleBaseElement extends UmbLitElement { - abstract renderReadOnly(); - abstract renderEditor(); - value: UeSegmentRuleParameterConfig; - initialized: Promise; +First, follow the [Vite Package Setup](/umbraco-cms/customizing/development-flow/vite-package-setup) article to scaffold your extension. Use `MySegmentRules` as your package name - @property({ type: Boolean, attribute: true, reflect: true }) - readonly?: boolean; +1. Install `@umbraco-engage/backoffice` package, replacing `x.x.x` with your Engage version: - updateParameterValue(value: any, key: keyof ValueType) { - if (!this.value?.config) return; +```text +npm install @umbaco-engage/backoffice@x.x.x +``` - const config = { ...(this.value.config ?? {}), ...{ [key]: value } }; - this.pending = assignToFrozenObject(this.value, { config }); - this.renderReadOnly(); - } +2. Ensure your `vite.config.ts` looks like the example below: - render() { - return this.readonly ? this.#renderReadOnly() : this.#renderEditor(); - } +```typescript +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + lib: { + entry: "src/my-element.ts", // your web component source file + formats: ["es"], + }, + outDir: "./client", // all compiled files will be placed here + emptyOutDir: true, + sourcemap: true, + rollupOptions: { + external: [/^@umbraco/], // ignore the Umbraco Backoffice package in the build + }, + }, + base: "/App_Plugins/MySegmentRules/client", // the base path of the app in the browser (used for assets) +}); +``` - #renderReadOnly() { - return html` -
- - ${this.renderReadOnly()} -
- `; - } +3. Update `umbraco-package.json` to register the bundle and segment rule. Note the `meta.type` property matches the `RuleType` defined above in `DayOfWeekSegmentRuleFactory`. - #renderEditor() { - return html` -
-

${this.manifest?.meta.name}

- -
-
${this.renderEditor()}
- `; - } +```json +{ + "$schema": "../../umbraco-package-schema.json", + "name": "My Custom Engage Segment Rules", + "allowPublicAccess": true, + "extensions": [ + { + "name": "My Engage Segment Rules Bundle", + "alias": "My.Bundle.SegmentRules", + "type": "bundle", + "js": "/App_Plugins/MySegmentRules/client/client.js" + }, + { + "type": "engageSegmentRule", + "alias": "Engage.Segment.Rule.DayOfWeek", + "name": "Engage Day of Week Segment Rule", + "weight": 100, + "elementName": "ue-segment-rule-day-of-week", + "meta": { + "name": "Day of week", + "icon": "icon-calendar", + "type": "DayOfWeek", + "config": { "dayOfWeek": "Sunday" } + } + } + ] } - ``` -**segment-rule-day-of-week.ts** +4. Update `src/my-element.ts` as below. Note `DayOfWeekSegmentRuleConfigModel` reflects the same data contract as the `DayOfWeekSegmentRuleConfig` class in C#. While it is possible to generate this using code-gen tools, this has been done manually to avoid complicating this tutorial. -```typescript -export interface UeSegmentRuleDayOfWeekConfig - extends DayOfWeekSegmentRuleConfigModel {} +Note too the `meta.config` object defined above in the package JSON implements the `DayOfWeekSegmentRuleConfigModel` interface. + +By extending `UeSegmentRuleBaseElement` you avoid writing boilerplate code, and don't have to worry about handling value updates or syncing data back to the segment. -const elementName = "ue-segment-rule-day-of-week"; +```typescript +import { + customElement, + html, + state, +} from "@umbraco-cms/backoffice/external/lit"; +import type { UUISelectEvent } from "@umbraco-cms/backoffice/external/uui"; +import { UeSegmentRuleBaseElement } from "@umbraco-engage/backoffice/personalization"; + +export interface DayOfWeekSegmentRuleConfigModel { + dayOfWeek: string; +} -@customElement(elementName) -export class UeSegmentRuleDayOfWeekElement extends UeSegmentRuleBaseElement { +@customElement("ue-segment-rule-day-of-week") +export class UeSegmentRuleDayOfWeekElement extends UeSegmentRuleBaseElement { @state() - private _options: Array = []; + private _options: Array