Search code examples
sitecoresitecore6sitecore7sitecore7.2

Add nofollow attribute to each <a> tag with external link after the page was rendered


Customer has requested, that all links to external pages in our sitecore solution should have a nofollow attribute. Which pipeline should I use to have an access to response html (to change the links before they will be delivered with markup to browser)? Or is there any better solution to accomplish this?

JavaScript is not much helpful here because I am not sure if all search engines are able to run JavaScript.

RenderField processor is also not usable, due to many custom tags in our code


Solution

  • You can use the Sitecore.Pipelines.HttpRequest And patch after the ExecuteRequest.

    On this point you have the fully rendered html, including all cached components from the HTML cache.

    Edit add a Example:

    #region Using
    using System;
    using System.IO;
    
    using Sitecore.Pipelines.HttpRequest;
    
    #endregion
    
    namespace MySpace.Sitecore.Pipelines
    {
    
        public class MyProcessor : HttpRequestProcessor
        {
    
            public override void Process(HttpRequestArgs args)
            {
    
                if (!global::Sitecore.Context.PageMode.IsPageEditor)
                {
                    if (!args.Context.Request.RawUrl.Contains(".") || (args.Context.Request.RawUrl.ToLower().Contains(".aspx") && !args.Context.Request.RawUrl.ToLower().StartsWith("/sitecore")))
                    {
                        args.Context.Response.Filter = new MyInterestFilter(args.Context.Response.Filter);
                    }
                }
            }
    
            #region Stream filter
    
            public class MyInterestFilter : Stream
            {
    
                public MyInterestFilter(Stream sink)
                {
                    _sink = sink;
                }
    
                private Stream _sink;
    
                #region Properites
    
                public override bool CanRead
                {
                    get { return true; }
                }
    
                public override bool CanSeek
                {
                    get { return true; }
                }
    
                public override bool CanWrite
                {
                    get { return true; }
                }
    
                public override void Flush()
                {
                    _sink.Flush();
                }
    
                public override long Length
                {
                    get { return 0; }
                }
    
                private long _position;
    
                public override long Position
                {
                    get { return _position; }
                    set { _position = value; }
                }
    
                #endregion
    
                #region Methods
    
                public override int Read(byte[] buffer, int offset, int count)
                {
                    return _sink.Read(buffer, offset, count);
                }
    
                public override long Seek(long offset, SeekOrigin origin)
                {
                    return _sink.Seek(offset, origin);
                }
    
                public override void SetLength(long value)
                {
                    _sink.SetLength(value);
                }
    
                public override void Close()
                {
                    _sink.Close();
                }
    
                public override void Write(byte[] buffer, int offset, int count)
                {
                    byte[] data = new byte[count];
                    Buffer.BlockCopy(buffer, offset, data, 0, count);
                    string html = System.Text.Encoding.Default.GetString(buffer);
    
                    html = MyReplace(html);
    
                    byte[] outdata = System.Text.Encoding.Default.GetBytes(html);
                    _sink.Write(outdata, 0, outdata.GetLength(0));
                }
    
                public static string MyReplace(string html)
                {
    
                     html = html.Replace("TESTSTRING", "REPLACEDTESTSTRING");
    
                    return html;
                }
    
                #endregion
    
            }
    
            #endregion
    
        }
    }
    

    And set a patch file in the App_Config include directory somethings like this:

    <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
      <sitecore>
        <pipelines>
          <httpRequestBegin>
            <processor type="MySpace.Sitecore.Pipelines.MyProcessor, MySpace.Sitecore" patch:after="processor[@type='Sitecore.Pipelines.HttpRequest.ExecuteRequest, Sitecore.Kernel']"/>
          </httpRequestBegin>
        </pipelines>
      </sitecore>
    </configuration>