Posts Tagged ‘Publication’
Delete keywords in Tridion
As posted earlier, I completed the keyword deletion tool. I’ve tried both approaches (explained in my earlier post) to implement this keyword deletion. Finally I’ve decided to go with deleting keywords from bottom to top that’s 2nd approach.
How to call it
All you need is just to create class object with TCM Uri of a parent keyword whose child keywords are to be deleted and call its delete method.
//initialize the class with keyword TCM Uri value TCMKeywords keywords = new TCMKeywords(ConfigurationManager.AppSettings["TCMURI"]); //deletes keyword branch keywords.Delete();
Here we don’t need to pass its publication TCM Uri since that can be retrieved from its keyword TCM Uri. I’ve given TCM Uri in my app.config file so that I can change it whenever I needed.
Call child keywords recursively
Tridion API does not provide direct method to get all child keywords in hierarchical order. But we can write a recursive call just like the way we do it for any other tree structure objects.
/// <summary>
/// Recursive method to navigate all keywords
/// </summary>
/// <param name="parentTCM">TCM Uri of parent keyword</param>
/// <param name="level">Hierarchy level of keyword</param>
private void NavigateKeywords(string parentTCM, int level)
{
//gets all child keywords from given parent
XmlNode keyNode = this.GetListChildKeywords(parentTCM);
foreach (XmlNode key in keyNode.ChildNodes)
{
//loops through its next level
NavigateKeywords(key.Attributes["ID"].Value, level + 1);
//deletes keyword if it doesn't have any child
this.DeleteKeyword((Keyword)this.GetObject(key.Attributes["ID"].Value), level);
}
}
Obviously a keyword cannot be deleted if it is being used by other items. So all other associations should be removed before deleting it. That’s the reason DeleteKeyword(…) is being called after NavigateKeywords(…). That means if keyword (A) do not have any child, keyword (A) will be considered for deletion.
GetListChildKeywords(…) is a private method to retrieve all child keywords in Xml type of object.
/// <summary>
/// Gets all child keywords in xml object
/// </summary>
/// <param name="parentKeywordTCM">Parent <see cref="Keyword">Keyword</see></param>
/// <returns>Child keywords in <see cref="XmlNode">XmlNode</see> object</returns>
private XmlNode GetListChildKeywords(string parentKeywordTCM)
{
//gets all child keywords
string keyXML = ((Keyword)this.GetObject(parentKeywordTCM)).GetListChildKeywords(EnumKeywordSortType.SortTypeTitle,ListColumnFilter.XMLListID, (ListRowFilter)TObj.CreateListRowFilter());
//returns output as xml object
return this.PopulateXMLNode(keyXML);
}
ListColumnFilter –Other attributes also can be retrieved other than ListID. But we need only list id for this tool.
ListRowFilter – Here we are getting all rows so we are not setting any filter conditions. This can be set based upon our requirements. Let’s look at this code sample if filtering condition is needed.
Deleting a keyword
The keywords in Tridion can be used in following ways.
- Classified with other building blocks
- Used in component or metadata fields
- Localized in its child publications
A keyword should be released from the all above associations before deleting it.
//releases keyword from its all dependencies
if (this.ReleaseKeyword(keyword, keyLevel))
{
//deletes keyword
keyword.Delete();
Console.WriteLine("{0}{1} deleted...", keyLevel, keyword.Title);
}
ReleaseKeyword(…) is a private method to unclassify and unlocalize the keywords.
/// <summary>
/// Releases the keyword from its dependencies
/// </summary>
/// <param name="keyword"><see cref="Keyword">Keyword</see> object to be released</param>
/// <param name="keyLevel">Hirarchical level of a keyword</param>
/// <returns>Returns <see cref="bool">bool</see> if released or not</returns>
private bool ReleaseKeyword(Keyword keyword, string keyLevel)
{
//default status
bool released = false;
//unclassifies the keyword
released = this.Unclassify(keyword, keyLevel);
//unlocalizes the keyword from its all child publications
if (released)
released = UnLocalize(keyword, keyLevel);
//returns released status
return released;
}
Unclassifying keywords
In Tridion, the content or building blocks are generally classified with keywords.
Classified means that it can be in either way,
1) Keyword can be used in any of field values in metadata or components.
2) An Tridion object is classified against keyword.
These two associations should be removed as part of unclassification.
For example, if a keyword is classified with 10 Tridion objects, we need to retrieve those 10 objects and call them separately its own unclassify method.
The problem here is a keyword in one publication would be derived into its child publications. In child publications, these keywords might have classified with other objects. Hence the appropriate keyword from the same publication should be retrieved to unclassify it.
/// <summary>
/// Unclassifies the keyword
/// </summary>
/// <param name="keyword"><see cref="Keyword">Keyword</see> object to be released</param>
/// <param name="keyLevel">Hierarchical level of a keyword</param>
/// <returns>Returns <see cref="bool">bool</see> if unclassified or not</returns>
private bool Unclassify(Keyword keyword, string keyLevel)
{
try
{
//gets all using items from all publications
string classifiedItemsXML = keyword.Info.GetListUsingItems(ListColumnFilter.XMLListDefault,(ListRowFilter)TObj.CreateListRowFilter());
//converts xml string to xml object
XmlNode xmlDoc = this.PopulateXMLNode(classifiedItemsXML);
string tcmChild = null;
//default publication is set to current publication
string pubURI = this.PublicationURI;
foreach (XmlNode child in xmlDoc.ChildNodes)
{
//gets keyword tcm uri
tcmChild = child.Attributes["ID"].Value;
//checks if publication of child object is same as its parent keyword
if (!this.IsSamePublication(tcmChild))
{
//gets publication tcm uri from given tcm uri
pubURI = GeneratePublicationTCM(tcmChild);
//gets the same keyword object from its child object publication
keyword = (Keyword)this.GetObject(pubURI, ReplacePublicationID(keyword.ID, this.GetPublicationID(tcmChild)));
}
//checks its child object type and unclassify
switch (child.Attributes["Type"].Value)
{
case "2":
((Folder)this.GetObject(pubURI, tcmChild)).UnClassify(keyword);
break;
case "4":
((StructureGroup)this.GetObject(pubURI, tcmChild)).UnClassify(keyword);
break;
case "16":
((Component)this.GetObject(pubURI, tcmChild)).UnClassify(keyword);
break;
case "32":
((ComponentTemplate)this.GetObject(pubURI, tcmChild)).UnClassify(keyword);
break;
case "64":
((Tridion.ContentManager.Interop.TDS.Page)this.GetObject(pubURI, tcmChild)).UnClassify(keyword);
break;
case "128":
((PageTemplate)this.GetObject(pubURI, tcmChild)).UnClassify(keyword);
break;
}
}
//display the output if any of child is unclassified
if (xmlDoc.ChildNodes.Count != 0)
Console.WriteLine("{0}{1} unclassified...", keyLevel, keyword.Title);
return true;
}
catch (Exception ex)
{
Console.WriteLine("Unclassification Failed!");
Console.WriteLine(ex.Message);
return false;
}
}
GetListUsingItems(…) is the common method in all Tridion objects to retrieve its associated items. In this case, this method will return all the objects wherever the keyword is being used.
Here important note is that if a keyword is unclassified, the parent object will not get republished automatically. If you need to republish the parent object while keyword unclassification, you need to set some code and trigger workflow events.
Unlocalizing keywords
Unlocalizing is not a straight forward approach unlike unclassification. There is no method to write all localized keywords.
If there is a keyword in publication, the same keyword has to be checked in its all child publications whether it is localized in child publication level.
/// <summary>
/// Unlocalizes keyword
/// </summary>
/// <param name="keyword"><see cref="Keyword">Keyword</see> object to be released</param>
/// <param name="keyLevel">Hirarchical level of a keyword</param>
/// <returns>Returns <see cref="bool">bool</see> if unlozalized or not</returns>
private bool UnLocalize(Keyword keyword, string keyLevel)
{
try
{
//gets all child publications
List<string> childPublications = this.GetChildPublications(keyword.Publication.ID);
foreach (string cPub in childPublications)
{
//gets the keyword in each child publication
Keyword childKey = (Keyword)this.GetObject(cPub, ReplacePublicationID(keyword.ID, this.SplitURI(cPub, 1)));
//checks if it is localized
if (childKey.Info.IsLocalized)
{
childKey.UnLocalize();
Console.WriteLine("{0}{1} unlocalized from {2}...", keyLevel, childKey.Title, childKey.Publication.Title);
}
}
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
GetChildPublications(…) posted earlier (Get Child publications in Tridion)
Output
I created these keywords for my testing. All keywords are classified against a component and two of them are localized in child publications.
I ran the tool and got the following output.
The source code can be copied from this link.
Get Child publications in Tridion
This code sample will give you all the derived child publications from the specific parent publication. There is no direct method to get all child publications but can be easily retrieved from GetListUsingItems(…).
I needed this method to get a status of a component in all child levels.
/// <summary>
/// Gets all child publications
/// </summary>
/// <param name="parent">TCM Uri of parent publication</param>
/// <returns>Collection of child publications</returns>
private void GetChildPublications(string parentTCM)
{
//gets current publication object
Publication pub = tdse.GetPublication(parentTCM);
//gets row filter object
ListRowFilter filter = tdse.CreateListRowFilter();
//filter only publication type
filter.SetCondition("ItemType", 1);
//returns using publications as xml
string itemsXML = pub.Info.GetListUsingItems(ListColumnFilter.XMLListID, filter);
//initialize xml document object
XmlDocument xmlDoc = new XmlDocument();
//loads items xml
xmlDoc.LoadXml(itemsXML);
foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
{
//loops id attribute in each child node
Console.WriteLine(node.Attributes["ID"].Value);
}
}
The below code returns all derived publications and remember that this will return all using items if ItemType is not specified.
//filter only publication type
filter.SetCondition("ItemType", 1);
//returns using publications as xml
string itemsXML = pub.Info.GetListUsingItems(ListColumnFilter.XMLListID, filter);
Output of above line is,
<?xml version="1.0" encoding="utf-8"?> <tcm:ListUsingItems xmlns:tcm="http://www.tridion.com/ContentManager/5.0"> <tcm:Item ID="tcm:0-123-1" /> <tcm:Item ID="tcm:0-124-1" /> <tcm:Item ID="tcm:0-125-1" /> <tcm:Item ID="tcm:0-142-1" /> <tcm:Item ID="tcm:0-143-1" /> <tcm:Item ID="tcm:0-144-1" /> </tcm:ListUsingItems>
Tridion: Organizational Items
- Collection of content and layout items that are used to create a website
- Contains folders, structure groups and categories
- Root publication should be defined to overall publications
- While creation, child publication will be exact copy of parent but virtual copy
- Usual Practice
o Empty publication should be created as root to accommodate future changes.
- Stores content building blocks (schemas, components, comp templates, page templates, folders and virtual folders)
- Contains physical copy of building blocks
- Default folders are Content, Default Building Blocks and System
- Usual practice
o Components are stored in Content folder
o Schemas and Templates are stored in System folder
- Organize, manage, and provide a URL structure for Pages
- Contains Pages with embedded building blocks
- Can be used for site navigation
- Can be displayed in order by prefixing 3 digit number, <nnn>_<Title>
- Title without prefix number will not be shown on page.
- Usual Practice
o Prefix numbers are incremental of 10
- Classify the contents using keywords
- Keywords are unique across categories in a publication
- Keywords can be used as source for collection controls (ex, dropdown)
- Two other types of keywords
o Abstract – defines generic characteristic of an object. It can’t be used for classification.
o Concrete – defines specific values
- Only possible through TOM API
o Category can have another category as parent
o Keywords can have multiple parents
o SDL Tridion GUI will only show a single parent
- Usual Practice
o Parent keyword name will be appended while trying to add duplicate keyword names (ex, <parentKey>_<keyword>
