API

Add content item in a checked-in state using Ektron API

During a recent content migration exercise I had need to bulk insert a lot of content that must be added in a checked-in state, i.e. the content must not have been published previously.

I was unable to find a solution using the Framework API or even the version 7 API (e.g. Ektron.CMS.API.Content.Content) so I had to delve deeper into the past!

The code below actually comes from the Workarea itself and uses the awful Visual Basic Collections (arrrrggghhh) :

using Microsoft.VisualBasic;

public partial class CheckIn : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        // Use a VB Collection to define the content item

        Collection objCol = new Collection();
        {
            objCol.Add(1, "ContentType"); // 1 = HTML / SmartForm
            objCol.Add("<root><MyField>Value goes here</MyField></root>", "ContentHtml"); // Content (XML)
            objCol.Add("my comment", "Comment"); // Comment field
            objCol.Add(0, "ContentID"); // Content ID (zero for new content)
            objCol.Add(2057, "ContentLanguage"); // UK English
            objCol.Add("my teaser", "ContentTeaser"); // Teaser / Summary field
            objCol.Add(72, "FolderID"); // Folder where content should be added to
            objCol.Add("my search text", "SearchText");
            objCol.Add("", "GoLive");
            objCol.Add("", "EndDate");
            objCol.Add(2, "EndDateAction");
            objCol.Add("my content title", "ContentTitle"); // Content title
            objCol.Add(true, "AddToQlink");
            objCol.Add(true, "IsSearchable");
            objCol.Add("7", "MultiXmlID"); // Smartform Id
        }

        long intContentId = 0;

        ContentAPI m_refContApi = new ContentAPI();

        // The old API uses current use by default, so switch to Internal Admin
        // in order to be able to add content.
        // Remember the ID of the original user so we can switch back to that again afterwards.
        long iOrig = m_refContApi.RequestInformationRef.CallerId;
        m_refContApi.RequestInformationRef.CallerId = 
          (long)Ektron.Cms.Common.EkEnumeration.UserGroups.InternalAdmin;
        m_refContApi.ContentLanguage = 2057;

        // Adds content, then checks it in
        intContentId = m_refContApi.EkContentRef.AddNewContentv2_0(objCol);
        m_refContApi.EkContentRef.CheckContentInv2_0(intContentId);

        // Set API back to original user ID
        m_refContApi.RequestInformationRef.CallerId = iOrig;
    }
}

Hopefully this code will save you having to dig through the old workarea code.

Add a PageBuilder page using the Ektron API

Pagebuilder pages are an Ektron feature that allow content authors to create flexible web pages by dragging and dropping widgets onto the page.  A widget is a module that can be added to a web page which provides a specific purpose such as an image, video, form or a block of HTML text.

There might be instances in which, during the course of a project, it becomes necessary to add pages into the CMS en masse, for instance, during a content migration excercise.

The following block of code below will allow you to create a Pagebuilder page and add a widget into it.

EDIT: Updated as original code sample wasn’t verbose enough
The code adds an Ektron ContentBlock control to the page.

long folderId = 86; // where to add the page to
var tmpPageData = new PageData(); // temporary object for page config

string controlUrl = "ContentBlock.ascx"; // name of the widget user control in widgets folder
string dropZoneId = "Middle"; // id of the DropZone control on the wireframe

var widget = new WidgetData
{
ControlURL = controlUrl,
ColumnID = 0,
Order = 0,
Minimized = false,
DropID = dropZoneId,
Settings = String.Format("{0}", 30);
};

tmpPageData.Widgets = new List(); // initialise widgetdata list on page
tmpPageData.Widgets.Add(widget); // add ContentBlock widget to page

// Create a drop zone data object
var dropZoneMain = new DropZoneData {DropZoneID = "Middle", Columns = new List()};

// Create a column data object
var columnDataMain = new ColumnData {columnID = 0, width = 100, unit = Units.percent};

// Add the column to the drop zone
dropZoneMain.Columns.Add(columnDataMain);

// Add the drop zone to the page
tmpPageData.Zones = new List {dropZoneMain};
tmpPageData.IsMasterLayout = false;

// Call a method to add the page (see method below)
AddPage(gameToPush.Title, gameToPush.Alias, folderId, 2, tmpPageData, 2057);

So the process above is add widgets to the PageData.Widgets property then add the Drop Zones to the PageData.Zones property (which also includes Columns).

The above code depends upon a method called “AddPage()” which is given below:

