diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs
index 76a817b63c..40b350cf15 100644
--- a/src/Umbraco.Core/Services/ContentService.cs
+++ b/src/Umbraco.Core/Services/ContentService.cs
@@ -2006,6 +2006,96 @@ namespace Umbraco.Core.Services
}
}
+ return true;
+ }
+
+ ///
+ /// Sorts a collection of objects by updating the SortOrder according
+ /// to the ordering of node Ids passed in.
+ ///
+ ///
+ /// Using this method will ensure that the Published-state is maintained upon sorting
+ /// so the cache is updated accordingly - as needed.
+ ///
+ ///
+ ///
+ ///
+ /// True if sorting succeeded, otherwise False
+ public bool Sort(int[] ids, int userId = 0, bool raiseEvents = true)
+ {
+ var shouldBePublished = new List();
+ var shouldBeSaved = new List();
+
+ using (new WriteLock(Locker))
+ {
+ var allContent = GetByIds(ids).ToDictionary(x => x.Id, x => x);
+ var items = ids.Select(x => allContent[x]);
+
+ using (var uow = UowProvider.GetUnitOfWork())
+ {
+ var asArray = items.ToArray();
+ var saveEventArgs = new SaveEventArgs(asArray);
+ if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, saveEventArgs))
+ {
+ uow.Commit();
+ return false;
+ }
+
+ var repository = RepositoryFactory.CreateContentRepository(uow);
+
+ var i = 0;
+ foreach (var content in asArray)
+ {
+ //If the current sort order equals that of the content
+ //we don't need to update it, so just increment the sort order
+ //and continue.
+ if (content.SortOrder == i)
+ {
+ i++;
+ continue;
+ }
+
+ content.SortOrder = i;
+ content.WriterId = userId;
+ i++;
+
+ if (content.Published)
+ {
+ //TODO: This should not be an inner operation, but if we do this, it cannot raise events and cannot be cancellable!
+ var published = _publishingStrategy.Publish(uow, content, userId).Success;
+ shouldBePublished.Add(content);
+ }
+ else
+ shouldBeSaved.Add(content);
+
+ repository.AddOrUpdate(content);
+ //add or update a preview
+ repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c));
+ }
+
+ foreach (var content in shouldBePublished)
+ {
+ //Create and Save ContentXml DTO
+ repository.AddOrUpdateContentXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c));
+ }
+
+ if (raiseEvents)
+ {
+ saveEventArgs.CanCancel = false;
+ uow.Events.Dispatch(Saved, this, saveEventArgs);
+ }
+
+ if (shouldBePublished.Any())
+ {
+ //TODO: This should not be an inner operation, but if we do this, it cannot raise events and cannot be cancellable!
+ _publishingStrategy.PublishingFinalized(uow, shouldBePublished, false);
+ }
+
+ Audit(uow, AuditType.Sort, "Sorting content performed by user", userId, 0);
+ uow.Commit();
+ }
+ }
+
return true;
}
diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs
index 7a5c64c0c0..14ef94bd7a 100644
--- a/src/Umbraco.Core/Services/IContentService.cs
+++ b/src/Umbraco.Core/Services/IContentService.cs
@@ -642,7 +642,21 @@ namespace Umbraco.Core.Services
///
///
/// True if sorting succeeded, otherwise False
- bool Sort(IEnumerable items, int userId = 0, bool raiseEvents = true);
+ bool Sort(IEnumerable items, int userId = 0, bool raiseEvents = true);
+
+ ///
+ /// Sorts a collection of objects by updating the SortOrder according
+ /// to the ordering of node Ids passed in.
+ ///
+ ///
+ /// Using this method will ensure that the Published-state is maintained upon sorting
+ /// so the cache is updated accordingly - as needed.
+ ///
+ ///
+ ///
+ ///
+ /// True if sorting succeeded, otherwise False
+ bool Sort(int[] ids, int userId = 0, bool raiseEvents = true);
///
/// Gets the parent of the current content as an item.
diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs
index d53ee84e7c..6b3a73f5df 100644
--- a/src/Umbraco.Web/Editors/ContentController.cs
+++ b/src/Umbraco.Web/Editors/ContentController.cs
@@ -792,11 +792,8 @@ namespace Umbraco.Web.Editors
{
var contentService = Services.ContentService;
- // content service GetByIds does order the content items based on the order of Ids passed in
- var content = contentService.GetByIds(sorted.IdSortOrder);
-
// Save content with new sort order and update content xml in db accordingly
- if (contentService.Sort(content) == false)
+ if (contentService.Sort(sorted.IdSortOrder) == false)
{
LogHelper.Warn("Content sorting failed, this was probably caused by an event being cancelled");
return Request.CreateValidationErrorResponse("Content sorting failed, this was probably caused by an event being cancelled");
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/nodeSorter.asmx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/nodeSorter.asmx.cs
index 505d715c3e..e7603abe2e 100644
--- a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/nodeSorter.asmx.cs
+++ b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/nodeSorter.asmx.cs
@@ -175,13 +175,16 @@ namespace umbraco.presentation.webservices
{
var contentService = ApplicationContext.Services.ContentService;
try
- {
- var intIds = ids.Select(int.Parse).ToArray();
- var allContent = contentService.GetByIds(intIds).ToDictionary(x => x.Id, x => x);
- var sortedContent = intIds.Select(x => allContent[x]);
-
+ {
// Save content with new sort order and update db+cache accordingly
- var sorted = contentService.Sort(sortedContent);
+ var intIds = new List();
+ foreach (var stringId in ids)
+ {
+ int intId;
+ if (int.TryParse(stringId, out intId))
+ intIds.Add(intId);
+ }
+ var sorted = contentService.Sort(intIds.ToArray());
// refresh sort order on cached xml
// but no... this is not distributed - solely relying on content service & events should be enough