Let’s imagine that we have multiple types of articles with multiple page layouts and we want to call Add a page dialog for each of them.
The problem is in SharePoint OOTB CreatePublishingPageDialog.aspx page which is called when you choose Add a page from Site Actions menu. With this one you could create just one type (content type) of article at the time with specific page layout. It is defined in Site Settingsunder Page layouts and site templates within Look and Feel category.
One of the solutions is to create custom CreatePublishingPageDialog.aspx page.
So, lets start. Inside of your WSP solution create new Application Page named CreatePublishingPageDialog.aspx.
Then go to HIVE location on your SharePoint server and find OOTB CreatePublishingPage.aspx file inside of TEMPLATE\LAYOUTS\ subfolder (for example “16\TEMPLATE\LAYOUTS\CreatePublishingPageDialog.aspx”).
Copy content of this file to your newly created Application Page.
Add this line as first line of your CreatePublishingPageDialog.aspx file:
<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
And replace this line …
<%@ Page Language="C#" DynamicMasterPageFile="~masterurl/default.master" Inherits="Microsoft.SharePoint.Publishing.Internal.CodeBehind.CreatePublishingPageDialog15" %>
… with this one:
<%@ Page Language="C#" DynamicMasterPageFile="~masterurl/default.master" CodeBehind="CreatePublishingPageDialog.aspx.cs" Inherits="Xnet.SP.Test.Layouts.Xnet.SP.Test.CreatePublishingPageDialog" %>
Then go to PlaceHolderMain and add this lines of code below TextBox with id nameInput:
<div class="ms-core-form-line">
<table border="0">
<tr>
<td>
<span class="ms-metadata ms-floatLeft ms-displayInlineBlock ms-verticalAlignBaseline">
<SharePoint:EncodedLiteral runat="server" text="News type" EncodeMethod='HtmlEncode'/>
</span>
</td>
<td>
<asp:DropDownList ID="ddlNewsType" runat="server"></asp:DropDownList>
</td>
</tr>
</table>
</div>
Go to code-behind of your Application Page (CreatePublishingPageDialog.aspx.cs file) and change LayoutsPageBase inherited class with Microsoft.SharePoint.Publishing.Internal.CodeBehind.CreatePublishingPageDialog15:
public partial class CreatePublishingPageDialog : Microsoft.SharePoint.Publishing.Internal.CodeBehind.CreatePublishingPageDialog15
Then change signature of OnLoad method with override property:
protected override void OnLoad(EventArgs e)
Add this code into OnLoad method:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
folderUrl = SPRequestParameterUtility.GetValue<string>(base.Request, "RootFolder", SPRequestParameterSource.QueryStringValues);
SPWeb web = SPContext.Current.Web;
SPFieldChoice field = (SPFieldChoice)web.Fields.GetFieldByInternalName("NewsType");
if (!Page.IsPostBack)
{
ddlNewsType.Items.Clear();
field.Choices.Cast<string>().ToList().ForEach(x => ddlNewsType.Items.Add(x));
}
else
{
originalRequestedName = nameInput.Text;
if (originalRequestedName.EndsWith(".aspx", StringComparison.OrdinalIgnoreCase))
{
originalRequestedName = originalRequestedName.Remove(checked(originalRequestedName.Length - ".aspx".Length));
}
nameInput.Text = nameInput.Text.Replace(' ', '-');
}
}
As you can see in code above drop down is populated with choices from NewsType choice field.
In the other hand (in post back time) we modify nameInput TextBox field.
Then we have to hides inherited CreateButton_Click method with a new one below:
protected new void CreateButton_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
SPLongOperation.Begin(delegate (SPLongOperation longOperation)
{
SPWeb web = SPContext.Current.Web;
PublishingWeb currentPublishingWeb = PublishingWeb.GetPublishingWeb(web);
PublishingPage publishingPage = null;
SPFolder sPFolder = null;
if (!string.IsNullOrEmpty(folderUrl))
{
sPFolder = currentPublishingWeb.Web.GetFolder(folderUrl);
if (!sPFolder.Exists)
{
string url = Helper.ConcatUrls(folderUrl, nameInput.Text);
SPUtility.CreateParentFoldersForFile(currentPublishingWeb.PagesList, url, false);
sPFolder = currentPublishingWeb.Web.GetFolder(folderUrl);
}
}
PageLayout pageLayout = null;
string text = base.Request.QueryString.Get("PLUrl");
if (string.IsNullOrEmpty(text))
{
pageLayout = currentPublishingWeb.DefaultPageLayout;
}
else
{
try
{
pageLayout = new PageLayout(base.Web.GetListItem(text));
}
catch (Exception)
{
Logger.ToLog(new Exception(string.Format("Unable to create PageLayout from listitem of path : {0}", text)));
pageLayout = currentPublishingWeb.DefaultPageLayout;
}
}
publishingPage = SPHelper.CreatePublishingPage(currentPublishingWeb, nameInput.Text, pageLayout, sPFolder, false);
if (publishingPage != null && originalRequestedName != null)
{
publishingPage.Title = originalRequestedName;
publishingPage.ListItem["NewsType"] = ddlNewsType.SelectedValue;
publishingPage.Update();
}
string text2 = SPHttpUtility.UrlPathEncode(publishingPage.ListItem.File.ServerRelativeUrl, false);
string FinishUrl = SPHelper.DesignModeUrl(text2);
if (!string.IsNullOrEmpty(base.Request.QueryString.Get("IsDlg")))
{
if (base.Request.QueryString["shouldRedirectPage"] == "0")
{
string scriptLiteralToEncode = SPHelper.ConvertToAbsoluteUrl(FinishUrl, currentPublishingWeb.Web.Site, true);
longOperation.EndScript("window.frameElement.commitPopup('" + SPHttpUtility.EcmaScriptStringLiteralEncode(scriptLiteralToEncode) + "');");
}
else
{
longOperation.EndScript("window.frameElement.navigateParent('" + SPHttpUtility.EcmaScriptStringLiteralEncode(FinishUrl) + "');");
}
}
else
{
longOperation.End(FinishUrl);
}
});
}
}
As you can see in code above we get specific Page Layout from PLUrl query string parameter. You can do the same for Content Type if you want. In the other hand you could give user option to select specific Page Layout or Content Type from drop down.
After we have page layout, we could create new Publishing Page with CreatePublishingPage method from SPHelper static class (check for SPHelper and Helper static classes on my GitHub via link at the end of thic blog post).
In the end we fill NewsType field of our Publishing Page with selected value from ddlNewsType drop down.
The last thing we have to do is to create Site Actions menu items. We could do this with MenuItemTemplate via Master Page or with CustomAction via Module.
Here is example with MenuItemTemplate:
<SharePoint:MenuItemTemplate runat="server" ID="MenuItem_CreateNews"
Text="Create News"
Description="Create News"
ClientOnClickNavigateUrl="javascript: SP.SOD.execute('sp.ui.dialog.js', 'SP.UI.ModalDialog.showModalDialog', { url: 'http://test/_layouts/15/Xnet.SP.Test/CreatePublishingPageDialog.aspx?IsDlg=1&PLUrl=http://test/_catalogs/masterpage/NewsPL.aspx' });"
MenuGroupId="400"
Sequence="100"
PermissionsString="AddAndCustomizePages"
PermissionMode="All" />
And example with CustomAction:
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction
Id="CreateNewsCA"
GroupId="SiteActions"
Location="Microsoft.SharePoint.StandardMenu"
Title="Create News"
Rights="AddAndCustomizePages"
Sequence="0">
<UrlAction Url="javascript: SP.SOD.execute('sp.ui.dialog.js', 'SP.UI.ModalDialog.showModalDialog', { url: 'http://test/_layouts/15/Xnet.SP.Test/CreatePublishingPageDialog.aspx?IsDlg=1&PLUrl=http://test/_catalogs/masterpage/NewsPL.aspx' });"/>
</CustomAction>
</Elements>