How to override View on Nop 4.20

6 months ago
Hello community. I'm quiet new to Nop and i'm trying to make my first plugin on 4.20. I want to change Product/_AddToCart view. I already include new view in plugin, write new functionality on that page, but now i'm struggle to override Nop view with my plugin view. Thanks in advance!
6 months ago
Hello, jomhur

I think you want to go to "Presentation\Nop.Web\Views\Product" and search for "ProductTemplate.Simple.cshtml" and "ProductTemplate.Grouped.cshtml".
In both cshtml file, you will find "@await Html.PartialAsync("_AddToCart", variant.AddToCart, dataDictAddToCart)".

If you want to replace the view, you can replace that line with your view component.

if you are creating a "IWidgetPlugin" you can call your view component like this:

"@await Component.InvokeAsync("Widget", new { widgetZone = PublicWidgetZones.HomepageTop })"

Just replace the "PublicWidgetZones.HomepageTop" with your WidgetZone Name.

I hope it will help you. Thank You.
6 months ago
jomhur wrote:
Hello community. I'm quiet new to Nop and i'm trying to make my first plugin on 4.20. I want to change Product/_AddToCart view. I already include new view in plugin, write new functionality on that page, but now i'm struggle to override Nop view with my plugin view. Thanks in advance!


You can use View location expander - IViewLocationExpander for override view from plugin.

Get a reference from - nopCommerce > Presentation > Nop.Web.Framework > Themes > ThemeableViewLocationExpander.cs

Hope this would be helpful.
6 months ago
Hi,

If you write 1 Plugin and want to overwrite the file in the View folder. You need to do the following: Add 2 files to your Plugin's Infrastructure folder.



Infrastructure / HomepageCategoriesViewEngine.cs
Infrastructure / NopStartup.cs


--------------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.Components.HomepageCategories.Infrasctructure
{
    /// <summary>
    /// Represents object for the configuring services on application startup
    /// </summary>
    public class NopStartup : INopStartup
    {
        /// <summary>
        /// Add and configure any of the middleware
        /// </summary>
        /// <param name="services">Collection of service descriptors</param>
        /// <param name="configuration">Configuration of the application</param>
        public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
        {
            services.Configure<RazorViewEngineOptions>(options =>
            {
                options.ViewLocationExpanders.Add(new HomepageCategoriesViewEngine());
            });
        }

        /// <summary>
        /// Configure the using of added middleware
        /// </summary>
        /// <param name="application">Builder for configuring an application's request pipeline</param>
        public void Configure(IApplicationBuilder application)
        {
        }

        /// <summary>
        /// Gets order of this startup configuration implementation
        /// </summary>
        public int Order => int.MaxValue;
    }
}

-----------HomepageCategoriesViewEngine.cs-----------

using Microsoft.AspNetCore.Mvc.Razor;
using System.Collections.Generic;
using System.Linq;

namespace Nop.Plugin.Components.HomepageCategories.Infrasctructure
{
  public class HomepageCategoriesViewEngine : IViewLocationExpander
  {
        public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
        {
            if (context.AreaName == null && context.ViewName == "Components/HomepageCategories/Default")
            {
                viewLocations = new[] { "/Plugins/Components.HomepageCategories/Views/PublicInfo.cshtml" }.Concat(viewLocations);
            }

            return viewLocations;
        }

    public void PopulateValues(ViewLocationExpanderContext context)
    {
    }
  }
}

Hope to help you!
4 months ago
Hi,
this solution works great with the default theme. After installing a Theme that he also overwrites the same View; the theme view wins over mine.

In this case, how should you do it?

ciao,
marco

nokia1028 wrote:
Hi,

If you write 1 Plugin and want to overwrite the file in the View folder. You need to do the following: Add 2 files to your Plugin's Infrastructure folder.



Infrastructure / HomepageCategoriesViewEngine.cs
Infrastructure / NopStartup.cs


--------------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.Components.HomepageCategories.Infrasctructure
{
    /// <summary>
    /// Represents object for the configuring services on application startup
    /// </summary>
    public class NopStartup : INopStartup
    {
        /// <summary>
        /// Add and configure any of the middleware
        /// </summary>
        /// <param name="services">Collection of service descriptors</param>
        /// <param name="configuration">Configuration of the application</param>
        public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
        {
            services.Configure<RazorViewEngineOptions>(options =>
            {
                options.ViewLocationExpanders.Add(new HomepageCategoriesViewEngine());
            });
        }

        /// <summary>
        /// Configure the using of added middleware
        /// </summary>
        /// <param name="application">Builder for configuring an application's request pipeline</param>
        public void Configure(IApplicationBuilder application)
        {
        }

        /// <summary>
        /// Gets order of this startup configuration implementation
        /// </summary>
        public int Order => int.MaxValue;
    }
}

-----------HomepageCategoriesViewEngine.cs-----------

using Microsoft.AspNetCore.Mvc.Razor;
using System.Collections.Generic;
using System.Linq;

namespace Nop.Plugin.Components.HomepageCategories.Infrasctructure
{
  public class HomepageCategoriesViewEngine : IViewLocationExpander
  {
        public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
        {
            if (context.AreaName == null && context.ViewName == "Components/HomepageCategories/Default")
            {
                viewLocations = new[] { "/Plugins/Components.HomepageCategories/Views/PublicInfo.cshtml" }.Concat(viewLocations);
            }

            return viewLocations;
        }

    public void PopulateValues(ViewLocationExpanderContext context)
    {
    }
  }
}

Hope to help you!
4 months ago
You need to theme path in view engine file (HomepageCategoriesViewEngine.cs)

Here is updated code



using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Razor;
using Nop.Web.Framework;
using Nop.Web.Framework.Themes;

namespace Nop.Plugin.Components.HomepageCategories.Infrasctructure
{
    public class HomepageCategoriesViewEngine : IViewLocationExpander
    {
        private const string THEME_KEY = "nop.themename";

        public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
        {
            #region public side

            if (context.Values.TryGetValue(THEME_KEY, out string theme))
            {
                if (context.ViewName == "Components/HomepageCategories/Default")
                {
                    viewLocations = new[] {
                        $"~/Plugins/Components.HomepageCategories/Themes/"+theme+"/Views/Shared/PublicInfo.cshtml",
                        $"~/Plugins/Components.HomepageCategories/Views/PublicInfo.cshtml"
                    }
                    .Concat(viewLocations);
                }
              
            }

            #endregion

            return viewLocations;
        }

        public void PopulateValues(ViewLocationExpanderContext context)
        {
            if (context.AreaName?.Equals(AreaNames.Admin) ?? false)
                return;

            var themeContext = (IThemeContext)context.ActionContext.HttpContext.RequestServices.GetService(typeof(IThemeContext));
            context.Values[THEME_KEY] = themeContext.WorkingThemeName;
        }

    }
}