Just in case anyone need the whole code
Customized to have any amount of menus and sub menus
NOP.Plugin.yourplugin/Infrastructure/CustomerViewEngine.cs
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Razor;
namespace Nop.Plugin.yourplugin.Infrastructure
{
class CustomerViewEngine: IViewLocationExpander
{
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
if (context.AreaName == null && context.ViewName == "Components/CustomerNavigation/Default")
{
viewLocations = new[] { $"/Plugins/yourplugin/Views/{{0}}.cshtml" }.Concat(viewLocations);
}
return viewLocations;
}
public void PopulateValues(ViewLocationExpanderContext context)
{
//throw new NotImplementedException();
}
}
}
NOP.Plugin.yourplugin/Infrastructure/NopStartup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Nop.Core.Infrastructure;
namespace Nop.Plugin.yourplugin.Infrastructure
{
class NopStartup : INopStartup
{
public int Order => int.MaxValue;
public void Configure(IApplicationBuilder application)
{
//throw new NotImplementedException();
}
public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add(new CustomerViewEngine());
});
}
}
}
NOP.Plugin.yourplugin/Models/PreparedModelConsumer.cs
using Nop.Services.Events;
using Nop.Web.Framework.Events;
using Nop.Web.Framework.Models;
using Nop.Web.Models.Customer;
namespace Nop.Plugin.yourplugin.Models
{
class PreparedModelConsumer : IConsumer<ModelPreparedEvent<BaseNopModel>>
{
public void HandleEvent(ModelPreparedEvent<BaseNopModel> eventMessage)
{
if (eventMessage?.Model is CustomerNavigationModel customerNavigationModel)
{
var parent1 = new CustomerNavigationItemModel
{
RouteName = "NOROUTE",
Title = "Parent 1",
Tab = (CustomerNavigationEnum)140,
ItemClass = "parent1"
};
customerNavigationModel.CustomerNavigationItems.Add(parent1);
var child1 = new CustomerNavigationItemModel
{
RouteName = "routename-or-url",
Title = "Child 1",
Tab = (CustomerNavigationEnum)140,
ItemClass = "child1",
};
child1.CustomProperties.Add("ParentMenu", "Parent 1"); // define the parent. use title of the parent
customerNavigationModel.CustomerNavigationItems.Add(child1);
var child2 = new CustomerNavigationItemModel
{
RouteName = "routename-or-url",
Title = "Child 2",
Tab = (CustomerNavigationEnum)140,
ItemClass = "child2",
};
child2.CustomProperties.Add("ParentMenu", "Parent 1"); // define the parent. use title of the parent
customerNavigationModel.CustomerNavigationItems.Add(child2);
var parent2 = new CustomerNavigationItemModel
{
RouteName = "NOROUTE",
Title = "Parent 2",
Tab = (CustomerNavigationEnum)140,
ItemClass = "parent2"
};
customerNavigationModel.CustomerNavigationItems.Add(parent2);
var child3 = new CustomerNavigationItemModel
{
RouteName = "routename-or-url",
Title = "Child 3",
Tab = (CustomerNavigationEnum)140,
ItemClass = "child3",
};
child3.CustomProperties.Add("ParentMenu", "Parent 2"); // define the parent. use title of the parent
customerNavigationModel.CustomerNavigationItems.Add(child3);
var child4 = new CustomerNavigationItemModel
{
RouteName = "routename-or-url",
Title = "Child 4",
Tab = (CustomerNavigationEnum)140,
ItemClass = "child4",
};
child4.CustomProperties.Add("ParentMenu", "Parent 2"); // define the parent. use title of the parent
customerNavigationModel.CustomerNavigationItems.Add(child4);
}
}
}
}
NOP.Plugin.yourplugin/Views/Components/CustomerNavigation/Default.cshtml
@using Nop.Web.Models.Customer;
@using Nop.Web.Framework.Infrastructure;
@model CustomerNavigationModel
@{
var childMenu = new Dictionary<string, List<CustomerNavigationItemModel>>();
foreach (var item in Model.CustomerNavigationItems.ToList())
{
if (item.CustomProperties.ContainsKey("ParentMenu"))
{
if (!childMenu.ContainsKey(item.CustomProperties["ParentMenu"].ToString()))
{
childMenu[item.CustomProperties["ParentMenu"].ToString()] = new List<CustomerNavigationItemModel>();
}
childMenu[item.CustomProperties["ParentMenu"].ToString()].Add(item);
Model.CustomerNavigationItems.Remove(item);
}
}
}
<div class="block block-account-navigation">
<div class="title">
<strong>@T("Account.Navigation")</strong>
</div>
<div class="listbox">
<ul class="list">
@await Component.InvokeAsync("Widget", new { widgetZone = PublicWidgetZones.AccountNavigationBefore })
@foreach (var item in Model.CustomerNavigationItems)
{
<li class="@item.ItemClass @(Model.SelectedTab == item.Tab ? "active" : "inactive")">
<a href="@Url.RouteUrl(item.RouteName)">@(item.Title)</a>
@if (childMenu.ContainsKey(item.Title))
{
foreach (var child in childMenu[item.Title])
{
<ul>
<li class="@child.ItemClass" style="margin-left: 10px;">
<a href="@Url.RouteUrl(child.RouteName)">@(child.Title)</a>
</li>
</ul>
}
}
</li>
}
@await Component.InvokeAsync("Widget", new { widgetZone = PublicWidgetZones.AccountNavigationAfter })
</ul>
</div>
</div>
NOP.Plugin.yourplugin/Nop.Plugin.yourplugin.csproj
...
<ItemGroup>
<ProjectReference Include="..\..\Presentation\Nop.Web.Framework\Nop.Web.Framework.csproj" />
<ProjectReference Include="..\..\Presentation\Nop.Web\Nop.Web.csproj" /> <!--add this line-->
<ClearPluginAssemblies Include="$(MSBuildProjectDirectory)\..\..\Build\ClearPluginAssemblies.proj" />
</ItemGroup>
...