Single block type with render style dropdown

A single block type example with a select one dropdown for choosing style

Selection factory

Start by adding a selection factory that will be used in the block type:

using EPiServer.Shell.ObjectEditing;
..
public class RekRecommendationsRenderStyleSelectionFactory : ISelectionFactory
{
    public IEnumerable<ISelectItem> GetSelections(ExtendedMetadata metadata)
    {
        return
        [
            new SelectItem { Text = "List - A list where each LI contains an A that links to the page.", Value = "list" },
            new SelectItem { Text = "Pills - Creates oval shaped links.", Value = "pills" },
            new SelectItem { Text = "Advanced - Often used for news recommendations. Includes image, title and preamble.", Value = "advanced" },
        ];
    }
}

We will use this for a select one dropdown on the block type:

The Renderstyle select one dropdown in Edit Mode

Block type

Add a RekRecommendationsBlock block type:

[SiteContentType(
    GUID = "8AD9C8E2-9337-4DCB-AC11-8A4F47D127E6",
    GroupName = Globals.GroupNames.Rek,
    DisplayName = "Rek.ai Recommendations",
    Description = "A block that displays recommendations. Has general options for styles and filtering.")]
[SiteImageUrl("/gfx/block-type-thumbnail-rek-recommendations.png")]
public class RekRecommendationsBlock : SiteBlockData // Or just BlockData if outside of Alloy
{
    [Display(
        Name = "Renderstyle",
        Description = "How the recommendations should be rendered.",
        Order = 1)]
    [SelectOne(SelectionFactoryType = typeof(RekRecommendationsRenderStyleSelectionFactory))]
    public virtual string Renderstyle { get; set; }
 
    [Display(
        Name = "Headertext",
        Description = "A heading that is printed above the recommendations. Ex: “Recommended reading”.",
        Order = 2)]
    [CultureSpecific]
    public virtual string Headertext { get; set; }
 
    [Display(
        Name = "Subtree",
        Description = "The subtree to use for recommendations, if empty, the entire site is used. Ex: /science/,/accommodation/",
        Order = 3)]
    [CultureSpecific]
    public virtual string Subtree { get; set; }
 
    [Display(
        Name = "Only subpages to the currently visited page",
        Description = "Used instead of subtree and defaults to the URL of the page that is loading the block.",
        Order = 4)]
    [CultureSpecific]
    public virtual bool UseRootPath { get; set; }
 
    [Display(
        Name = "Number of hits",
        Description = "The maximum number of hits to display.",
        Order = 5)]
    [CultureSpecific]
    public virtual int Hits { get; set; }
 
    [Display(
        Name = "Advanced settings",
        Description = "Provides the opportunity to enter more parameters to the recommendation than what the interface offers. Ex: data-allowedlangs=\"se\" data-excludetree=\"/website-part-1,/website-part-2\"",
        Order = 6)]
    [CultureSpecific]
    [UIHint(UIHint.Textarea)]
    public virtual string AdvancedSettings { get; set; }
}

Block type thumbnail referenced by SiteImageUrl:

Thumbnail for the Rek.ai Recommendations block type

View

Add a RekRecommendationsBlock.cshtml file to Views/Shared/Blocks:

@model RekRecommendationsBlock
 
@{
    var attributes = new Dictionary<string, string>
    {
        { "class", "rek-prediction" },
        { "data-renderstyle", Model.Renderstyle ?? "list" }
    };
 
    if (Model.Headertext != null)
    {
        attributes.Add("data-headertext", HttpUtility.HtmlEncode(Model.Headertext));
    }
 
    if (Model.Hits > 0)
    {
        attributes.Add("data-nrofhits", Model.Hits.ToString(CultureInfo.InvariantCulture));
    }
 
    if (!string.IsNullOrWhiteSpace(Model.Subtree) && !Model.UseRootPath)
    {
        attributes.Add("data-subtree", HttpUtility.HtmlEncode(Model.Subtree));
    }
    
    if (Model.UseRootPath)
    {
        attributes.Add("data-userootpath", "true");
    }
 
    if (!isProduction
        && !string.IsNullOrWhiteSpace(siteSettings.RekProjectId)
        && !string.IsNullOrWhiteSpace(siteSettings.RekSecretKey))
    {
        attributes.Add("data-projectid", siteSettings.RekProjectId);
        attributes.Add("data-srek", siteSettings.RekSecretKey);
    }
 
    var advancedSettings = Model.AdvancedSettings != null ? " " + Model.AdvancedSettings : string.Empty;
}
 
<div @Html.Raw(string.Join(" ", attributes.Select(x => $"{x.Key}=\"{x.Value}\"")) + advancedSettings)></div>