Tridion Core Service Update Error - tridion

On a refactoring exercise we are working on, we have to change Page Templates for select websites. Most page get localized and have their page templates updated by the code below but for a few we get the following error:
XML validation error. Reason: The element 'Metadata' in namespace 'uuid:940d95aa-fcce-481c-8de5-c61d06c74f46' has invalid child element 'description' in namespace 'uuid:940d95aa-fcce-481c-8de5-c61d06c74f46'.
List of possible elements expected: 'TitleSEO, KeywordsSEO, DescriptionSEO, omniture' in namespace 'uuid:940d95aa-fcce-481c-8de5-c61d06c74f46'.
There is no description field in our metadata schema and TitleSEO, KeywordsSEO, DescriptionSEO, omniture are all optional fields which are not being changed by the code .
try
{
pData = client.Read(page.Attribute("ID").Value, null) as PageData;
//Localize Page
if (!(bool)pData.BluePrintInfo.IsLocalized)
{
client.Localize(pData.Id, new ReadOptions());
if (dTemplateIDs.ContainsKey(pData.PageTemplate.IdRef.ToString()))
{
pData.IsPageTemplateInherited = false;
pData.PageTemplate.IdRef = dTemplateIDs[pData.PageTemplate.IdRef];
client.Update(pData, new ReadOptions());
}
}
}
catch (Exception ex)
{
Console.WriteLine("Error Inner " + ex.Message);
}

It sounds like at some point in the past there was a field in your page metadata schema called "description" (which I suspect was later changed to what is now "DescriptionSEO"). These few pages that cause the error have probably not been updated since the change, and so have the old metadata field in their XML, hence the validation problem when you come to change the Page Template.
If it's only a few pages, just open the pages, add some description or otherwise change something, save them and then try your code again.
If it's more than a few, you'll probably need to detect and remove the existing data programmatically.

I am not sure which version of SDL Tridion you are using, but in some early versions of SDL Tridion 2011, if Metadata had previously been added to any object, it was not cleared by changing the Metadata Schema to be empty on the object. As such, I have found that you had to set the Metadata value to NULL with code before saving the item. This may solve your problem.

Related

Drupal 7 Rules: after generating new content, unable to access a view related to this new data

Using Rules modules, I set up a rule "After saving new content of type X".
So, adding a new content of "X" should:
Based on its nid, call a view, which returns back a JSON, from where I fetch the info to work later. The info I need is on this view, not in the node I am inserting, but to get this view I need the nid and some other info from the node I am creating
The problem is that even if I get the nid of the new node, when I call the view it just returns an empty result. It seems like the data it's still not on Drupal database, so the view results empty. I tried to add a sleep(10) before calling the view, giving some time to Drupal, but no success.
The Content is published, and I added also a 'Save entity' Action to the Rule
Hope with this code here helps to understand:
dsm($node); //I can see al attributes from the node I am inserting
$url="http://localhost/bopa/?q=export_cultivos/$node->nid";
dpm($url);
//it gives me a correct URL, that tested later directly on the browser, works
$data=file_get_contents($url);
$data2 = json_decode($data,true);
dsm($data2);
//EMPTY array
I guess you are passing nid as string not as variable in URL. $node->nid is not getting substituted. So use following code snippet
$url="http://localhost/bopa/?q=export_cultivos/".$node->nid;

How to get the itemxml of a selected item in Tridion

