In many of the solutions we develop with Sitecore, for external links, we need to add the nofollow noopener noreferrer values of the rel attribute for the <a> tags to have a final markup like this.
1 2 3 4 5 6 | <span class="token tag"><span class="token punctuation"><</span>a <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://www.example.com<span class="token punctuation">"</span></span> <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_blank<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>nofollow noopener noreferrer<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Go to the page <span class="token tag"><span class="token punctuation"></</span>a<span class="token punctuation">></span></span> |
These values allow us to
- nofollow: Tells search engines not to follow the link.
- noopener: Stops the new page from controlling the original page.
- noreferrer: Hides the link source from the new page.
With this goal in mind, we are going to see in this tutorial a proposal to add the rel attribute in an elegant way in our solution.
Sitecore Link Attributes Settings Item
The goal will be to add the values nofollow, noopener noreferrer to the attribute, but it does not necessarily have to be for all external links. Exceptions could surely be established according to the client’s needs. Keeping these considerations in mind, in Sitecore, we can define the following template, with its respective standard values.
Template
Standard Values
The logic on the .NET side
To obtain the attribute and its values to add to external links, we will use a helper that allows sending the URL to be analyzed as a parameter and returning the expected attribute or an empty string from a view.
C# Code
In the helper, we will have to obtain the values of the settings item specified above, and to have a better performance of this solution, we will add the setting values to the cache to obtain them quickly later.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-static">static</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">LinkAttributesHelper</span> <span class="token punctuation">{</span> <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-static">static</span> <span class="token class-name">LinkAttributesSettings</span> _linkAttributesSettings <span class="token operator">=</span> <span class="token keyword keyword-null">null</span><span class="token punctuation">;</span> <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-static">static</span> <span class="token return-type class-name"><span class="token keyword keyword-string">string</span></span> <span class="token function">GetLinkAttributes</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword keyword-string">string</span></span> url<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>Sitecore<span class="token punctuation">.</span>Context<span class="token punctuation">.</span>PageMode<span class="token punctuation">.</span>IsExperienceEditor<span class="token punctuation">)</span> <span class="token keyword keyword-return">return</span> <span class="token keyword keyword-string">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">IsAbsoluteUrl</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword keyword-return">return</span> <span class="token keyword keyword-string">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span><span class="token keyword keyword-string">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword keyword-return">return</span> <span class="token keyword keyword-string">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> settings <span class="token operator">=</span> <span class="token function">GetLinkAttributesSettings</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>settings <span class="token operator">==</span> <span class="token keyword keyword-null">null</span><span class="token punctuation">)</span> <span class="token keyword keyword-return">return</span> <span class="token keyword keyword-string">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span><span class="token keyword keyword-string">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>settings<span class="token punctuation">.</span>RelAttributeValues<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword keyword-return">return</span> <span class="token keyword keyword-string">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span><span class="token keyword keyword-string">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>settings<span class="token punctuation">.</span>WhitelistedDomains<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token operator">!</span>settings<span class="token punctuation">.</span>WhitelistedDomains<span class="token punctuation">.</span><span class="token function">Split</span><span class="token punctuation">(</span><span class="token char">' '</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Any</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword keyword-return">return</span> <span class="token keyword keyword-string">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> isWhitelistedDomain <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token keyword keyword-foreach">foreach</span> <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword keyword-var">var</span></span> domain <span class="token keyword keyword-in">in</span> settings<span class="token punctuation">.</span>WhitelistedDomains<span class="token punctuation">.</span><span class="token function">Split</span><span class="token punctuation">(</span><span class="token char">' '</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>url<span class="token punctuation">.</span><span class="token function">Contains</span><span class="token punctuation">(</span>domain<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> isWhitelistedDomain <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>domain <span class="token operator">==</span> <span class="token string">"'self'"</span> <span class="token operator">||</span> domain <span class="token operator">==</span> <span class="token string">"self"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>url<span class="token punctuation">.</span><span class="token function">Contains</span><span class="token punctuation">(</span>Sitecore<span class="token punctuation">.</span>Context<span class="token punctuation">.</span>Site<span class="token punctuation">.</span>HostName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> isWhitelistedDomain <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword keyword-return">return</span> <span class="token operator">!</span>isWhitelistedDomain <span class="token punctuation">?</span> <span class="token interpolation-string"><span class="token string">$"rel=\"</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">settings<span class="token punctuation">.</span>RelAttributeValues</span><span class="token punctuation">}</span></span><span class="token string">\""</span></span> <span class="token punctuation">:</span> <span class="token keyword keyword-string">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-static">static</span> <span class="token return-type class-name"><span class="token keyword keyword-bool">bool</span></span> <span class="token function">IsAbsoluteUrl</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword keyword-string">string</span></span> url<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword keyword-return">return</span> Uri<span class="token punctuation">.</span><span class="token function">TryCreate</span><span class="token punctuation">(</span>url<span class="token punctuation">,</span> UriKind<span class="token punctuation">.</span>Absolute<span class="token punctuation">,</span> <span class="token keyword keyword-out">out</span> _<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-static">static</span> <span class="token return-type class-name">LinkAttributesSettings</span> <span class="token function">GetLinkAttributesSettings</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> modelMapper <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">ModelMapper</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// To get the values of an Item</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> cacheManager <span class="token operator">=</span> ServiceLocator<span class="token punctuation">.</span>ServiceProvider<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetService</span><span class="token generic class-name"><span class="token punctuation"><</span>ICacheManager<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> cacheKey <span class="token operator">=</span> <span class="token interpolation-string"><span class="token string">$"link-attributes-</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp"><span class="token operator"><</span>YourLinkAttributesSettingsItem<span class="token operator">></span><span class="token punctuation">.</span><span class="token function">ToShortID</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">;</span> _linkAttributesSettings <span class="token operator">=</span> cacheManager<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Get</span><span class="token generic class-name"><span class="token punctuation"><</span>LinkAttributesSettings<span class="token punctuation">></span></span></span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>_linkAttributesSettings <span class="token operator">==</span> <span class="token keyword keyword-null">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> _linkAttributesSettings <span class="token operator">=</span> modelMapper<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">MapItemToNew</span><span class="token generic class-name"><span class="token punctuation"><</span>LinkAttributesSettings<span class="token punctuation">></span></span></span><span class="token punctuation">(</span> Sitecore<span class="token punctuation">.</span>Context<span class="token punctuation">.</span>Database<span class="token punctuation">.</span><span class="token function">GetItem</span><span class="token punctuation">(</span><span class="token operator"><</span>YourLinkAttributesSettingsItem<span class="token operator">></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> cacheManager<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">,</span> _linkAttributesSettings<span class="token punctuation">,</span> TimeSpan<span class="token punctuation">.</span><span class="token function">FromMinutes</span><span class="token punctuation">(</span><span class="token number">30</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-return">return</span> _linkAttributesSettings<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">LinkAttributesSettings</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">RawValueOnly</span></span><span class="token punctuation">]</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name"><span class="token keyword keyword-string">string</span></span> RelAttributeValues <span class="token punctuation">{</span> <span class="token keyword keyword-get">get</span><span class="token punctuation">;</span> <span class="token keyword keyword-set">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">RawValueOnly</span></span><span class="token punctuation">]</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name"><span class="token keyword keyword-string">string</span></span> WhitelistedDomains <span class="token punctuation">{</span> <span class="token keyword keyword-get">get</span><span class="token punctuation">;</span> <span class="token keyword keyword-set">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
View code
From the view of a component, we can have something like this.
1 2 3 4 | <span class="token tag"><span class="token punctuation"><</span>a <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>@Model.Url<span class="token punctuation">"</span></span> <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>@Model.Target<span class="token punctuation">"</span></span> <span class="token attr-name">@Html.Raw(LinkAttributesHelper.GetLinkAttributes(Model.Url))</span><span class="token punctuation">></span></span> @Model.Text <span class="token tag"><span class="token punctuation"></</span>a<span class="token punctuation">></span></span> |
Note. For this example, we assume that the Model object has the attributes of a General Link, that is, the URL and the Target.
Thanks for reading!
ASP.NET 8.0.7 Hosting Recommendation
ASP.NET is a powerful platform for creating web applications and services. You must be comfortable with JavaScript, HTML, CSS, and C# before developing a web application in ASP.NET. On the market, there are thousands of web hosting companies providing ASP.NET Hosting. But, only very few web hosting companies could provide high quality ASP.NET hosting solution. ASP.NET is the best development language in Windows platform, which is released by Microsoft and widely used to build all types of dynamic Web sites and XML Web services. With this article, we’re going to help you to find the best ASP.NET Hosting solution in Europe based on reliability, features, price, performance and technical support. After we reviewed about 30+ ASP.NET hosting providers in Europe, our Best ASP.NET Hosting Award in Europe goes to HostForLIFE.eu, one of the fastest growing private companies and one of the most reliable hosting providers in Europe.