Custom Hooks by Example


This custom hook example sets a component automatically so that site contributors do not need to set the same component manually for each descendent page.

Stepping through this example:

  1. In Schema Designer, create a component with the rootname SiteControl.
  2. Again, in Schema Designer, create a page with a component element.
  3. In the Site Tree of your CMS, create an instance of SiteControl (e.g., MySiteControl).
  4. In the Site Tree, create an instance of the page (e.g., Home) that you've configured to include a component element.
  5. For the page's component element, select the MySiteControl instance. MySiteControl will be acquired automatically by descendent pages once the code is in place.

    Setting a Component on a New Page

  6. Add the following code blocks to [path-to-cms-site-instance]/App_Data/xml/Custom/CustomHooks.cs.
    Note
    You will find the entire code block below.
  7. When CMS users create a new page, this action triggers OnNew().
    #region ICustomHooks Members
    public void OnNew(IPage page, IUserWriteSession session)
    {
    this.SetComponentFromAncestor(page, "SiteControl");
    page.Save();
    }
    
    ...
                         
    #endregion
  8. The onNew() passes the newly created page ID and session name parameter, in this case "SiteControl," to SetComponentFromAncestor().
    #region CustomHooks Helpers
    public void SetComponentFromAncestor(IPage page, string eltName)
    {
    string eltID = this.GetSiteControlId(page, eltName);
    if (!string.IsNullOrWhiteSpace(eltID))
    {
    this.SetElementValue(page, eltName, eltID);
    }
    }
  9. In turn, the SetComponentFromAncestor() calls GetSiteControlId(), which walks the new page's ancestor tree.
    public string GetSiteControlId(IPage parent, string eltName)
    {
    IPage current = parent;
    while (current != null)
    {
    var elt = current.Element(eltName);
    if (elt != null && !string.IsNullOrWhiteSpace(elt.Value))
    {
    return elt.Value;
    }
    current = current.Parent();
    }
    return "";
    }
  10. When the calling chain finds an ancestor page containing the SiteControl element, then SetComponentFromAncestor() checks that its value is not null. (If null, the SetComponentFromAncestor() returns an empty string.)
  11. If the parent's siteControl element contains an ID value, then this ID value and the SiteControl's element name are passed to SetElementValue(). Consequently, the new page's SiteControl Element acquires these values.
    public void SetElementValue(IPage page, string eltName, string eltValue)
    {
    var elt = page.Element(eltName);
    if (elt != null)
    {
    elt.Value = eltValue;
    }
    }
    #endregion
  12. To complete this walk through, create a new page as a child of the Home page to ensure that the MySiteControl reference has populated the component element of your new page, automatically.

    Auto-Assignment of Component

Next Steps:

The CustomsHooks.cs file is processed whenever an event is triggered in the CMS, regardless of if it was by a user, through workflow, or by another API-related action. Given this indiscriminate behavior of custom hooks, it's important that they handle any checks for specific scenarios. An example of such code would be a function that fires only when an administrator is performing the action.

There is no access to the display when running a hook, so while an error can be thrown, it will interrupt the processing of whatever called the script that threw the error. There is currently no method for messaging, so you can't communicate what your hooks are doing to the user that triggered them. It's best to make sure that the actions are thoroughly documented and easily discoverable for other developers.

Thoroughly test all scripts intended to be used as custom hooks before implementing them in a live environment. A poorly coded custom hook could prevent users from accessing content or logging in, and it could even destroy content in a site.

Complete Code for Custom Hook Example

public class CustomHooks : ICustomHooks
{
#region ICustomHooks Members

public void OnNew(IPage page, IUserWriteSession session)
{
this.SetComponentFromAncestor(page, "SiteControl");
page.Save();
}
            
...
            
#endregion
            
            
#region CustomHooks Helpers
            
public void SetComponentFromAncestor(IPage page, string eltName)
{
string eltID = this.GetSiteControlId(page, eltName);
if (!string.IsNullOrWhiteSpace(eltID))
{
this.SetElementValue(page, eltName, eltID);
}
}
            
            
public string GetSiteControlId(IPage parent, string eltName)
{
IPage current = parent;
while (current != null)
{
var elt = current.Element(eltName);
if (elt != null && !string.IsNullOrWhiteSpace(elt.Value))
{
return elt.Value;
}
current = current.Parent();
}
return "";
}
            
            
public void SetElementValue(IPage page, string eltName, string eltValue)
{
var elt = page.Element(eltName);
if (elt != null)
{
elt.Value = eltValue;
}
}
#endregion
}