Adding or modifying category template

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.
12 years ago
I would like to create a hybrid category template using the existing templates; with just a text link for the category but an image for products in that category - I don't want to have to find an image for every category.

So I created a new ascx in the Templates/Categories folder and added the template, updated my categories to use the new template id and... it doesn't work with this error:
Parser Error Message: Could not load type 'NopSolutions.NopCommerce.Web.Templates.Categories.ProductsInLines3'.
Which, looking about suggests I need to recompile the site - which seems a bit much considering I just wanna adjust how category pages are displayed.

The site is already deployed and I don't want to muck up future upgrades I'm concerned that if I have to recompile the site now, in order to get my new template to work, that when 2.0 is released I'll have to remember to recompile against that version and forever more.

I have recompiled the site (downloaded the source) with my template and there are no errors - so I'm pretty confident my page works. But the live site was deployed using Microsoft Web Platform Installer and I really don't like the idea of redeploying the whole site just for a single template.

This is my aspx:

<%@ Control Language="C#" AutoEventWireup="true" 
    Inherits="NopSolutions.NopCommerce.Web.Templates.Categories.ProductsInLines3" CodeBehind="ProductsInLines3.ascx.cs" %>
    
<%@ Register TagPrefix="nopCommerce" TagName="PriceRangeFilter" Src="~/Modules/PriceRangeFilter.ascx" %>
<%@ Register TagPrefix="nopCommerce" TagName="ProductSpecificationFilter" Src="~/Modules/ProductSpecificationFilter.ascx" %>

<%@ Register TagPrefix="nopCommerce" TagName="ProductBox2" Src="~/Modules/ProductBox2.ascx" %>
<%@ Register TagPrefix="nopCommerce" TagName="ProductBox1" Src="~/Modules/ProductBox1.ascx" %>


<div class="category-page">
    <div class="page-title">
        <h1><asp:Literal runat="server" ID="lName"></asp:Literal></h1>
    </div>
    <div class="clear">
    </div>
    <div class="category-description">
        <asp:Literal runat="server" ID="lDescription"></asp:Literal>
    </div>
    <div class="clear">
    </div>
    <div class="sub-category-list">
        <asp:Repeater ID="rptrSubCategories" runat="server" OnItemDataBound="rptrSubCategories_ItemDataBound">
            <ItemTemplate>
                <asp:HyperLink ID="hlCategory" runat="server" Text='<%#Server.HtmlEncode(Eval("LocalizedName").ToString()) %>' />
            </ItemTemplate>
            <SeparatorTemplate>
                <br />
            </SeparatorTemplate>
        </asp:Repeater>
    </div>
    <div class="clear">
    </div>
   <asp:Panel runat="server" ID="pnlSorting" CssClass="product-sorting">
        <%=GetLocaleResourceString("ProductSorting.SortBy")%>
        <asp:DropDownList ID="ddlSorting" runat="server" OnSelectedIndexChanged="ddlSorting_SelectedIndexChanged"
            AutoPostBack="true" />
    </asp:Panel>
    <div class="clear">
    </div>
    <asp:Panel runat="server" ID="pnlFilters" CssClass="product-filters">
        <div class="filter-title">
            <asp:Label runat="server" ID="lblProductFilterTitle">
                <%=GetLocaleResourceString("Products.FilterOptionsTitle")%>
            </asp:Label>
        </div>
        <div class="filter-item">
            <nopcommerce:pricerangefilter id="ctrlPriceRangeFilter" runat="server" />
        </div>
        <div class="filter-item">
            <nopcommerce:productspecificationfilter id="ctrlProductSpecificationFilter" runat="server" />
        </div>
    </asp:Panel>
    <div class="clear">
    </div>
    <div class="product-list1">
        <asp:ListView ID="lvCatalog" runat="server">
            <LayoutTemplate>
                <asp:PlaceHolder ID="itemPlaceholder" runat="server"></asp:PlaceHolder>
            </LayoutTemplate>
            <ItemTemplate>
                <div class="item-box">
                    <nopcommerce:productbox2 id="ctrlProductBox" product='<%# Container.DataItem %>'
                        runat="server" />
                </div>
            </ItemTemplate>
        </asp:ListView>
        <div class="clear">
        </div>
        <div class="product-pager">
            <nopcommerce:pager runat="server" id="catalogPager" firstbuttontext="<% $NopResources:Pager.First %>"
                lastbuttontext="<% $NopResources:Pager.Last %>" nextbuttontext="<% $NopResources:Pager.Next %>"
                previousbuttontext="<% $NopResources:Pager.Previous %>" currentpagetext="Pager.CurrentPage" />
        </div>
    </div>
</div>


