How to publish Sitecore items programatically that have been updated using the editor

redrobot picture redrobot · May 25, 2016 · Viewed 10.5k times · Source

I have been trying to publish items through code that have been changed in the Sitecore editor. If I update field values programatically and publish those changes, it works fine though.

Our content management editors regularly make changes in the editor without necessarily publishing them. We want to provide them with a functionality to click one button that publishes all relevant changes and clears the Sitecore cache.

I don't want to publish the whole site, only several predefined items.

We are currently using Sitecore.NET 6.4.1 (rev. 110720). I am not in the possibility to update Sitecore.

I tried these options:

Option 1: instantiating a new publisher object

Database master = Sitecore.Configuration.Factory.GetDatabase("master");
Database web = Sitecore.Configuration.Factory.GetDatabase("web");

Sitecore.Publishing.PublishOptions publishOptions = new Sitecore.Publishing.PublishOptions(master,
                        web,
                        Sitecore.Publishing.PublishMode.SingleItem,
                        item.Language,
                        System.DateTime.Now); 

Sitecore.Publishing.Publisher publisher = new Sitecore.Publishing.Publisher(publishOptions);

publisher.Options.RootItem = item;

publisher.Options.Deep = true;

publisher.Publish(); 

Option 2: using the static publishmanager

Database db = Sitecore.Configuration.Factory.GetDatabase("web");
Database[] databases = new Database[1] { db };

Sitecore.Handle publishHandle = Sitecore.Publishing.PublishManager.PublishItem(item, databases, db.Languages, true, false);

Both methods are wrapped in a using statement to use the same account which is used by the content management editors.

string domainUser = @"sitecore\admin";

if (Sitecore.Security.Accounts.User.Exists(domainUser))
{
      Sitecore.Security.Accounts.User user =
      Sitecore.Security.Accounts.User.FromName(domainUser, false);

      using (new Sitecore.Security.Accounts.UserSwitcher(user))
      {
            // publish code ...
      }

}

The logs don't show anything noteworthy as far as I can tell

ManagedPoolThread #7 13:41:46 INFO  Job started: Publish to 'web'
ManagedPoolThread #7 13:41:46 INFO  HtmlCacheClearer clearing HTML caches for all sites (5).
ManagedPoolThread #7 13:41:46 INFO  HtmlCacheClearer done.
ManagedPoolThread #7 13:41:46 INFO  Job ended: Publish to 'web' (units processed: 2)
ManagedPoolThread #5 13:41:46 INFO  Job ended: Publish (units processed: )

It is definetely not a caching issue, because when publishing manually in the editor before clearing the cache programatically, the changes are visible in code.

So I'm looking for a way to programatically publish a predefined list of updated items, disregarding the way the edit has been made.

Answer

Adrian Iorgu picture Adrian Iorgu · May 25, 2016

This is how I used to publish items in a Sitecore 6.5 solution. Looks very similar to your first solution, and this still works fine for me. Do you see any errors / info logs in the Sitecore log?

public void PublishItem(Database dbMaster, Database dbWeb, Item iParent)
{
    try
    {
        PublishOptions po = new PublishOptions(dbMaster, dbWeb, PublishMode.SingleItem, Sitecore.Context.Language, DateTime.Now);
        po.RootItem = iParent;
        po.Deep = true; // Publishing subitems

        (new Publisher(po)).Publish();
    }
    catch (Exception ex)
    {
        Sitecore.Diagnostics.Log.Error("Exception publishing items from custom pipeline! : " + ex, this);
    }
}

Regarding the caching, that should be handled by the publishing operation automatically on the web database.

Sometimes when I manipulate items programatically on the master database, I force Sitecore to clear the cache only for those items with the code below:

Item baseitem = Database.GetDatabase("master").SelectSingleItem(sitecore_path);
if (baseitem != null)
{
    //Sitecore.Caching.CacheManager.ClearAllCaches();  
    string load = String.Concat(new object[] { "item:load(id=", baseitem.ID, ",language=", baseitem.Language, ",version=", baseitem.Version, ")" });
    Sitecore.Context.ClientPage.SendMessage(this, load);
    String refresh = String.Format("item:refreshchildren(id={0})", baseitem.Parent.ID);
    Sitecore.Context.ClientPage.ClientResponse.Timer(refresh, 2);
}