I would like to get and display the itemxml of the selected item from the Tridion CME.
I was able to get the Itemxml from my VM server when i give the tcm id in the browser.
However, i would like to get the same information from Tridion GUI Extension.
I am able to get the selected item tcm id. Is there any way to get the itemxml using coreservice?
or is there any other way to get this?
At the moment there's no way you can get Item XML through core service. Item XML you have seen was provided to you by TCM Protocol handler that might not be there in future versions. If you want to show item XML in CME - take a look at this extention by Yoaw:
http://sdltridionworld.com/articles/sdltridion2011/tutorials/GUIextensionIn8steps.aspx
Also, keep in mind that not all properties of an item might be exposed in Xml, sometimes you have more info in Data object
Take a look at the PowerTools, it has an ItemXML viewer (written by Robert Curlette) for all items in SDL Tridion
http://code.google.com/p/tridion-2011-power-tools/wiki/ItemXML
The XML is loaded on a tab using JavaScript as follows:
ItemXmlTab.ItemXmlTab.prototype.updateView = function ItemXmlTab$updateView()
{
if (this.isSelected())
{
var xslPath = $ptUtils.expandPath("/PowerTools/Client/ItemXml/ItemXmlTab.xslt", true);
$xml.loadXsltProcessor(xslPath, function (value)
{
var xmlSource = $display.getItem().getXml();
// Filter out all spacing characters
xmlSource = xmlSource.replace(/\t|\n|\r/g, "");
var html = $xml.xsltTransform(value, $xml.getNewXmlDocument(xmlSource), null);
$dom.setOuterHTML($("#itemXml"), html);
});
}
};
You can view the source code of the extension at http://code.google.com/p/tridion-2011-power-tools/source/browse/#svn%2Ftrunk%2FPowerTools.Editor%2FPowerTools%2FClient%2FItemXml%253Fstate%253Dclosed
You can get the item XML via CoreService, but this will get you the Tridion R6 (2011) Xml format, which is not the same you would see before.
Sample code available here.
I tend to have a page "GetItemXml.aspx" on my Tcm servers that I then call with a Uri as a parameter, and then this page would return the Item Xml.
Article written by Yoav Niran (Url in the post of user978511) is perfect for your requirement.
if you are still facing any issue and in hurry to get it working just perform below steps -
1- Download the extension.
2- Apply the steps 7 and 8 of this article to configure this extension.

How to check publishing or rendering context with TOM.NET?

SDL Tridion's Content Manager templating API (TOM.NET) offers ways to detect publishing or rendering context.
Use Cases
Present debugging information to a specific environment (e.g. TCM Uris only on Staging)
Show different markup in Preview (e.g. show a link to the published page)
Show different author-able fields in Experience Manager or SiteEdit
I've seen and tried a few examples, but after following a chat between colleagues Stan and Eric, I want to make sure I follow for TOM.NET (6.1 / Tridion 2011).
Scenarios
Publishing to a specific Publication Target (typically "Live" and "Staging")
Content Manager Explorer (CME) Preview
Session Preview rendering for Experience Manager (XPM)
(Added) Template Builder
1. Publishing to a Target (or from a Publication)
Tridion.ContentManager.Publishing.PublishEngine.GetPublishInfo(IdentifiableObject item)
Item would be a page or component. This returns a collection of PublishInfo objects, which includes PublicationTarget to confirm where you're publishing to.
Tridion.ContentManager.Templating.PublishingContext.PublicationTarget has PublicationTarget as well.
2. CME Preview
PublicationTarget is null, which makes sense because you don't have a Publication Target . :-)
3. Session Preview
Use the RenderMode Enum under Tridion.ContentManager.Publishing, which has:
'Publish' (0)
'PreviewStatic' (1)
'PreviewDynamic' (2)
PublicationTarget wouldn't be null for Session Preview, which isn't really publishing.
4. (Added) Template Builder
?
Alexander Klock also describes some related examples which cover most of this except CME Preview.
Question(s)
Am I missing any scenarios? Publish to a specific publication target, regular preview, and XPM session preview?
How should I avoid hard-coding PublicationTargets (e.g. is it better to check the string values instead of TCM Uris)?
Update: added Template Builder to the list per Vikas's answer, how do I know I'm rendering within Template Builder?
You really need a tl;dr on this question...
Here's what I know:
Template Builder
Publication target is null, RenderMode is PreviewDynamic
CME Preview
Publication Target ID is tcm:0-0-0 (or TcmUri.UriNull), RenderMode is PreviewDynamic
Session Preview
Publication Target ID is the real target ID, RenderMode is PreviewDynamic
Publish
Publication Target ID is the real one, RenderMode is Publish
EDIT
Here's some sample code I wrote recently to determine the Current mode.
private CurrentMode GetCurrentMode()
{
RenderMode renderMode = _engine.RenderMode;
if (renderMode == RenderMode.Publish) return CurrentMode.Publish;
if (renderMode == RenderMode.PreviewDynamic)
{
if (_engine.PublishingContext.PublicationTarget == null) return CurrentMode.TemplateBuilder;
PublicationTarget target = _engine.PublishingContext.PublicationTarget;
if (target.Id.Equals(TcmUri.UriNull)) return CurrentMode.CmePreview;
return CurrentMode.SessionPreview;
}
return CurrentMode.Unknown;
}
private enum CurrentMode
{
TemplateBuilder,
CmePreview,
SessionPreview,
Publish,
Unknown
}
You presented a very good view of complete publishing/preview model. Here are my thoughts..
Are we missing any scenarios?
I think you covered everything expect the template builder case, which is similar to CME preview where we get publishing target as null but can be used to check different condition so important for debugging purpose.
How should I avoid hard-coding PublicationTargets
Yes we should never use tcm uri in any code, as you suggested we could use name and even name can be configured in respective config files for that program.
Also may not be relevant here, its always good to have separate target for Tridion UI edting other than staging. Both can be configured on same server with two deployer's. One could be staging.yoursite.com and other could be tridionui.yoursite.com
Thanks..

