December 31, 2014

Different API and Extension points in Tridion CM

Sdl Tridion can be customized at various levels as it provides very rich APIs to extend it. Tridion has different extension points for CM and CD. i will try to cover maximum extension points below.

Content Management

APIs

1) Tom.net: Tom.net is .net based API, it runs and CM machine. it allows to you to interact from CM machine only.  Tom.net provides various methods to be used for Templating, Event System. This is Read/Write API, but write operations are by default off in config.

2) Core Service - Core service is WCF service which expose various APIs to interact with CM system. it provide CRUD methods to operate on various CMS Objects. Main use-case of core-service is when you need to interact with CM machine from different machine other than CM or if you want to integrated CM with some third party system. It was introduced in Tridion 2011 (to replace existing COM based APIs) and still in use. It is also used in Workflows
e.g:  you need to read some Xml and create components in Tridion CM.

3) Anguilla: It is used to extend Content Manager Explorer(CME) user interface. eg. you want to introduce new buttons and new functionality in CME. e.g Custom spell checker, custom publishing, extend paste functionality. It was introduced in Tridion 2011 and still in use.

4) ECL : External Content Library was introduced in Tridion 2013, its very useful and awesome API available in Tridion. It allows to list/integrate external content repositories  third-party content/media in CMS and allow you to use it as native components with little exception. The access point looks just like a normal folder, making it easy to manage.
e.g . User want to see all images of DAM into CM system, want to view You tube or Dailymotion videos in CM interface to use in the components. 

Extension Points:

5) GUI Extensions - Its used to extend/customized the CMS UI. anguilla, JS and .net are used to create a GUI extension.

6) Events: Tridion provides Events as extension point where you can capture particular event and provide some customization. one of the most used use-case is validation of data. so when user save the component, save even can be captured and validate the data, log the data etc.

7) Custom Resolver: A resolver basically read an item from the publishing-queue and returns a list of items to be rendered. Tridion has kept it extensible so if you want to override default resolving behavior.
e.g when a component is resolved, by default all the component that links to this component are also resolved and so on. so it gives very long queue and impact the performance also, so if you want to resolve only this component or level 1 component this can be extended and registered in the TridionContentManager.config file.

8) Custom Page: Custom Pages can be used to perform operations in the Content Manager that are not supported by the default UI(user interface) . e.g, create a Custom Page that talks with the Core Service to automate Page creation. it can also be used to customize dashboard for users.

December 16, 2014

Anchor in Tridion Component links

In Tridion Link Anchor (jump to specific section of the page) is very tricky. there is an out of the box anchor option. let discuss that first.

Anchor OOTB : In component link there is an attribute "Add Anchor"

<tridion:ComponentLink runat="server" PageURI="tcm:85-159563-64" ComponentURI="tcm:85-159309" TemplateURI="tcm:0-0-0" AddAnchor="true" LinkText="internal link test" LinkAttributes=" title= &#34;alt text for link &#34;" TextOnFail="true"/>

when this AddAnchor = true is set. Tridion CD will create anchor for particular components as per their position of the page.

e.g following is a Tridion page sompage.aspx having three components Comp 1 and Comp 2 and Comp 3

------------
Comp 1
---------
Comp 2
---------
Comp 3
---------------

e.g you use comp2 as component link on another page. it will be resolved as somepage.aspx#1
so this is as per the position of the component on page.

another catch is you have to create <a id="1"> on somePage explicitly using your templates. this is not automated.

Custom solution:
As OOTB solution is base on numbers only. if you want to based it on some text e.g #Intro. you need some customization for it.

I have develop & tested this small solution for it.
------------------------------------------------------------------------------------------------------------
namespace  CD.Web.ComponentLink.Extensions
{
    public class ComponentLink : Tridion.ContentDelivery.Web.UI.ComponentLink
    {
        [DefaultValue("None")]
        [Bindable(true)]
        [Category("Appearance")]
        public string AnchorName { get; set; }


        protected override void Render(HtmlTextWriter writer)
        {
            if (HttpContext.Current == null || HttpContext.Current.Application == null)
                return;
            using (var compLink = new Tridion.ContentDelivery.Web.Linking.ComponentLink(new TcmUri(ComponentUri).PublicationId))
            {
             
                var link = compLink.GetLink(PageUri, ComponentUri, TemplateUri, LinkAttributes, LinkText, TextOnFail, AddAnchor);
                link.Anchor = AnchorName;
             
                string linkAsString = link.ToString();
                writer.Write(linkAsString);
                this.RenderChildren(writer);
            }
        }

    }

}
------------------------------------------------------------------------------------------------------


  • Register above custom control in your website's web.config 
  • Update schema to accept the Anchor from Editor
  • Update template code to pass this anchor name as mention below

