After finding Simon Dingley's SO post on "Umbraco 6: How to put newly created node on top" I've tried to implement the sorting but I think things have changed enough that this doesn't seem to actually work and the new node is placed at the bottom of the list of any siblings instead of at the top where I need it to be?
Also, the duplicate check seems to be failing as multiple nodes are being created at different levels at different times if anyone can see where that's wrong?
Here's an image as an example of the replication issue:
If the nodes are manually sorted to put the module manager at the top - the duplication doesn't happen of course as the "found" flag is triggered immediately in the loop but then is ignored as it loops through the children?
Here's the latest code:
using System;using System.Diagnostics;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
namespace NG.USK.Helpers
{
/// <summary>
/// Check for a child page element for each of the main parent document types to enable the usage of the individual functionality module plugins
/// </summary>
public class CreatePageElements : ApplicationEventHandler
{
public CreatePageElements()
{
ContentService.Saved += ContentService_Saved;
}
private static void ContentService_Saved(IContentService sender, SaveEventArgs<IContent> args)
{
foreach (
var node in
args.SavedEntities.Where(
node =>
node.ContentType.Alias.InvariantEquals("NG_USK_Homepage") ||
node.ContentType.Alias.InvariantEquals("NG_USK_StandardPage") ||
node.ContentType.Alias.InvariantEquals("NG_USK_StandardPageChild") ||
node.ContentType.Alias.InvariantEquals("NG_USK_NewsArticle") ||
node.ContentType.Alias.InvariantEquals("NG_USK_Downloads")
)
)
{
try
{
if (!node.Children().Any())
{
MakePageElements(node);
}
else
{
var ignore = false;
foreach ( var child in node.Children())
{
if (child.ContentType.Alias.InvariantEquals("NG_USK__PageElements"))
{
ignore = true;
}
if (ignore == false)
{
MakePageElements(node);
}
}
}
}
catch (Exception err)
{
// Get stack trace for the exception with source file information
var st = new StackTrace(err, true);
// Get the top stack frame
var frame = st.GetFrame(0);
// Get the line number from the stack frame
var line = frame.GetFileLineNumber();
LogHelper.Warn(typeof(CreatePageElements), "ERROR ON: ContentService_Saved - " + node.ContentType.Alias + " ~ " + err.Message + "[" + line + "]:" + st);
}
}
}
private static void MakePageElements(IContent node)
{
if (
node.ContentType.Alias.InvariantEquals("NG_USK__AutoRedirect") ||
node.ContentType.Alias.InvariantEquals("NG_USK_LandingPage")
)
{
return;
}
var nodeName = node.Name;
var pageModuleName = nodeName + " Modules";
var cs = ApplicationContext.Current.Services.ContentService;
var elementsNode = cs.CreateContent(pageModuleName, node.Id, "NG_USK__PageElements");
//get the new node's parent
var parentNode = elementsNode.Parent();
//Check if parentNode.Children is greater than just the new elementNode to squish the "Sequence contains no elements" error
if (parentNode.Children().Count() > 1)
{
//move the node to the first child: <-- THIS IS WHERE IT FALLS OVER!!!!
elementsNode.SortOrder = parentNode.Children().OrderBy(n => n.SortOrder).First().SortOrder - 1;
}
else
{
elementsNode.SortOrder = 0;
}
//Get this value again for logging:
var hider = string.Empty;
//Make sure the element has the NaviHide property available
if (elementsNode.HasProperty("umbracoNaviHide"))
{
//tell it to have the NaviHide Property set to true:
elementsNode.SetValue("umbracoNaviHide", true);
//Get this value again for logging:
hider = elementsNode.GetValue<string>("umbracoNaviHide") == "0" ? "hide" : "show";
}
//Log this to the TraceLog
LogHelper.Info(typeof(CreatePageElements), "DETAILS ON: " + elementsNode.Name + " is now the " + elementsNode.SortOrder + " child of " + parentNode.Name + " and set to " + hider);
//save and publish
cs.SaveAndPublishWithStatus(elementsNode);
}
}
}
void ContentService_Saved(IContentService sender, Umbraco.Core.Events.SaveEventArgs<IContent> e)
{
foreach (var content in e.SavedEntities
//Check if the content item type has a specific alias
// .Where(c => c.ContentType.Alias.InvariantEquals("MyContentType"))
//Check if it is a new item
.Where(c => c.IsNewEntity()))
{
// reference the content service
var contentService = ApplicationContext.Current.Services.ContentService;
// get the sibling nodes but not the one that has just been saved, into a list
var siblingContentItems = content.Parent().Children().Where(f => f.Id != content.Id).ToList();
// add the one being saved to the start of the list
siblingContentItems.Insert(0,content);
// call contentService Sort method on the list...
contentService.Sort(siblingContentItems);
}
}
Thank you so much for this, it's put me that much closer to the goal as we now have sort sorted!
However, it seems the code is still not triggering the "ignore" flag and, therefore, is generating multiple ModuleManager nodes under the home node:
Here is the new codebase:
using System;using System.Diagnostics;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
namespace NG.USK.Helpers
{
/// <summary>
/// Check for a child page element for each of the main parent document types to enable the usage of the individual functionality module plugins
/// </summary>
public class CreateModuleManager : ApplicationEventHandler
{
public CreateModuleManager()
{
ContentService.Saved += ContentService_Saved;
}
private static void ContentService_Saved(IContentService sender, SaveEventArgs<IContent> args)
{
foreach (
var node in
args.SavedEntities.Where(
node =>
node.ContentType.Alias.InvariantEquals("NG_USK_Homepage") ||
node.ContentType.Alias.InvariantEquals("NG_USK_StandardPage") ||
node.ContentType.Alias.InvariantEquals("NG_USK_StandardPageChild") ||
node.ContentType.Alias.InvariantEquals("NG_USK_NewsArticle") ||
node.ContentType.Alias.InvariantEquals("NG_USK_Downloads")
)
)
{
try
{
if (!node.Children().Any())
{
MakeModuleManager(node);
}
else
{
var ignore = false;
foreach ( var child in node.Children())
{
if (child.ContentType.Alias.InvariantEquals("NG_USK__ModuleManager"))
{
ignore = true;
}
if (ignore == false)
{
MakeModuleManager(node);
}
}
}
}
catch (Exception err)
{
// Get stack trace for the exception with source file information
var st = new StackTrace(err, true);
// Get the top stack frame
var frame = st.GetFrame(0);
// Get the line number from the stack frame
var line = frame.GetFileLineNumber();
LogHelper.Warn(typeof(CreateModuleManager), "ERROR ON: ContentService_Saved - " + node.ContentType.Alias + " ~ " + err.Message + "[" + line + "]:" + st);
}
}
}
private static void MakeModuleManager(IContent node)
{
if (
node.ContentType.Alias.InvariantEquals("NG_USK__AutoRedirect") ||
node.ContentType.Alias.InvariantEquals("NG_USK_LandingPage")
)
{
return;
}
var nodeName = node.Name;
var moduleManagerName = nodeName + " Modules";
var cs = ApplicationContext.Current.Services.ContentService;
var moduleManagerNode = cs.CreateContent(moduleManagerName, node.Id, "NG_USK__ModuleManager");
//Set this value for logging:
var hider = string.Empty;
//Make sure the element has the NaviHide property available
if (moduleManagerNode.HasProperty("umbracoNaviHide"))
{
//tell it to have the NaviHide Property set to true:
moduleManagerNode.SetValue("umbracoNaviHide", true);
//Get this value again for logging:
hider = moduleManagerNode.GetValue<string>("umbracoNaviHide") == "0" ? "hide" : "show";
}
//Log this to the TraceLog
LogHelper.Info(typeof(CreateModuleManager), "DETAILS ON: " + moduleManagerNode.Name + " is now the " + moduleManagerNode.SortOrder + " child of " + moduleManagerNode.Parent().Name + " and set to " + hider);
//save and publish
cs.SaveAndPublishWithStatus(moduleManagerNode);
if (moduleManagerNode.HasIdentity)
{
// get the sibling nodes but not the one that has just been saved, into a list
var siblingContentItems = moduleManagerNode.Parent().Children().Where(f => f.Id != moduleManagerNode.Id).ToList();
// add the one being saved to the start of the list
siblingContentItems.Insert(0, moduleManagerNode);
// call contentService Sort method on the list...
cs.Sort(siblingContentItems);
}
}
}
}
are you able to set a break point and step through this code ?
a) to see if somehow it is firing twice
or
b) to determine the step in the logic which is creating the additional module
That said, could you not in your MakeModuleNode method, first check to see if there already exists a node of your ModuleManager type before creating it ??
If an editor changes the name of a page in your site, ie to correct a typo or because they do that sometimes, wouldn't that create further Module Manager folders ?
If there is only one folder for modules underneath each node, couldn't they all just be called modules ?
Thank you so much for this, it's put me that much closer to completion!
You're thought about checking for children in the MakeModuleManager method was the ticket!!!
Revised code below:
using System;using System.Diagnostics;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
namespace NG.USK.Helpers
{
/// <summary>
/// Check for a child page element for each of the main parent document types to enable the usage of the individual functionality module plugins
/// </summary>
public class CreateModuleManager : ApplicationEventHandler
{
public CreateModuleManager()
{
ContentService.Saved += ContentService_Saved;
}
private static void ContentService_Saved(IContentService sender, SaveEventArgs<IContent> args)
{
foreach (
var node in
args.SavedEntities.Where(
node =>
node.ContentType.Alias.InvariantEquals("NG_USK_Homepage") ||
node.ContentType.Alias.InvariantEquals("NG_USK_StandardPage") ||
node.ContentType.Alias.InvariantEquals("NG_USK_StandardPageChild") ||
node.ContentType.Alias.InvariantEquals("NG_USK_NewsArticle") ||
node.ContentType.Alias.InvariantEquals("NG_USK_Downloads")
)
)
{
try
{
if (!node.Children().Any())
{
MakeModuleManager(node);
}
else
{
var ignore = false;
foreach (var child in node.Children())
{
if (child.ContentType.Alias.InvariantEquals("NG_USK__ModuleManager"))
{
ignore = true;
}
if (ignore == false)
{
MakeModuleManager(node);
break;
}
}
}
}
catch (Exception err)
{
// Get stack trace for the exception with source file information
var st = new StackTrace(err, true);
// Get the top stack frame
var frame = st.GetFrame(0);
// Get the line number from the stack frame
var line = frame.GetFileLineNumber();
LogHelper.Warn(typeof (CreateModuleManager),
"ERROR ON: ContentService_Saved - " + node.ContentType.Alias + " ~ " + err.Message + "[" + line + "]:" + st);
}
}
}
private static void MakeModuleManager(IContent node)
{
try
{
if (
node.ContentType.Alias.InvariantEquals("NG_USK__AutoRedirect") ||
node.ContentType.Alias.InvariantEquals("NG_USK_LandingPage") ||
node.Children().Any(x => x.ContentType.Alias.InvariantEquals("NG_USK_ModuleManager"))
)
{
return;
}
var nodeName = node.Name;
var moduleManagerName = nodeName + " Modules";
var cs = ApplicationContext.Current.Services.ContentService;
var moduleManagerNode = cs.CreateContent(moduleManagerName, node.Id, "NG_USK__ModuleManager");
//Set this value for logging:
var hider = string.Empty;
//Make sure the element has the NaviHide property available
if (moduleManagerNode.HasProperty("umbracoNaviHide"))
{
//tell it to have the NaviHide Property set to true:
moduleManagerNode.SetValue("umbracoNaviHide", true);
//Get this value again for logging:
hider = moduleManagerNode.GetValue<string>("umbracoNaviHide") == "0" ? "hide" : "show";
}
//Log this to the TraceLog
LogHelper.Info(typeof (CreateModuleManager),
"DETAILS ON: " + moduleManagerNode.Name + " is now the " + moduleManagerNode.SortOrder + " child of " +
moduleManagerNode.Parent().Name + " and set to " + hider);
//save and publish
cs.SaveAndPublishWithStatus(moduleManagerNode);
if (moduleManagerNode.HasIdentity)
{
// get the sibling nodes but not the one that has just been saved, into a list
var siblingContentItems = moduleManagerNode.Parent().Children().Where(f => f.Id != moduleManagerNode.Id).ToList();
// add the one being saved to the start of the list
siblingContentItems.Insert(0, moduleManagerNode);
// call contentService Sort method on the list...
cs.Sort(siblingContentItems);
}
}
catch (Exception doh)
{
// Get stack trace for the exception with source file information
var st = new StackTrace(doh, true);
// Get the top stack frame
var frame = st.GetFrame(0);
// Get the line number from the stack frame
var line = frame.GetFileLineNumber();
LogHelper.Warn(typeof (CreateModuleManager),
"ERROR ON: MakeModuleManager - " + node.ContentType.Alias + " ~ " + doh.Message + "[" + line + "]:" + st);
}
}
}
}
I've just come across this post. If all you're looking to do is add new nodes to the top of the list of siblings in Umbraco 7 then you can use the following code. It actually has an extra feature where it checks for an "Add to Top" property on the parent so it's flexible but you can remove that part of the code if you don't need it.
Call it with something like ContentService.Saved += OnSaved; of course.
/// <summary>
/// On save, if there is one item to save, if the item is new (uses IsNewEntity) and the page has the "addToTop" property set, add the item to the top.
/// The sort order is set to one less than the current top child in the list to ensure the content appears at the top of its node tree.
/// </summary>
private void OnSaved(IContentService sender, SaveEventArgs<IContent> args)
{
if (args.SavedEntities.Count() == 1)
{
var content = args.SavedEntities.First();
var isNew = content.IsNewEntity();
if (isNew)
{
var parent = content.Parent();
if (parent != null && parent.HasProperty("addToTop") && parent.GetValue<bool>("addToTop"))
{
var sortOrder = sender.GetChildren(parent.Id).Min(o => o.SortOrder);
content.SortOrder = sortOrder - 1;
if (content.Published)
sender.SaveAndPublishWithStatus(content);
else
sender.Save(content);
}
}
}
}
Umbraco 7: How to put a newly created node on top
[UPDATED]
After finding Simon Dingley's SO post on "Umbraco 6: How to put newly created node on top" I've tried to implement the sorting but I think things have changed enough that this doesn't seem to actually work and the new node is placed at the bottom of the list of any siblings instead of at the top where I need it to be?
Also, the duplicate check seems to be failing as multiple nodes are being created at different levels at different times if anyone can see where that's wrong?
Here's an image as an example of the replication issue:
If the nodes are manually sorted to put the module manager at the top - the duplication doesn't happen of course as the "found" flag is triggered immediately in the loop but then is ignored as it loops through the children?
Here's the latest code:
Thanks everyone!
Hi Jon
I'm wondering if you can achieve what you are after using the ContentServices Sort method ?
https://our.umbraco.org/documentation/reference/management/services/contentservice
the gist of which would be...
Marc,
Thank you so much for this, it's put me that much closer to the goal as we now have sort sorted!
However, it seems the code is still not triggering the "ignore" flag and, therefore, is generating multiple ModuleManager nodes under the home node:
Here is the new codebase:
Hi Jon
are you able to set a break point and step through this code ? a) to see if somehow it is firing twice or b) to determine the step in the logic which is creating the additional module
That said, could you not in your MakeModuleNode method, first check to see if there already exists a node of your ModuleManager type before creating it ??
If an editor changes the name of a page in your site, ie to correct a typo or because they do that sometimes, wouldn't that create further Module Manager folders ?
If there is only one folder for modules underneath each node, couldn't they all just be called modules ?
eg
/Text Page/Modules & /Text Page/hidden page test/Modules
Also I'm slightly intrigued as to what the Modules are for each page; have you looked at packages such as 'nested content' ? https://our.umbraco.org/projects/backoffice-extensions/nested-content/
Marc,
Thank you so much for this, it's put me that much closer to completion!
You're thought about checking for children in the MakeModuleManager method was the ticket!!!
Revised code below:
Final screenshot:
#h5yr!
I've just come across this post. If all you're looking to do is add new nodes to the top of the list of siblings in Umbraco 7 then you can use the following code. It actually has an extra feature where it checks for an "Add to Top" property on the parent so it's flexible but you can remove that part of the code if you don't need it.
Call it with something like ContentService.Saved += OnSaved; of course.
is working on a reply...