Tridion and REL: Updating page filename within the page's PublishedUrl property

We have a requirement where the url of a page needs to be localizable/translated. Our existing mechanism relies on the actual published url to retrieve the page via oData. To clarify with a simplified example: we have some logic in the front end that takes the request url (which doesn't have a file extension, appends a .html extension, e.g.:
/my-awesome-path/my-awesome-page
now becomes
/my-awesome-path/my-awesome-page.html
the logic then pulls the page from oData using the query
/odata.svc/Pages?$filter=url eq '/my-awesome-path/my-awesome-page.html'
There is much more logic that we have around this to parse this SEO-friendly url and get MVC controller function parameters and other whatnots, but that's not relevant here.
Our requirement is that we cannot localize the page to give it a translated url since this would mean the entire page can't be managed in the parent web publication.
To get the localized path leading up to the page filename we simply localize the SGs. The difficulty is with the page filename. On the page's metadata we have a linked "localizable metadata" component with a field for providing a localized page filename.
What we'd like to do is update the page's URL property during the publishing/deployment process to update the page's published url with the localized page filename from this linked metadata component (assume that we have access to the localized filename field's value at any stage between start of publishing to commitment of deployment).
I've tried doing this via a custom resolver, however, at this level it appears that the page.PublishedUrl property is already established by the CM and cannot be overridden. So updating the page.FileName property doesn't do anything useful.
I've also tried directly updating the URL column in the PAGE table in Broker DB to a different name and it appears that everything continues to work, including dynamic linking and unpublishing of the page. Obviously writing a storage extension or a deployer extension to directly update the DB via jdbc is unacceptable.
Here are the options I'm thinking of:
1) try a deployer extension and use the Tridion API to update the url property
2) try writing a custom renderer that executes the url replace logic without actually updating the url in the broker. I don't favour this since request-time processing is required each time.
My question is: what is the most appropriate way to update the page url property? Will writing a custom deployer using Tridion APIs to update the URL property lead me to a dead end just like the Resolver did?
Following the points in Nuno's comment above I decided against using a custom deployer and have solved the problem using 2 event subscriptions of the Event System. On page publish I first localize the page, grab the localized filename from the localized linked metadata component and save the page. Then in a subsequent event I simply unlocalize the page. Here is my working code:
[TcmExtension("Publish or Unpublish Events")]
public class PublishOrUnpublishEvents : TcmExtension
{
public PublishOrUnpublishEvents()
{
EventSystem.Subscribe<Page, PublishEventArgs>(SetLocalizedPageFileName, EventPhases.Initiated);
EventSystem.Subscribe<Page, SetPublishStateEventArgs>(UnlocalizePageOncePublished, EventPhases.Initiated);
}
public void SetLocalizedPageFileName(Page page, PublishEventArgs args, EventPhases phase)
{
string localFilename = GetLocalilizedFileNameFromPageMetadata(page);
if (!string.IsNullOrEmpty(localFilename))
{
page.Localize();
if (page.TryCheckOut())
{
page.FileName = localFilename;
page.Save(true);
}
}
}
public void UnlocalizePageOncePublished(Page page, SetPublishStateEventArgs args, EventPhases phase)
{
string localFilename = GetLocalilizedFileNameFromPageMetadata(page);
if (!string.IsNullOrEmpty(localFilename))
page.UnLocalize();
}
private string GetLocalilizedFileNameFromPageMetadata(Page page)
{
string localFilename = string.Empty;
if (page.Metadata != null)
{
ItemFields fields = new ItemFields(page.Metadata, page.MetadataSchema);
if (fields.Contains("LocalizableMeta"))
{
ComponentLinkField localMetaField = fields["LocalizableMeta"] as ComponentLinkField;
Component component = localMetaField.Value;
ItemFields compFields = new ItemFields(component.Content, component.Schema);
if (compFields.Contains("LocalizedPageFilename"))
{
SingleLineTextField fileNameTextField = compFields["LocalizedPageFilename"] as SingleLineTextField;
localFilename = fileNameTextField.Value;
}
}
}
return localFilename;
}
}
Perhaps another option:
Store the localised URL has an additional metadata field for the page, keeping the same physical URL for the published pages.
I see your requirement is to avoid localisation of child pages, I like the way it's possible in wordpress to enter globally how URLs work, for example:
/mysite/%postname%/
It would be cool to build something similar to this within SDL Tridion, where the content title could be extracted and used at the content URL.
Either way, if you'd have to write a system that takes the 'Friendly URL' and does a look up for the actual URL, which I think would be pretty simple.

