5
votes

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.

3
In your option2 (publishmanager), you are publishing to the master database. Could you try that one with the web database as target? Also, make sure you are using the right database context (maybe use a db switcher to master db as well).Gatogordo
doesn't seem to work either. I added a DatabaseSwitcher and changed the database to web, also tried the other way around.redrobot
I use option 2, can you update the code in the question with the web?, other The publish target is not always "web", better not use this hardcoded, 2) If the parent not exists in the web database the item will not be publishedJan Bluemink
Updated to "web", that wasn't the issue because I tried both to be sure, but I think I figured it out, will post an answer laterredrobot

3 Answers

5
votes

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);
}
2
votes

After all, the issue was not really in the code but just the wrong order of doing things and using correct databases.

  1. Update the field in the Sitecore editor
  2. Clear the master database cache
  3. Get the item explicitly from the master database
  4. Publish the item with the "web" database as target
  5. Clear the "web" database cache

Final code to publish an item:

using (new Sitecore.SecurityModel.SecurityDisabler())
{
    string itemId = "E7A2DE22-4338-49A6-840F-4B3124F1FFBD";

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

    ClearSitecoreDatabaseCache(masterdb);

    Item masterItem = masterdb.GetItem(new ID(itemId));

    // target databases
    Database[] databases = new Database[1] { webdb };

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

    ClearSitecoreDatabaseCache(webdb);
}

Code to clear the cache:

public void ClearSitecoreDatabaseCache(Database db)
{
    // clear html cache
    Sitecore.Context.Site.Caches.HtmlCache.Clear();

    db.Caches.ItemCache.Clear();
    db.Caches.DataCache.Clear();

    //Clear prefetch cache
    foreach (var cache in Sitecore.Caching.CacheManager.GetAllCaches())
    {
        if (cache.Name.Contains(string.Format("Prefetch data({0})", db.Name)))
        {
            cache.Clear();
        }
    }
}
2
votes

According to me, clearing all caches while publishing is not a practical way. It will impact on site performance a lot.

Actually, after editing the content from dbbrowser, you just need to clear item specific cache (for edited items only). To know how to do that, check - http://sitecoreblog.patelyogesh.in/2013/08/sitecore-partial-cache-clear-programmatically.html.

Means, steps you should take: 1. Edit content from DBBrowser 2. Before publishing, clear item specific cache for publishing items 3. No additional "web" or "master" cache clearing required publishing.

I'm sure this will help your solution.