and this is the code behind:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml;
using NopSolutions.NopCommerce.BusinessLogic;
using NopSolutions.NopCommerce.BusinessLogic.Categories;
using NopSolutions.NopCommerce.BusinessLogic.Configuration.Settings;
using NopSolutions.NopCommerce.BusinessLogic.Directory;
using NopSolutions.NopCommerce.BusinessLogic.Infrastructure;
using NopSolutions.NopCommerce.BusinessLogic.Localization;
using NopSolutions.NopCommerce.BusinessLogic.Media;
using NopSolutions.NopCommerce.BusinessLogic.Products;
using NopSolutions.NopCommerce.BusinessLogic.SEO;
using NopSolutions.NopCommerce.Common.Utils;

namespace NopSolutions.NopCommerce.Web.Templates.Categories
{
    public partial class ProductsInLines3 : BaseNopFrontendUserControl
    {
        #region Protected Methods

        protected void BindData()
        {
            var category = this.CategoryService.GetCategoryById(this.CategoryId);

            lName.Text = Server.HtmlEncode(category.LocalizedName);
            lDescription.Text = category.LocalizedDescription;

            //subcategories
            var subCategories = this.CategoryService.GetAllCategoriesByParentCategoryId(this.CategoryId);
            if (subCategories.Count > 0)
            {
                rptrSubCategories.DataSource = subCategories;
                rptrSubCategories.DataBind();
            }
            else
                rptrSubCategories.Visible = false;

            //price ranges
            this.ctrlPriceRangeFilter.PriceRanges = category.PriceRanges;

            //page size
            int totalRecords = 0;
            int pageSize = 10;
            if (category.PageSize > 0)
            {
                pageSize = category.PageSize;
            }

            //price ranges
            decimal? minPrice = null;
            decimal? maxPrice = null;
            decimal? minPriceConverted = null;
            decimal? maxPriceConverted = null;
            if (ctrlPriceRangeFilter.SelectedPriceRange != null)
            {
                minPrice = ctrlPriceRangeFilter.SelectedPriceRange.From;
                if (minPrice.HasValue)
                {
                    minPriceConverted = this.CurrencyService.ConvertCurrency(minPrice.Value, NopContext.Current.WorkingCurrency, this.CurrencyService.PrimaryStoreCurrency);
                }

                maxPrice = ctrlPriceRangeFilter.SelectedPriceRange.To;
                if (maxPrice.HasValue)
                {
                    maxPriceConverted = this.CurrencyService.ConvertCurrency(maxPrice.Value, NopContext.Current.WorkingCurrency, this.CurrencyService.PrimaryStoreCurrency);
                }
            }

            //specification filter
            var psoFilterOption = ctrlProductSpecificationFilter.GetAlreadyFilteredSpecOptionIds();

            //sorting
            ProductSortingEnum orderBy = ProductSortingEnum.Position;
            if (this.SettingManager.GetSettingValueBoolean("Common.AllowProductSorting"))
            {
                CommonHelper.SelectListItem(this.ddlSorting, CommonHelper.QueryStringInt("orderby"));
                orderBy = (ProductSortingEnum)Enum.ToObject(typeof(ProductSortingEnum), int.Parse(ddlSorting.SelectedItem.Value));
            }

            //featured products are not supported by this template
            //that's hwhy we load all featured and non-featured products
            var productCollection = this.ProductService.GetAllProducts(this.CategoryId,
                0, 0, null, minPriceConverted, maxPriceConverted,
                string.Empty, false, pageSize, this.CurrentPageIndex,
                psoFilterOption, orderBy, out totalRecords);

            if (productCollection.Count > 0)
            {
                this.catalogPager.PageSize = pageSize;
                this.catalogPager.TotalRecords = totalRecords;
                this.catalogPager.PageIndex = this.CurrentPageIndex;

                this.lvCatalog.DataSource = productCollection;
                this.lvCatalog.DataBind();
            }
            else
            {
                this.lvCatalog.Visible = false;
                this.pnlSorting.Visible = false;
            }
        }

        protected void ddlSorting_SelectedIndexChanged(object sender, EventArgs e)
        {
            string url = CommonHelper.GetThisPageUrl(true);
            url = CommonHelper.ModifyQueryString(url, "orderby=" + ddlSorting.SelectedItem.Value, null);
            Response.Redirect(url);
        }

        protected void dlSubCategories_ItemDataBound(object sender, DataListItemEventArgs e)
        {
            if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            {
                var category = e.Item.DataItem as Category;
                string categoryURL = SEOHelper.GetCategoryUrl(category);

                var hlImageLink = e.Item.FindControl("hlImageLink") as HyperLink;
                if (hlImageLink != null)
                {
                    hlImageLink.ImageUrl = this.PictureService.GetPictureUrl(category.PictureId, this.SettingManager.GetSettingValueInteger("Media.Category.ThumbnailImageSize", 125), true);
                    hlImageLink.NavigateUrl = categoryURL;
                    hlImageLink.ToolTip = String.Format(GetLocaleResourceString("Media.Category.ImageLinkTitleFormat"), category.LocalizedName);
                    hlImageLink.Text = String.Format(GetLocaleResourceString("Media.Category.ImageAlternateTextFormat"), category.LocalizedName);
                }

                var hlCategory = e.Item.FindControl("hlCategory") as HyperLink;
                if (hlCategory != null)
                {
                    hlCategory.NavigateUrl = categoryURL;
                    hlCategory.ToolTip = String.Format(GetLocaleResourceString("Media.Category.ImageLinkTitleFormat"), category.LocalizedName);
                    hlCategory.Text = Server.HtmlEncode(category.LocalizedName);
                }
            }
        }