Tridion 2009 - Publish another Component from a Component Template

First, the overall description:
There are two Component Templates, NewsArticle and NewsList. NewsArticle is a Dreamweaver Template, and is used to display the content of a news article. NewsList is an xml file that contains aggregated information about all of the news articles.
Currently, a content author must publish the news article, and then re-publish the newslist to regenerate the xml.
Problem:
I have been tasked with having the publish of a news article also regenerate and publish the newslist. Through C#, I am able to retrieve the content of the newslist component, generate the updated xml from the news article, and merge it into the xml from the newslist. I am running into trouble getting the newslist to publish.
I have limited access to documentation, but from what I do have, I believe using the static PublishEngine.Publish method will allow me to do what I need. I believe the first parameter (items) is just a list that contains my updated newslist, and the second parameter is a new PublishInstruction with the RenderInstruction.RenderMode set to Publish. I am a little lost on what the publicationTargets should be.
Am I on the right track? If so, any help with the Publish method call is appreciated, and if not, any suggestions?
Like Quirijn suggested, a broker query is the cleanest approach.
In a situation if a broker isn't available (i.e. static publishing model only) I usually generate the newslist XML from a TBB that adds the XML as a binary, rather than kicking off publishing of another component or page. You can do this by calling this method in your C# TBB:
engine.PublishingContext.RenderedItem.AddBinary(
Stream yourXmlContentConvertedToMemoryStream,
string filename,
StructureGroup location,
string variantId,
string mimeType)
Make the variantId unique per the newslist XML file that you create, so that different components can overwrite/update the same file.
Better yet, do this in a Page Template rather than Component Template so that the news list is generated once per page, rather than per component (if you have multiple articles per page).
You are on the right tracks here with the engine.Publish() method:
PublishEngine.Publish(
new IdentifiableObject[] { linkedComponent },
engine.PublishingContext.PublishInstruction,
new List() { engine.PublishingContext.PublicationTarget });
You can just reuse the PublishInstruction and Target from the current context of your template. This sample shows a Component, but it should work in a page too.
One thing to keep in mind is that this is not possible in SDL Tridion 2011 SP1, as the publish action is not allowed out of the box due to security restrictions. I have an article about this here http://www.tridiondeveloper.com/the-story-of-sdl-tridion-2011-custom-resolver-and-the-allowwriteoperationsintemplates-attribute

Resources