...
Navigate to the Startup.cs
file and add the following code to the ConfigureServices method to register the plugin with the solution's service collection.
Code Block |
---|
```cs |
...
using Fotoware.ContentPlatform.Plugins.Optimizely; |
...
services.AddFotowareContentPlatformPlugin(); |
...
``` |
Configure appsettings.json
Code Block |
---|
```json |
...
"ContentPlatform": { |
...
"BaseTenantUrl": "https://yourdomain.preview-picturepark.com", |
...
"RootFolderId": 102, |
...
"EnableOnAllMedia": true, |
...
"DisableDefaultMediaSelector": false, |
...
"DefaultTinyMceImageWidth": 600, |
...
"UseImageCdnUrlInTinyMce": false, |
...
"MediaTypes": |
...
{
[ { "Name": "Image", |
...
"FileExtensions": ".jpg,.jpeg,.jpe,.gif,.bmp,.png,.gif", |
...
"DownloadContentSelectionName": "Original", |
...
"PreviewContentSelectionName": "Preview", |
...
"PreferredDownloadWidth": |
...
},
{
1200 }, { "Name": "Video", |
...
"FileExtensions": ".mov,.mp4", |
...
"DownloadContentSelectionName": "VideoSmall", |
...
"PreviewContentSelectionName": "Preview" |
...
}, |
...
{
...
{ "Name": "Pdf", |
...
"FileExtensions": ".pdf", |
...
"DownloadContentSelectionName": "Original", |
...
"PreviewContentSelectionName": "Preview" |
...
}
]
}
...
}
]
}
``` |
Value | Description |
---|---|
BaseTenantUrl | The base URL of the picker. |
RootFolderId | The Optimizely media folder ID where the media is downloaded and stored. |
EnableOnAllMedia | When set to true, all media properties will have the DAM picker capability. |
DisableDefaultMediaSelector | When set to true, the default Optimizely media selector behavior will be disabled. |
DefaultTinyMceImageWidth | The default width for displaying images selected from the DAM in TinyMCE. |
UseImageCdnUrlInTinyMce | When enabled, the image URL in TinyMCE will use the CDN URL instead of the Optimizely image URL. |
MediaTypes | Configuration for the supported media types in the plugin. |
MediaTypes.Name | The name of the media type. The supported media types are Image, Video, and PDF. |
MediaTypes.FileExtensions | The file extensions of the media type, separated by a comma. |
MediaTypes.DownloadContentSelectionName | Refers to the content variant name used for downloading and importing into Optimizely media. |
MediaTypes.PreviewContentSelectionName | Refers to the content variant name used for previewing purposes. |
PreferredDownloadWidth | Specifies the preferred image width for downloading. This option is supported only for the Image media type. |
...
You must implement the IFotowareMedia interface on a content type that inherits from the Optimizely MediaData class in your solution. This enables additional fields that the add-on uses to maintain synchronization with the original media.
Code Block |
---|
```cs |
...
public interface IFotowareMedia : IContentData |
...
{
string Name { get; set; }
{ string Name { get; set; } /// |
...
<summary> /// Fotoware alternative |
...
text /// </summary> |
...
string FotowareAltText { get; set; |
...
} /// |
...
<summary> /// Fotoware |
...
description /// </summary> |
...
string FotowareDescription { get; set; |
...
} /// |
...
<summary> /// Fotoware CDN |
...
url /// </summary> |
...
string FotowareUrl { get; set; |
...
} /// |
...
<summary> /// Fotoware Preview CDN |
...
url /// </summary> |
...
string FotowarePreviewUrl { get; set; |
...
} /// |
...
<summary> /// Fotoware JSON |
...
metadata /// </summary> |
...
string FotowareJson { get; set; |
...
} /// |
...
<summary> /// Fotoware modified |
...
date /// </summary> |
...
DateTime? FotowareModifiedDate { get; set; } |
...
} |
...
``` |
Example implementation of IFotowareMedia
Code Block |
---|
```cs |
...
[ContentType(GUID = "0A89E464-56D4-449F-AEA8-2BF774AB8730")] |
...
[MediaDescriptor(ExtensionString = "jpg,jpeg,jpe,ico,gif,bmp,png")] |
...
public class ImageFile : ImageData, IFotowareMedia |
...
{
{ [UIHint(UIHint.Textarea)] |
...
public virtual string Description { get; set; }
public virtual string AltText { get; set; }
// IFotowareMedia properties
...
public virtual string Description { get; set; } public virtual string AltText { get; set; } // IFotowareMedia properties [Display(GroupName = FotowareGroupNames.Fotoware)] |
...
public virtual string FotowareUrl { get; set; }
public virtual string FotowareUrl { get; set; } [Editable(false)] |
...
[Display(GroupName = FotowareGroupNames.Fotoware)] |
...
public virtual string FotowarePreviewUrl { get; set; }
public virtual string FotowarePreviewUrl { get; set; } [UIHint(UIHint.Textarea)] |
...
[Editable(false)] |
...
[Display(GroupName = FotowareGroupNames.Fotoware)] |
...
public virtual string FotowareJson { get; set; }
public virtual string FotowareJson { get; set; } [Editable(false)] |
...
[Display(GroupName = FotowareGroupNames.Fotoware)] |
...
public virtual DateTime? FotowareModifiedDate { get; set; |
...
} [ScaffoldColumn(false)] |
...
public string FotowareAltText
{
...
public string FotowareAltText { get => this.GetPropertyValue(p => p.AltText); |
...
set => this.SetPropertyValue(p => p.AltText, value); |
...
}
} [ScaffoldColumn(false)] |
...
public string FotowareDescription
{
...
public string FotowareDescription { get => this.GetPropertyValue(p => p.Description); |
...
set => this.SetPropertyValue(p => p.Description, value); |
...
}
}
} } ``` |
The ModifiedDate property is used to track when the media was last changed in the DAM. The plugin uses it to determine whether to download the media.
...
Example of TinyMCE configuration
Code Block |
---|
```cs |
...
services.Configure<TinyMceConfiguration>(config => |
...
{
{ config.Default().AddSetting("extended_valid_elements", |
...
"iframe[src|alt|title|width|height|align|name],picture,source[srcset|media|src],span") |
...
.AddPlugin( |
...
"epi-link epi-image-editor epi-dnd-processor epi-personalized-content preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template codesample table charmap pagebreak nonbreaking anchor insertdatetime advlist lists " |
...
+ "wordcount help code") |
...
.Toolbar( |
...
"bold italic strikethrough forecolor | epi-link image media epi-image-editor epi-personalized-content | contentplatform-insert-media | bullist numlist | searchreplace fullscreen ", |
...
"styleselect blocks | alignleft aligncenter alignright alignjustify | removeformat | table toc | code"
, "");
});
"styleselect blocks | alignleft aligncenter alignright alignjustify | removeformat | table toc | code" , ""); }); ``` |
By default, the button is added to the default TinyMCE, but if you have custom tinys for blocks with other configurations, you can apply the following: .AddFotowareContentPlatformToTinyMCE(serviceCollection):
Code Block |
---|
``` |
...
services.Configure<TinyMceConfiguration>(config => |
...
config.For<TextHtmlBlock>(t => t.Text) |
...
.AddEpiserverSupport() |
...
.AddFotowareContentPlatformToTinyMCE(serviceCollection) // This registers the plugin and the settings. |
...
.Toolbar(AllSettings); |
...
); |
...
``` |
Apply UIHint and FotowareConfiguration attributes to Optimize properties
...
Example of using the image UIHint
Code Block |
---|
```cs |
...
[Display(Name = "Content Reference (Optimizely)", GroupName = "Content Reference", Order = 10)] |
...
[UIHint(ContentPlatformUiHint.Image)] |
...
public virtual ContentReference ContentReferenceOptimizely { get; set; } |
...
[Display(Name = "Content Reference (Fotoware)", GroupName = "Content Reference", Order = 20)] |
...
[FotowareConfiguration(DisableDefaultMediaSelector = true)] |
...
[UIHint(ContentPlatformUiHint.Image)] |
...
public virtual ContentReference ContentReferenceFotoware { get; set; } |
...
[Display(Name = "Url (Optimizely)", GroupName = "Url", Order = 10)] |
...
[UIHint(ContentPlatformUiHint.ImageUrl)] |
...
public virtual Url ImageAsUrlOptimizely { get; set; } |
...
``` |
The UIHint attribute can be applied to ContentReference and Url property types.
Value | Description |
---|---|
ContentPlatformUiHint.Image | Replaces the Optimize selector with the Fotoware image selector for the ContentReference property. |
ContentPlatformUiHint.ImageUrl | Replaces the Optimize selector with the Fotoware image selector for the Url property. |
ContentPlatformUiHint.Video | Replaces the Optimize selector with the Fotoware video selector for the ContentReference property. |
ContentPlatformUiHint.VideoUrl | Replaces the Optimize selector with the Fotoware video selector for the Url property. |
ContentPlatformUiHint.Pdf | Replaces the Optimize selector with the Fotoware media selector for the ContentReference property. |
ContentPlatformUiHint.PdfUrl | Replaces the Optimize selector with the Fotoware media selector for the Url property. |
...
To disable the plugin in the Optimizely Commerce Asset list, set the PreventCommerceEditorIntegration setting to true.
Code Block |
---|
```json |
...
"ContentPlatform": { |
...
... |
...
"PreventCommerceEditorIntegration": true |
...
} |
...
``` |
Logging
The plugin has a number of logging information that can be used for information and debugging the integration. Update appsettings.json as the following.
Code Block |
---|
```json |
...
"Logging": |
...
{ "LogLevel": |
...
{ "Fotoware.ContentPlatform.Plugins.Optimizely": "Information" |
...
}
},
} }, ``` |
Multiple site configuration
You can configure the plugin to run with Optimizely multi-site scenario by specifying the site ID for each site in the Sites collection in appsettings.json.
Code Block |
---|
```json |
...
"ContentPlatform": { |
...
"BaseCdnUrl": "https://optimizely.preview-picturepark.com", |
...
"Sites": |
...
{
[ { "SiteId": "7e9335f8-2f16-44b0-8870-8f2d4bc0160c", |
...
"RootFolderId": 102, |
...
"EnableOnAllMedia": true, |
...
"DisableDefaultMediaSelector": false, |
...
"DefaultTinyMceImageWidth": 600, |
...
"UseImageCdnUrlInTinyMce": false, |
...
"MediaTypes": |
...
{
[ { "Name": "Image", |
...
"FileExtensions": ".jpg,.jpeg,.jpe,.gif,.bmp,.png,.gif", |
...
"PreferredDownloadWidth": 1200, |
...
"DownloadContentSelectionName": "Original", |
...
"PreviewContentSelectionName": "Preview" |
...
},
{
}, { "Name": "Video", |
...
"FileExtensions": ".mov,.mp4", |
...
"DownloadContentSelectionName": "VideoSmall", |
...
"PreviewContentSelectionName": "Preview" |
...
},
{
}, { "Name": "Pdf", |
...
"FileExtensions": ".pdf", |
...
"DownloadContentSelectionName": "Original" |
...
, "PreviewContentSelectionName": "Preview" |
...
}
]
}
]
}
} ] } ] } ``` |
SiteId - The ID of the site, which you can find in Admin > Manage Websites.
Customization
...
Managing the structure of downloaded assets in Optimizely
Fotoware Media imported into Optimizely are organized into a year-month folder structure to facilitate browsing and prevent issues with large media lists in the same folder, which Optimizely doesn't handle well. By default, folders are created based on the year and month when the media was imported. However, you can customize this structure. For example, you could base it on metadata within your solution.
Code Block |
---|
``` |
...
2024 |
...
| |
...
---06 |
...
|
| image01.jpg |
...
video02.mp4 |
...
````
|
This customization is achieved by implementing the IFolderResolver interface.
...
You can create custom HTML input when inserting media into TinyMCE, such as filling in the alt text or adding CSS classes.
To achieve thisdo so, implement and register an IFotowareTinyMceTemplate where you implement the GetHtml(ContentReference contentReference, InsertTinyMceMedia insertTinyMceMedia) method.
...
Example of how to register event handlers for the Fotoware events in an InitializationModule
Code Block |
---|
```cs |
...
[ModuleDependency(typeof(InitializationModule))] |
...
public class FotowareContentEventsInitializationModule : IInitializableModule |
...
{
...
{ public void Initialize(InitializationEngine context) |
...
{
...
{ var events = context.Locate.Advanced.GetRequiredService<FotowareEvents>(); |
...
events.OnContentDownloading += OnContentDownloading; |
...
events.OnContentDownloaded += OnContentDownloaded; |
...
}
...
} public void Uninitialize(InitializationEngine context) |
...
{
...
{ var events = context.Locate.Advanced.GetRequiredService<FotowareEvents>(); |
...
events.OnContentDownloading -= OnContentDownloading; |
...
events.OnContentDownloaded -= OnContentDownloaded; |
...
}
...
} private void OnContentDownloading(object sender, FotowareContentEventArgs e) |
...
{
{ // Handle content downloaded event |
...
}
...
here } private void OnContentDownloaded(object sender, FotowareContentEventArgs e) |
...
{
{ // Handle content downloaded event |
...
}
}
here } } ``` |
OnContentDownloading - Raised before downloading a media with the possibility to cancel the action.
OnContentDownloaded - Raised after the media has been downloaded.
How to use in the frontend
Using PropertyFor
```
Code Block |
---|
``` @Html.PropertyFor(m => Model.CurrentPage.ImageAsContentReference) |
...
``` |
...
####Output |
...
``` |
...
<img alt="image01.jpg" src="/globalassets/fotoware/2024/6/image01.jpg" /> |
...
``` |
Adding a HTML attribute
Code Block |
---|
``` |
...
@Html.PropertyFor(x => Model.CurrentPage.ContentReferenceOptimizely, new { Attributes = new { @class = "fotoware-image" } }) |
...
``` |
...
####Output |
...
``` |
...
<img alt="image01.jpg" class="fotoware-image" src="/globalassets/fotoware/2024/6/image01.jpg"> |
...
``` |
Adding a query string
Code Block |
---|
``` |
...
@Html.PropertyFor(x => Model.CurrentPage.ContentReferenceOptimizely, new { QueryStrings = new { format = "webp" } }) |
...
``` |
...
Output |
...
``` |
...
<img alt="image01.jpg" src="/globalassets/fotoware/2024/6/image01.jpg?format=webp"> |
...
``` |
Adding query parameters
Code Block |
---|
``` |
...
@Html.PropertyFor(x => Model.CurrentPage.ContentReferenceOptimizely, new { QueryParameters = "format=webp&quality=80" }) |
...
``` |
...
Output |
...
``` |
...
<img alt="image01.jpg" src="/globalassets/fotoware/2024/6/image01.jpg?format=webp&quality=80"> |
...
``` |
Use CDN URL
Code Block |
---|
``` |
...
@Html.PropertyFor(x => Model.CurrentPage.ContentReferenceOptimizely, new { MediaOptions = new { UseCdnUrl = true } }) |
...
``` |
...
Output |
...
``` |
...
<img alt="image01.jpg" src="https://optimizely.preview-picturepark.com/v/TBVACNY3/"> |
...
``` |
Use CDN URL with the specified width
Code Block |
---|
``` |
...
@Html.PropertyFor(x => Model.CurrentPage.ContentReferenceOptimizely, new { MediaOptions = new { Width = 600, UseCdnUrl = true } }) |
...
``` |
...
Output |
...
``` |
...
<img alt="image01.jpg" src="https://optimizely.preview-picturepark.com/v/TBVACNY3/fit-in:600x100000"> |
...
``` |