        protected void FillDropDowns()
        {
            if (this.SettingManager.GetSettingValueBoolean("Common.AllowProductSorting"))
            {
                ddlSorting.Items.Clear();

                var ddlSortPositionItem = new ListItem(GetLocaleResourceString("ProductSorting.Position"), ((int)ProductSortingEnum.Position).ToString());
                ddlSorting.Items.Add(ddlSortPositionItem);

                var ddlSortNameItem = new ListItem(GetLocaleResourceString("ProductSorting.Name"), ((int)ProductSortingEnum.Name).ToString());
                ddlSorting.Items.Add(ddlSortNameItem);

                var ddlSortPriceItem = new ListItem(GetLocaleResourceString("ProductSorting.Price"), ((int)ProductSortingEnum.Price).ToString());
                ddlSorting.Items.Add(ddlSortPriceItem);

            }
            else
            {
                pnlSorting.Visible = false;
            }
        }

        protected void lvCatalog_ItemDataBound(object sender, ListViewItemEventArgs e)
        {
            if (e.Item.ItemType == ListViewItemType.DataItem)
            {
                var dataItem = e.Item as ListViewDataItem;
                if (dataItem != null)
                {
                    var product = dataItem.DataItem as Product;
                    if (product != null)
                    {
                        var hlProduct = dataItem.FindControl("hlProduct") as HyperLink;
                        hlProduct.NavigateUrl = SEOHelper.GetProductUrl(product);
                    }
                }
            }
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            ctrlPriceRangeFilter.ExcludedQueryStringParams = catalogPager.QueryStringProperty;

            ctrlProductSpecificationFilter.ExcludedQueryStringParams = catalogPager.QueryStringProperty;
            ctrlProductSpecificationFilter.CategoryId = this.CategoryId;

            ctrlProductSpecificationFilter.ReservedQueryStringParams = "CategoryId,";
            ctrlProductSpecificationFilter.ReservedQueryStringParams += "orderby,";
            ctrlProductSpecificationFilter.ReservedQueryStringParams += ctrlPriceRangeFilter.QueryStringProperty;
            ctrlProductSpecificationFilter.ReservedQueryStringParams += ",";
            ctrlProductSpecificationFilter.ReservedQueryStringParams += catalogPager.QueryStringProperty;
        }

        protected override void OnPreRender(EventArgs e)
        {
            this.pnlFilters.Visible = ctrlPriceRangeFilter.Visible || ctrlProductSpecificationFilter.Visible;
            base.OnPreRender(e);
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                FillDropDowns();
                BindData();
            }
        }

        protected void rptrSubCategories_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
            {
                var category = e.Item.DataItem as Category;
                var hlCategory = e.Item.FindControl("hlCategory") as HyperLink;
                if (hlCategory != null)
                {
                    hlCategory.NavigateUrl = SEOHelper.GetCategoryUrl(category);
                }
            }
        }

        #endregion

    }
}
12 years ago
Using the WPI assumes that you won't need to compile anything. You can do a small hack however...

Create a new class library, add reference to Nop.BusinessLogic, add a new class file called ProductsInGrid3, inherit from user control. Copy the code from your current code behind and designer into the new class file, the. Specify that the .ascx inherits from the user control located in your class library.

Then all you have to do is publish the .ascx and the class library (to bin/).
12 years ago
theonlylawislove wrote:
Using the WPI assumes that you won't need to compile anything. You can do a small hack however...

Create a new class library, add reference to Nop.BusinessLogic, add a new class file called ProductsInGrid3, inherit from user control. Copy the code from your current code behind and designer into the new class file, the. Specify that the .ascx inherits from the user control located in your class library.

Then all you have to do is publish the .ascx and the class library (to bin/).

Nice - good tip!!
Will give that a go
12 years ago
This approach works - for anyone finding this and trying to do the same thing it is slightly more complex than described, but really only a case of referencing the appropriate dlls from nopCommerce.
I needed Nop.BusinessLogic.dll, Nop.Common.dll, Nop.Controls.dll and NopCommerceStore.dll

Eventually my class library compiled, I referenced it in the main website and updated ProductsInLines3 to inherit from that and I'm golden ;)
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.