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
Related
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.
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..
When we publish some page/dynamic component from tridion is it possible to add some external multimedia file/content(ex:jpg image) in to current executing/rendering package at publish time.So that final transportation package has this binary file present along with original published content?
Is this achivable using customization of tridion renderer/resolver?If yes please provide some inputs.
*Note:*The binary content that needs to be pushed in to package at publish time is not present as multimedia component in tridion, it is located at other file location outside tridion CMS.Instead we have some stub multimedia component being used inside published component/page which has some dummy image. we plan to replace the stub image with original image at publish(rendering/resolving) time.
Since we have huge bulk of binary content stored in DAM tool we dont want that data to be recreated as multimedia component in tridion, insted we want to use that data by querying DAM tool and attach it in to tridion package with some logical referencesplanning to maintain one to one mapping between stub multimedia comp tcmid to original content in some mapping DB for reference).
Please let us know if any solution is there to attach external binary content to package at publish time.
The best - and easiest way - is to use the mechanism provided by Tridion out-of-the-box for this. Create a new multimedia component, select "External" in the resource type drop-down, and type the URL to the object. As long as you can address it with a URL, it will work exactly as you want (item will be added to package and sent to delivery server).
If this is not good enough for you, then yes, you can add it to the package yourself. I've done this in the past with code somewhat like this:
FileInfo file = // Weird logic to get a FileInfo object from external system
Item item = package.GetItem("My original Item");
item.SetAsStream(file.OpenRead());
This replaced the content of my original component with the actual file I wanted. This will work for you IF the original component is also a multimedia component. If it's not, just create a new item with your own name, etc. If possible, do use the out-of-the-box process instead.
PS: FileInfo Class.
As Nuno suggested the best way is to use multimedia component with 'External' resource type. You may not need to create these manually, you can automate using core services or API programs.
Another way I used before to create zip file at run time and add same to package with following code. Hope it may help.
using (MemoryStream ms = new MemoryStream())
{
zip.Save(ms);
downloadAllInOneURL = String.Format("ZipAsset{0}.zip", uniqueZipID);
downloadAllInOneURL = m_Engine.PublishingContext.RenderedItem.AddBinary(ms, downloadAllInOneURL, "", "application/zip").Url;
downloadAllInOneSize = getSize(ms.Length);
}
We are using custom-written proxy class for handling the Web Service communication provided by Mihai Cadariu (screenshot attached) for resolving dynamic linking.
For forming the LinkUrl parameters to resolve dynamiclink/component link we are following the below sample approach. But its throwing error (stacktrace,debug error)attached .Please validate and provide the inputs where we are going wrong. Please let us know the parameters we are passing are correct or not
Approach we used:
-->We have two components Comp1,Comp2 (can be created of same/different schema guess it not any issue)
-->Comp2 is being used as component link inside Comp1 (we have a component link field in comp1)
-->Created two dynamic CT’s DCT1, DCT2 for each comp (CT’s have simple DWT, Default finish actions)
Note: also tried keeping DD4T TBBs in similar set of CT’s as other approach but final got same error result
-->DWT code has --> SomeLink (to render component link so that LinkResolver TBB will resolve the links)
Also kept OTHWayLink (for cross checking)
-->Created two Pages Page1 (has Comp1+DCT1), Page2 (has Comp2 +DCT2) and published both pages to broker DB
-->Our goal is to resolve component link (Comp2) which is present inside Comp1 content so,
-->For GetDynamicLink() we provided parameters as given below. Which throwed error :400 (bad request) and exception in log trace attached above.
Param’s List --> string targetPageUri, string targetComponentUri, string targetTemplateUri, string linkText, bool showTextOnFail, string linkTagAttributes
Param’s we passed--> Page2 tcmid, Comp2 tcmid, DCT2 tcmid ,”some link txt”,true,”some string”;
-->For GetComponentLink()we provided parameters as given below. In this case we tried keeping both dynamic and non dynamic CT’s combination inside pages, Which also throwed error :400 (bad request) and exception in log trace attached above.
Param’s List --> string targetComponentUri, string sourcePageUri, string excludeTemplateUri, string linkText, bool showTextOnFail, bool showAnchor, string linkTagAttributes
Param’s we passed --> Comp2 tcmid, Page1 tcmid, DCT1 tcmid, “some link txt”,true,true,”some string” ;
we are refering Live documentation for Linking.
Mihai Proxy Code sample:
Error message:
Looks to me like your odata website is not set up correctly in d:/inetpub/wwwroot/odata/bin as the error message is that Classes are not found.
Can you confirm you've installed/placed the correct SDL Tridion dll/lib and configuration XML files into your website?
Here is a great post about how SDL Tridion loads these files: http://www.tridiondeveloper.com/how-tridion-content-delivery-loads-configuration-files-in-dotnet I'm sure once you've got the Odata application/website up and running this will work correctly for you.
The Content Delivery linking service's parameters are documented on this page (log in required). I'll paste an excerpt below, but you really should simply compare your strings to the parameters mentioned on that page.
Component Links
Command:/linking/componentLink (Java) or /linking.svc/componentLink (.NET)
Input parameters:
Parameter name Default value
sourcePageURI (none)
targetComponentURI (none)
excludeTemplateURI (none)
linkTagAttributes (empty)
linkText (empty)
showTextOnFail true
showAnchor false
From cross-checking these with the code you pasted in the screenshot, everything seems to line up.
That answer your question. But I doubt it solves your problem, since that seems (as John Winter suggested) more infrastructural: you're missing cd_link.jar in the relevant directory.
If you find it difficult to diagnose this problem further, I suggest contacting the original author of this custom code (or SDL or one of its partners). This will ensure you get help from someone who is experienced in troubleshooting the loading of JARs, DLLs and configuration files.
Using Tridion Core Service, how can I get all the items in a folder?
You need a filter (OrganizationalItemItemsFilterData).
Then you need to call client.GetList(folderId, filter) to get the list of items in that folder.
OrganizationalItemItemsFilterData filter = new OrganizationalItemItemsFilterData();
foreach (XElement element in client.GetListXml("tcm:3-640-2", filter).Nodes())
{
Console.WriteLine(element.Attribute("ID").Value);
}
A good example on how to use the Core Service which contains all sorts of read operations (like reading a single item and getting a list of items) is shown in the following eXtension on SDL Tridion World: Item Selector Custom URL
The download on SDL Tridion World comes with complete source but this can also be found directly on Google Code where it is hosted as an open source solution. The actual Core Service code can be found in the UserControls/TridionTreeView.ascx.cs Class.