In my previous post, I described a simple alternative to using Umbraco Courier for basic staging sites and how it could be accomplished through just a few lines of custom code. In that post, however, I did not cover any means to set and store the host names for which we wanted to display the staging data.
The most logical place for this setting is the “Culture and Hostnames” dialog. A simple “Staging” checkbox should do the trick nicely:
However, we don’t want to touch the core dialog. Instead we want to replace the original with our own. This way our plugin is much less invasive and easier to install/uninstall.
We do this on the TreeControllerBase.MenuRendering event:
TreeControllerBase.MenuRendering += TreeControllerBase_MenuRendering;
Below we simply remove the original dialog and substitute our own!
private void TreeControllerBase_MenuRendering(TreeControllerBase treeControllerBase, MenuRenderingEventArgs menuRenderingEventArgs) { //Only do this for the assignDomain menu if (menuRenderingEventArgs.Menu == null || menuRenderingEventArgs.Menu.Items.All(x => x.Alias != "assignDomain")) { return; } //find original dialog and it's index MenuItem oldItem = menuRenderingEventArgs.Menu.Items.FirstOrDefault(x => x.Alias == "assignDomain"); int i = menuRenderingEventArgs.Menu.Items.FindIndex(x => x.Alias == "assignDomain"); //remove original dialog (and our new dialog if it's already been added menuRenderingEventArgs.Menu.Items.RemoveAll(x => x.Alias == "assignDomain"); menuRenderingEventArgs.Menu.Items.RemoveAll(x => x.Alias == "stageSetup"); //finally create our new replacement dialog MenuItem stageSetup = new MenuItem("stageSetup", oldItem.Name); stageSetup.Icon = oldItem.Icon; string dialogURL = string.Format("{0}?id={1}", "/umbraco/ustage/dialog/assigndomain2sv.aspx", menuRenderingEventArgs.NodeId); stageSetup.LaunchDialogUrl(dialogURL, "Set Domains for Staging and Live Sites"); //and insert it into the menu items collection menuRenderingEventArgs.Menu.Items.Insert(i, stageSetup); }
The key difference in our version of the dialog controller is that we have an additional flag for whether the domain is a staging domain or not. To handle this staging data, we inherit from base “DomainsApiController” and add our own action in which we call not only the base “SaveLanguageAndDomain” method, but also our logic to save the staging domains in a separate table (again, to keep separation from core).
[HttpPost] public PostBackModelWithStaging SaveLanguageAndDomainsStaging(PostBackModelWithStaging model) { //first populate standard PostBackModel with required properties including domains PostBackModel baseModel = new PostBackModel(); baseModel.NodeId = model.NodeId; baseModel.Valid = model.Valid; baseModel.Language = model.Language; DomainModel[] dms = new DomainModel[model.Domains.Count()]; int i = 0; foreach (var d in model.Domains) { var dm = new DomainModel(d.Name, d.Lang); dms[i] = dm; i++; } baseModel.Domains = dms; //Call the base SaveLangueageAndDomains, passing in its baseModel that it wants baseModel = base.SaveLanguageAndDomains(baseModel); //update staging version with updated base in case there are changes model.NodeId = baseModel.NodeId; model.Valid = baseModel.Valid; model.Language = baseModel.Language; DomainModelWithStaging[] dms2 = new DomainModelWithStaging[baseModel.Domains.Count()]; i = 0; foreach (var d in baseModel.Domains) { var dm = new DomainModelWithStaging(d.Name, d.Lang,false); //get proper staging setting assigned to domain model dm.Staging = model.Domains.Where(x => x.Name.ToLower() == dm.Name.ToLower()).FirstOrDefault().Staging; dms2[i] = dm; i++; } model.Domains = dms2; //save data to database if (model.Valid) { model = ProcessDomainsForStaging(model); } return model; }
As you can see above, we also have a new "PostbackWithStaging" model to include the staging data and a new “StagingDomain” class, which inherits from the core "Domain" class and handles the CRUD operations for us.
To handle the deletion of domains from the dialog, we attach to the delete event of the domain. Our full list of new event handlers are now listed below:
//Prepare the stagingdocument on save ContentService.Saved += Saved; //replace original dialog with custom menu on menuRendering TreeControllerBase.MenuRendering += TreeControllerBase_MenuRendering; //handle delete event of StagingDomain to delete staging table info StagingDomain.AfterDelete += StagingDomain.DeleteStagingInfo;
All that is left is to ensure the table exists on startup:
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) { Database db = applicationContext.DatabaseContext.Database; //Check if the DB table does NOT exist if (!db.TableExist("uStageDomains")) { //Create DB table - and set overwrite to false db.CreateTable<uStageDomains>(false); } }
That’s it! We now have our staging information controlled alongside our culture and hostnames data. We retrieve it like so within our contentfinder;
private static bool IsStagingDomain(string domain) { StagingDomain sd = new StagingDomain(domain); return sd.IsStaging; }
The full plugin (as well as full source code) is available here. We welcome any improvements, enhancements, or suggestions. Thanks!
Other Posts in This Series
Looking for help in Umbraco? We're an Umbraco Certified Partner. Contact us and let's talk about how Liquid can help you!