CMS Information Pages (Sample Code included)

11 years ago
First off I want to say how impressed I was with NopCommerce. I think it is one of the best Open Source shopping carts I have come across. So well done!!!

I wanted to see how easy it was to make the 3 info pages Content Managed. However I did not like the Provider model as I felt the Data Layer was a bit excessive and repeated. That is by no means a criticism; I can see why you did it, however I wanted to use Linq-To-Sql. So here goes, 3 pages content managed in half an hour.

First the Database scripts.

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Nop_PageTemplateLocalized](
  [PageTemplateLocalizedId] [int] IDENTITY(1,1) NOT NULL,
  [PageTemplateId] [int] NOT NULL,
  [LanguageId] [int] NOT NULL,
  [Body] [nvarchar](max) NOT NULL,
CONSTRAINT [PK_Nop_PageTemplateLocalized] PRIMARY KEY CLUSTERED
(
  [PageTemplateLocalizedId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE UNIQUE NONCLUSTERED INDEX [IX_Nop_PageTemplateLocalized] ON [dbo].[Nop_PageTemplateLocalized]
(
  [LanguageId] ASC,
  [PageTemplateId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

SET IDENTITY_INSERT [dbo].[Nop_PageTemplate] ON
INSERT INTO [Nop_PageTemplate] ([PageTemplateId], [Name]) VALUES (1, 'ConditionsOfUse')
INSERT INTO [Nop_PageTemplate] ([PageTemplateId], [Name]) VALUES (2, 'PrivacyNotice')
INSERT INTO [Nop_PageTemplate] ([PageTemplateId], [Name]) VALUES (3, 'Shipping&Returns')
SET IDENTITY_INSERT [dbo].[Nop_PageTemplate] OFF
GO

SET IDENTITY_INSERT [dbo].[Nop_PageTemplateLocalized] ON
INSERT INTO [dbo].[Nop_PageTemplateLocalized] ([PageTemplateLocalizedId],[PageTemplateId],[LanguageId],[Body]) VALUES (1,1,1,'')
INSERT INTO [dbo].[Nop_PageTemplateLocalized] ([PageTemplateLocalizedId],[PageTemplateId],[LanguageId],[Body]) VALUES (2,2,1,'')
INSERT INTO [dbo].[Nop_PageTemplateLocalized] ([PageTemplateLocalizedId],[PageTemplateId],[LanguageId],[Body]) VALUES (3,3,1,'')
SET IDENTITY_INSERT [dbo].[Nop_PageTemplateLocalized] OFF
GO


I have followed the Nop naming standard as Linq allows me to have my entities named nicely anyway.

So next, create a DBML file and drag those two tables into it, add an Association in the dbml between the FK and the PK and that is the whole data layer. Next lets create a Controller for this data layer.

namespace Simian.Controllers
{
  public static class PageTemplateController
  {
    private static QE2StampsDataContext _db;

    static PageTemplateController()
    {
      _db = new QE2StampsDataContext();
    }

    /// <summary>
    /// Gets all page templates.
    /// </summary>
    /// <returns></returns>
    public static IQueryable GetAllPageTemplates()
    {
      return from pt in _db.PageTemplates
        select pt;
    }

    /// <summary>
    /// Retrieves the page template.
    /// </summary>
    /// <param name="pageTemplateId">The page template id.</param>
    /// <param name="languageId">The language id.</param>
    /// <returns></returns>
    public static PageTemplateLocalized RetrievePageTemplate(int pageTemplateId, int languageId)
    {
      return (from ptl in _db.PageTemplateLocalizeds
            where ptl.PageTemplateId == pageTemplateId
            && ptl.LanguageId == languageId
            select ptl).SingleOrDefault();
    }

    /// <summary>
    /// Updates the page template.
    /// </summary>
    /// <param name="pageTemplateId">The page template id.</param>
    /// <param name="languageId">The language id.</param>
    /// <param name="body">The body.</param>
    public static void UpdatePageTemplate(int pageTemplateId, int languageId, string body)
    {
      PageTemplateLocalized pageTemplate = RetrievePageTemplate(pageTemplateId, languageId);
      pageTemplate.Body = body;
      _db.SubmitChanges();
    }

    /// <summary>
    /// Inserts the page template.
    /// </summary>
    /// <param name="pageTemplateId">The page template id.</param>
    /// <param name="languageId">The language id.</param>
    /// <param name="body">The body.</param>
    public static void InsertPageTemplate(int pageTemplateId, int languageId, string body)
    {
      PageTemplateLocalized pageTemplate = new PageTemplateLocalized()
        {
          PageTemplateId = pageTemplateId,
          LanguageId = languageId,
          Body = body
        };

      _db.PageTemplateLocalizeds.InsertOnSubmit(pageTemplate);
      _db.SubmitChanges();
    }

    /// <summary>
    /// Deletes the specified page template id.
    /// </summary>
    /// <param name="pageTemplateId">The page template id.</param>
    /// <param name="languageId">The language id.</param>
    public static void Delete(int pageTemplateId, int languageId)
    {
      PageTemplateLocalized pageTemplate = RetrievePageTemplate(pageTemplateId, languageId);
      _db.PageTemplateLocalizeds.DeleteOnSubmit(pageTemplate);
      _db.SubmitChanges();
    }

    /// <summary>
    /// Retrieves the name of the page template.
    /// </summary>
    /// <param name="pageTemplateId">The page template id.</param>
    /// <returns></returns>
    public static string RetrievePageTemplateName(int pageTemplateId)
    {
      return (from pt in _db.PageTemplates
          where pt.PageTemplateId == pageTemplateId
          select pt).Single().Name;
    }

    /// <summary>
    /// Retrieves the page template.
    /// </summary>
    /// <param name="templateName">Name of the template.</param>
    /// <param name="languageId">The language id.</param>
    /// <returns></returns>
    public static PageTemplateLocalized RetrievePageTemplate(string templateName, int languageId)
    {
      return (from ptl in _db.PageTemplateLocalizeds
          where ptl.PageTemplate.Name == templateName
          && ptl.LanguageId == languageId
          select ptl).SingleOrDefault();
    }
  }
}


Next we need to create two admin pages for this, so I made a copy of the Administration_MessageTemplates and Administration_MessageTemplateDetails pages. I'm not going to give you the aspx as I am sure you can work that out, but the important code behind bits are

a) the page that gets a list of the pages
        protected void BindGrid()
        {
      gvPageTemplates.DataSource = PageTemplateController.GetAllPageTemplates();
      gvPageTemplates.DataBind();
        }


b) the details page (Please note I always use Id and not ID for may parameters as I am an FXCop freak!)
    public partial class Administration_PageTemplateDetails : BaseNopAdministrationPage
    {
        private void BindData()
        {
            Language language = LanguageManager.GetByLanguageID(LanguageId);
      PageTemplateLocalized pageTemplate = PageTemplateController.RetrievePageTemplate(PageTemplateId, LanguageId);

      if (language != null)
      {
        lblLanguage.Text = language.Name;

        if (pageTemplate != null)
        {
          txtBody.Value = pageTemplate.Body;
          lblTemplate.Text = pageTemplate.PageTemplate.Name;
        }
        else
        {
          lblTemplate.Text = PageTemplateController.RetrievePageTemplateName(PageTemplateId);
          SaveButton.Text = "Add";
          DeleteButton.Visible = false;
        }
      }
      else
                Response.Redirect("PageTemplates.aspx");
        }

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

        protected void SaveButton_Click(object sender, EventArgs e)
        {
            if (Page.IsValid)
            {
                try
                {
          PageTemplateLocalized pageTemplate = PageTemplateController.RetrievePageTemplate(PageTemplateId, LanguageId);
          if (pageTemplate != null)
          {
            PageTemplateController.UpdatePageTemplate(PageTemplateId, LanguageId, txtBody.Value);
            Response.Redirect("PageTemplateDetails.aspx?PageTemplateId=" + PageTemplateId.ToString() + "&LanguageId=" + LanguageId.ToString());
          }
          else
          {
            PageTemplateController.InsertPageTemplate(PageTemplateId, LanguageId, txtBody.Value);
            Response.Redirect("PageTemplateDetails.aspx?PageTemplateID=" + PageTemplateId.ToString() + "&LanguageId=" + LanguageId.ToString());
          }
        }
                catch (Exception exc)
                {
                    ProcessException(exc);
                }
            }
        }

        protected void DeleteButton_Click(object sender, EventArgs e)
        {
            try
            {
        PageTemplateController.Delete(PageTemplateId, LanguageId);
                Response.Redirect("MessageTemplates.aspx");
            }
            catch (Exception exc)
            {
                ProcessException(exc);
            }
        }

        public int PageTemplateId
        {
            get
            {
                return CommonHelper.QueryStringInt("PageTemplateId");
            }
        }

        public int LanguageId
        {
            get
            {
                return CommonHelper.QueryStringInt("LanguageId");
            }
        }
    }


OK - so now we have an Admin page for our CMS. Remember to add this page to your site map for the menu. I put mine under the CMS features

      <siteMapNode title="Page templates" url="~/Administration/PageTemplates.aspx"></siteMapNode>


Nearly there, make the pages read from the controller. Here I have derived the NopBasePage so that I can upgrade in the future.

public class SimianPage : BaseNopPage
{
  /// <summary>
  /// Gets the page template.
  /// </summary>
  /// <param name="templateName">Name of the template.</param>
  /// <returns></returns>
  protected String GetPageTemplate(string templateName)
  {
    Language language = NopContext.Current.WorkingLanguage;
    PageTemplateLocalized template = PageTemplateController.RetrievePageTemplate(templateName, language.LanguageID);

    if (template != null)
      return template.Body;
    else
      return String.Empty;
  }
}


OK, last thing. Make my three pages derive from my new base page, e.g.

public partial class PrivacyInfoPage : SimianPage


and now the aspx will look like this

<%@ Page Language="C#" MasterPageFile="~/main.master" AutoEventWireup="true" CodeFile="PrivacyInfo.aspx.cs"
    Inherits="NopSolutions.NopCommerce.Web.PrivacyInfoPage" %>

<asp:Content ID="Content1" ContentPlaceHolderID="cph1" runat="Server">
    <div class="htmlcontent">
        <div class="htmlcontent-title">
            <%=GetLocaleResourceString("Content.PrivacyNotice")%>
        </div>
        <div class="clear">
        </div>
        <div class="htmlcontent-body">
            <%=GetPageTemplate("PrivacyNotice")%>
        </div>
    </div>
</asp:Content>


Now you have Content managed pages for the Shipping details
11 years ago
Hi, thanks for your contribution.

CMS features are already implemented and will be available in the next release.
11 years ago
nopCommerce team | retroviz wrote:
Hi, thanks for your contribution.

CMS features are already implemented and will be available in the next release.


When will be available?
11 years ago
We do not yet know the date of the next release.