<Rk:ComponentLink runat="server" PageURI="tcm:85-159563-64" ComponentURI="tcm:85-159309" TemplateURI="tcm:0-0-0" AnchorName="true" AddAnchor="false" LinkText="internal link test" LinkAttributes=" title= &#34;alt text for link &#34;" TextOnFail="true"/>

do post comments if you have any questions.

December 09, 2014

CXM: Customer Experience Managment-tridion


Customer Experience Management (CXM) is a strategy and practice for managing customer
experiences online and offline to acquire, retain, and turn customers into satisfied, loyal brand
advocates and ambassadors.(Wiki)

I heard this acronym around 1.5 year back in a discussion and then found lots of  information from Forrester and RealstoryGroup.

Some says" is nothing more than a feature arms race between companies that have latched onto a false "next big thing". These features were not developed in response to actual customer needs or requests. I never hear anyone talking about CXM except for CMS vendors and analysts."

As per my view, CXM Make sense in lots of context.

Following example describe a particular experience of an user. and how different type of module/systems enhance the experience of user.

Experience:
  1. Raj get to know of discount on newly launched restaurant in his Area via a Ad on search engine - Ads
  2. He browse the restaurant website on his Mobile. - Mobile Delivery
  3. Check few restaurant picture and details -  DAM/MAM
  4. Then Browse the reviews of restaurant on the website and yelp!! - Reviews, Ratings
  5. Raj also checks restaurant 's Facebook page for more reviews. - Social Share, Social Listening.
  6. He finally calls their customer care to book the restaurant. - Customer care

if we replace restaurant with a Mobile phone.

  1. Customer buy the phone from the Website. E-commerce
  2. Website also add some loyalty points for his buying which could be later on used for buying some other product. - Loyalty management 
  3. Share the review on website & his joy on Social media.
  4. On revisiting the website, website come up with accessories and other stuff related to his past browsing and buying experience.  Personalization. 
  5. Vendor sends him various coupons/products information or email on his mobile/mail - Coupon management, Campaigning
CXM Technology Ecosystem

   IMAGE Courtesy:  rEALsTORY gROUP

SDL Tridion as CXM Capabilities.


Recently SDL launched new offering SDL Customer Experience Cloud which is an SaaS based solution and provide provide most of the features from above pictures on cloud in integrated mode. It seems very promising and give a leg-up to SDL in very competitive CMS world. 

November 25, 2014

Tridion: Image handling in Responsive design.

In responsive websites, we usually keep different breakpoints for different devices & different breakpoints require different image sizes. There are different ways to use images in responsive layouts.
  • Same image on all Devices
  • Manual upload of device specific Image
  • Generate images on Fly.
  • Tridion CID
Same image on all devices: This is simplest of all as point of development, let user upload single image and same image is published on delivery. But there are few points which needs to be taken care for this.

UI Designer has to maintain the aspect ratio in his designs across Desktop, tablet, mobile or whatever breakpoints you have. e.g

Desktop:  200  : 100
Tablet:      100 :  50
Mobile:     50:    25

so if you see the aspect ration has been maintained at 2:1.  so Maintaining aspect-ratio is very important as it can go haywire if the objects start scaling based on the screen dimension. To maintain aspect ratio of the objects, select Auto for either width or height of the object in the Primary view

Tridion side there is no special change is required. normal image publishing.

Cons: Mobile has to download the same big image, which could be bandwidth issue, also in sites where lots of images are used, this approach on tablet/mobile would not be considered best

Manual upload of device specific Image:  There are different reasons where device specific images are required:
  • Designers are not totally versed with it. so ratios are not maintained  across devices
  • Performance and bandwidth issue
  • For mobile instead of whole image only part of image is required for more cleared and focused view.
these images could be manually-generated or from some DAM System.

Tridion Implementation:

Create a category with Keywords having device information. 
Category : Device Type
Keywords - large, medium, small

Create a embedded schema "Responsive Multimedia" as shown below
ScreenSize refer above category.

For this we created a generic helper class in razor, it generate the Data-Interchange tags in images. We are using Foundation Framework for handle responsiveness of site  here. 

<img data-interchange="[@Publication.MultimediaUrl/@mobile, (default)], [@Publication.MultimediaUrl/@tablet, (medium)], [@desktop, (large)]"></img>