private void AddPage(string pageTitle, string alias, long folderId, long wireFrameId,
Ektron.Cms.PageBuilder.PageData pageData, int langId = 2057,
ContentMetaData[] metaData = null)
{

    var pageManager = new PageModel();
    var contentManagerOld = new Ektron.Cms.API.Content.Content();
    pageManager.RequestInformation = contentManagerOld.RequestInformationRef;

    var tmpPageData = new PageData();

    // First create the page entity in the CMS
    pageManager.Create(pageTitle, folderId, alias, langId, wireFrameId, String.Empty, "summary", out tmpPageData, true);

    // Assign widgets and drop zones
    tmpPageData.Widgets = pageData.Widgets;
    tmpPageData.Zones = pageData.Zones;

    // Save to the CMS
    pageManager.CheckIn(tmpPageData);
    pageManager.Publish(tmpPageData);

    // Assign metadata
    if (tmpPageData.pageID > 0)
    {
        if (metaData != null)
        {
            if (metaData.Length > 0)
            {
                contentManagerOld.ContentLanguage = langId;

                foreach (ContentMetaData meta in metaData)
                {
                    contentManagerOld.UpdateContentMetaData(tmpPageData.pageID, meta.Id, meta.Text);
                }
            }
        }
    }
}

At first glance this seems a bit counter-intuitive.  The addition of widgets and drop zones to the page is done separately, whereas you may have thought that widgets go into columns which go into zones which go pages.  In fact the widgets and zones are accessed through different properties as you can see above.

Write efficient taxonomy code

Ektron’s Taxonomy feature allows categorisation of content, users and community groups.  The Ektron API allows this grouping of content to be retrieved and manipulated in code.

One common problem I have encountered on projects is poor performing API code due to a lack of understanding of just how the API works.  Your taxonomy API requests should be specific and exact: retrieve only what you need to from the CMS.

The Framework API in version 8.5 does a lot to remedy these problems so I am focusing here on the pre-Framework-API-world.

Below is some example code (edited for brevity) from a recent project that performs a taxonomy request, looking for content items:


Ektron.Cms.TaxonomyRequest taxonomyRequest = new TaxonomyRequest();
taxonomyRequest.TaxonomyLanguage = CultureInfo.CurrentCulture.LCID;
taxonomyRequest.TaxonomyId = id;
taxonomyRequest.IncludeItems = true;
Ektron.Cms.API.Content.Taxonomy taxonomyApi = new Ektron.Cms.API.Content.Taxonomy();
taxonomy = taxonomyApi.LoadTaxonomy(ref taxonomyRequest);

On face value there is nothing wrong with this code. However, if I also state that the purpose of this call was just to get the Taxonomy Path you might then spot a few issues immediately.

Firstly, the “IncludeItems” property is set to “true”. This means the API will retrieve all of the content items in addition to the taxonomy information. A taxonomy could contain tens or hundreds of items, massively increasing the amount of data that the CMS has to retrieve.

Secondly, the “Depth” property has not been set. The Taxonomy Depth property specifies how “deep” the request should go, i.e. how many levels of sub-categories should be pulled back. By not specifying this you risk getting lots and lots of categories retrieve. Combine this with the first problem and you can easily see how slow this could become!

Thirdly, as we only want to get information about the taxonomy (and not the items in the taxonomy) we should instead use taxonomyApi.ReadTaxonomy rather than taxonomyApi.LoadTaxonomy. The former performs less queries as it ignores whatever is in the categories.

There have been several projects I have worked on where there were complaints that the CMS was slow. Quite often the problem was tracked down to a poorly written taxonomy request like this one.

Add item to the library using Ektron API

The Ektron library is a useful area within the CMS that can be used to store all kinds of static files. By static I mean that it is just a basic file to which you will not need to apply metadata, taxonomy, aliases or any of the other features of a CMS asset.

The chances are, at some point you will need to add a file to the Library using the API. Perhaps you are providing a custom method to upload photographs to the CMS or users need to submit their CV as a Word document.

Adding a file to the Library is a two step process. Assuming you have the file already uploaded the file to the web server hard disk (to a temporary location), you first need to copy the file to the right place and then call the API to tell Ektron CMS where the file is. The API call alone will not put the file in the right physical location.

Here is the call to put the file into the right place:


string libraryFilePath = "/uploadedimages" + folderPath + "/" + title + "." + cd.AssetData.FileExtension;


File.Move(Server.MapPath(newImagePath), HttpContext.Current.Request.PhysicalApplicationPath.TrimEnd('\\') + libraryFilePath);

This will move the file from a temporary location into the permanent location within the “uploadedimages” folder. The “folderpath” variable will contain the folder structure where the file is added.
Ektron.Cms.LibraryData libData = new Ektron.Cms.LibraryData();

libData.FileName = libraryFilePath;
libData.LanguageId = languageId;
libData.Title = cd.Title;
libData.ParentId = cd.FolderId;
libData.FolderName = cd.FolderName;
libData.ContentType = 7;
libData.Type = "images";

long libID = 0;
libID = libAPI.AddLibraryItem(ref libData);

The above code is used to add an image to the Library.