Now you can read the component and read the values of uploaded images and generate the image tag with data-interchange as shown above. 

Generate images on Fly  Other approach is to upload a single image and generate the rest of the device specific images on Fly using custom code. But design should maintain aspect ratio of the images. 

Tridion code: we have written a c# tbb to handle it, here is the code for it. you can customize it 

[TcmTemplateTitle("AddAssets")]
    public class AddAssets : TemplateBase
    {
        
        public override void Transform(Engine engine, Package package)
        {
            Initialize(engine, package);
            var items = m_Package.GetEntries();
            var dynamicbinaries = new Dictionary<string, string[]>();
            foreach (var i in items)
            {
                Logger.Info(i.Key + ":" + i.Value);

                if (i.Key != "GenerateDynamic") continue;
                Logger.Info("Generate Dynamic parsing:");

                var arr = i.Value.GetAsString();
                var binaries = arr.Split(',');

                dynamicbinaries.Add(binaries[0], binaries);
           }

            var allowedContentTypes = new Dictionary<ContentType, ImageFormat>()
                                   {
                                       {ContentType.Bmp, ImageFormat.Bmp},
                                       {ContentType.Jpeg, ImageFormat.Jpeg},
                                       {ContentType.Png, ImageFormat.Png},
                                       {ContentType.Gif, ImageFormat.Gif}
                                   };
            foreach (var contentType in allowedContentTypes.Keys)
            {
                foreach (var item in package.GetAllByType(contentType))
                {
                    if (dynamicbinaries.ContainsKey(item.Properties[Item.ItemPropertyTcmUri]))
                    {
                        InsertRelatedBinaries(item, allowedContentTypes[contentType], dynamicbinaries[item.Properties[Item.ItemPropertyTcmUri]]);
                    }
                }

            }
        }

        private void GenerateDeviceSpecificBinaries(Item item, ImageFormat imageFormat, string[] binary)
        {

            var mmc = new Component(new TcmUri(item.Properties[Item.ItemPropertyTcmUri]), m_Engine.GetSession());

            var binaryContent = mmc.BinaryContent;
            var binaryBytes = binaryContent.GetByteArray();
            using (var bitmap = new Bitmap(new MemoryStream(binaryBytes)))
            {
                var tabPercentage = Int32.Parse(m_Package.GetValue("TabPercentage"));
                var mobilePercentage = Int32.Parse(m_Package.GetValue("MobilePercentage"));
                var resizedBitmap = ResizeBitmap(bitmap, tabPercentage);
                AddBitmapAsBinary(item, imageFormat, mmc, binaryContent, resizedBitmap, "2", binary[2]);//Tablet Images

                resizedBitmap = ResizeBitmap(bitmap, mobilePercentage);

                AddBitmapAsBinary(item, imageFormat, mmc, binaryContent, resizedBitmap, "3", binary[1]); // Mobile Images
                resizedBitmap.Dispose();
            }
        }

        private void AddBitmapAsBinary(Item item, ImageFormat format, Component mmc, BinaryContent binaryContent, Bitmap resizedBitmap, string variant, string filename)
        {
            var resizedStream = new MemoryStream();
            resizedBitmap.Save(resizedStream, format);
            var binary = this.m_Engine.PublishingContext.RenderedItem.AddBinary(
                resizedStream, filename, variant, mmc,
                binaryContent.MultimediaType.MimeType);
            resizedStream.Dispose();
        }

        private Bitmap ResizeBitmap(Bitmap sourceBitmap, int per)
        {
          
                var sourceWidth = sourceBitmap.Width;
                var sourceHeight = sourceBitmap.Height;

                float nPercentW = per;
                float nPercentH = per;

                var  destWidth = (int)(sourceWidth * (nPercentW / 100));
                var  destHeight = (int)(sourceHeight * (nPercentH / 100));
           

            var resultBitmap = new Bitmap(destWidth, destHeight);
            var graphicsd = Graphics.FromImage(resultBitmap);
            graphicsd.InterpolationMode = InterpolationMode.HighQualityBicubic;

            graphicsd.DrawImage(sourceBitmap, 0, 0, destWidth, destHeight);
            graphicsd.Dispose();

            return resultBitmap;
        }

    }
}

Tridion CID  Contextual Image delivery  is a product from SDL which helps in transforming the images in various ways such as
  • Resize with Cropping
  • Resize without Cropping
  • Trim image
  • Change Image format
Please read this very good article for further explanation of this module. What Does Contextual Image Delivery Mean for SDL Tridion Images?