Blog posts by Per Nergård2020-02-14T14:14:42.0000000Z/blogs/Per-Nergard/Optimizely WorldDeveloper meetup i Göteborg/blogs/Per-Nergard/Dates/2020/2/developer-meetup-in-gothenburg/2020-02-14T14:14:42.0000000Z<p>Knowit och Episervers meetup i Malmö var en succé så nu kör vi den även i Göteborg den 3e mars. Så om man är intresserad av att höra mer om vad som är på gång inom .Net core eller lära sig mer om Episervers nya referens arkitektur "Foundation" ska man genast klicka sig vidare till meetup sidan och anmäla sig. Kan ni inte gå just detta tillfälle passa på att gå med i gruppen så att ni inte missar kommande events!</p>
<p><a href="https://www.meetup.com/EPiServer-utvecklare-Goteborg/events/268705786/">https://www.meetup.com/EPiServer-utvecklare-Goteborg/events/268705786/</a></p>
Developer meetup in Malmö/blogs/Per-Nergard/Dates/2020/1/developer-meetup-in-malmo/2020-01-27T12:45:35.0000000Z<p>After a long slumber in the Episerver Developers Öresund group Knowit and Episerver is kicking off 2020 with a developer meetup in Malmö february 6.</p>
<p>Episerver .Net Core and the new reference project Episerver Foundation is the topics of the evening.</p>
<p>So if you are in the Öresund area come and join us.</p>
<p>See below link to sign up!</p>
<p><a href="https://www.meetup.com/EPiServer-utvecklare-Oresund/events/267933749/">https://www.meetup.com/EPiServer-utvecklare-Oresund/events/267933749/</a></p>Use a page type as a scheduledjob/blogs/Per-Nergard/Dates/2020/1/scheduledjobs-ish-with-input-parameters/2020-01-21T09:55:36.0000000Z<p>Scheduledjobs have evolved a bit over the years but they still lack a nice way to have input parameters. If you don't hard code everything I see the following alternatives.</p>
<ul>
<li>Appsettings<br />Works but can only be done by a developer with access to the server environment. Causes a restart of the website.<br /><br /></li>
<li>Properties on a page<br />I really like using a builtuin way to get a nice editorial experience when setting parameters. But having to view logs / status in admin mode and change settings in edit mode feels a bit disconnected. And I think that admin-mode access for non developers should be kept to an absolute minimum.<br /><br /></li>
<li>Extending the builtin views in admin mode<br />Mathias Kunto did a nice implemantation where you can extend the builtin views with the help of control adapters. You can read his blog post <a href="https://blog.mathiaskunto.com/2014/03/21/scheduled-jobs-with-input-parameters-in-episerver-7-5/">here</a>.</li>
</ul>
<p>So hardcoding and using appsettings is out of questions but I really like using builtin editorial features for a smooth experience but mixing edit and admin mode together makes is hard to understand. Mathias way is for sure the most "integrated" way of doing it, but is in admin mode which is still in webforms and for some jobs I would like a more granular control over who can handle specific jobs without giving access to everything in admin mode.</p>
<p>So here is a proof of concept of the solution I came up with: A page type that after initial publish it automatically sets it self for scheduled publishing according to the preffered interval and all work is done during the publishing event.</p>
<p>To get everything up and running we need a specific page type which have all the settings we want and the model will contain all code that do the actual scheduledwork and handling logging. We also need an initalizationmodule hooking up to the PublishingContent and PublishedContent events. And of course the schedulejob handling future publishing of content must be up and running.</p>
<p>The page type is lika any normal page type but it contains one method that will perform all work and log a status message to a IList property:</p>
<pre class="language-csharp"><code>public void DoTheMagic()
{
if (this.HistoryLog == null) this.HistoryLog = new List<Log>();
var message = new Log
{
Date = DateTime.Now.ToString(),
Message = "We did som magic!",
ExecutedBy = "The logged in user"
};
this.HistoryLog.Add(message);
}</code></pre>
<p>In the initaliziationmodule PublishingContent event if the content is of the correct type we call the DoTheMagic method. We need to do it in the publishing event because we are creating a log message and adds it to the logging IList property and we need to have the object in a writable state.</p>
<pre class="language-csharp"><code>private void ToolPageInitializationModule1_PublishingContent(object sender, EPiServer.ContentEventArgs e)
{
var page = e.Content as ToolPage;
if (page != null)
{
page.DoTheMagic();
}
}</code></pre>
<p>To hande setting the new scheduled publish date we need to to it in the PublishedContent event. Trying to change the date in the same event as the DoTheMagic don't work.</p>
<pre class="language-csharp"><code>private void ToolPageInitializationModule1_PublishedContent(object sender, ContentEventArgs e)
{
var page = e.Content as ToolPage;
var writable = page.CreateWritableClone() as ToolPage;
if (page != null)
{
if (page.Interval == "Minute")
{
var date = writable.StartTime = page.StartTime.AddMinutes(page.IntervalValue);
writable.StartPublish = date;
ServiceLocator.Current.GetInstance<IContentRepository>().Save(writable, SaveAction.CheckIn | SaveAction.Schedule, EPiServer.Security.AccessLevel.NoAccess);
}
}
}</code></pre>
<p>So in the editorial interface it looks like this:</p>
<p><img src="/link/fc72859129bc49a4ae9a90764f2feb2e.aspx" /></p>
<p><img src="/link/ae02845bb3474216b1e6f1ef7b62b407.aspx" /></p>
<p>So this is only a simple proof of concept but it does what I set up to do so at this stage Im happy :)</p>Find and delete content based on type/blogs/Per-Nergard/Dates/2019/6/find-and-delete-content-based-on-type/2019-06-17T15:47:46.0000000Z<p>Another blog post and another admin mode plugin..</p>
<p>From time to time I have had the need to delete content for specific types. It could be a cleanup case before using a dev database as UAT or maybe we wan't to discard some content type.</p>
<p>In general content of a specific types tend to be all over the place especially with images and blocks so this can be a tedious process. So I whipped together a small admin mode plugin that lets you select a type and get a list of all content-instances and lets you delete all or selected instances of that type. Nothing fancy but it does it't job.</p>
<p>You can find the code over at my <a href="https://gist.github.com/PNergard/8a1037dcea6918dfc558676bded4e7b9">Gist</a> and it looks lite this.</p>
<p><img src="/link/def33cea04e64ea2add53e51da715fb8.aspx" /></p>Episerver CMS 11 certification - tips and comments/blogs/Per-Nergard/Dates/2019/4/episerver-cms-certification---tips-and-comments/2019-04-13T14:44:20.0000000Z<p>This week it what that time again where I needed to renew my Episerver CMS certificate. So here is a post with some thoughts, comments and tips that hopefully is to some use for others preparing for the exam.</p>
<p>A lot of things have happened in the Episerver world the last couple of years both with the CMS and other products and not least going into the cloud with the DXC.I think this is reflected in the exam. You really need to have a broad knowledge about Episerver both from a developer perspective but also general product knowledge and editorial skills sprinkled with some Find and DXC to pass the exam.</p>
<p>I've been working with Episerver for a long time (maybe too long) and I'm certified in all versions since CMS 5, and although I try to keep myself updated my professional career has drifted away to doing other stuff than coding so I thought that some reading in the development guide probably was a good idea.</p>
<p>I was pleasently suprised that the <a href="/link/f3882e248540406fa3bc4a6858a3b244.aspx">development guide</a> has been updated and include more code examples than before.Also a big improvement is that new features now are clearly marked from which version that feature is available which is great for seasoned developers that really only need to brush up their knowledge on new stuff. The new improved looks on world also really made reading more easy on the eyes.</p>
<p>I'd say that the development guide is the main place to go for information but the <a href="/link/3aa770bc7f0044fb9175c18048c0d2e7.aspx">user guide</a> is a great place to gain knowledge about ie personalization of blocks, and you can learn som useful stuff around environments, deployment, optional extras and service and health continuity in the <a href="https://www.episerver.com/services/descriptions/episerver-dxc-service-description/">DXC service description</a>. And if you haven' used Episerver Find it can be well spent time to play around with how to do searches using different Find features like best bets, stemming, filtering etc. And don't forget to use the Visual Studio extension creating an Alloy sample project and have a look in the code and maybe try out some of the newer features like projects and notifications.</p>
<p>It's alot of material to read through but if you have the time I would really recomend going through it all since the documentation is quite good and even super experienced Episerver proffessionals will learn something new.</p>
<p>Anders G Nordbys <a href="https://andersnordby.wordpress.com/2018/01/09/knowledge-areas-for-the-episerver-cms-certification/">blog post</a> from 2018 is still a very good writeup with general information and hints. </p>
<p>So with this post and Anders blog posts, in combination with putting in some effort I'm sure that pass you will pass the exam.</p>
<p>Oh and the exam I took was for CMS version 11.</p>
<p>Happy certification!</p>AllowedTypes for LinkItem collection/blogs/Per-Nergard/Dates/2019/3/allowedtypes-for-linkitem-collection/2019-04-02T17:29:30.0000000Z<p>The other day I heard a discussion about a possible requirement for only allowing specific pages in a LinkItem collection. My first thought was to use a ContentArea property in combination with the AllowedTypes attribute but for some reason the possiblity to have external links was needed.</p>
<p>I googled a bit but I only found a post where a custom validation class handled validation of max number of items in a LinkItemCollection, you can read Allan Thraens blog post <a href="/link/e7723a75c6a24c6a8c5b952386265817.aspx">here</a>.</p>
<p>It seemed like a clean and simple approach so I decided to do a variant that is similiar to AllowedTypes for ContentArea and ContentReference properties.</p>
<p>My solution is a simple validation attribute that takes an array of types that should be allowed to add to a LinkItemCollection property. The attribute ignores linkitems that are not Episerver content.If an Epierver content (page,image) is added to the LinkItemCollection and the underlying type is not inte the allowed types array a error message is displayed and publishing of the page is blocked.</p>
<p>You can find the coder over at my <a href="https://gist.github.com/PNergard/7df2636b45753a5b9a654447cf64461a">gist</a>.</p>Automatically create pages for ContentReference properties/blogs/Per-Nergard/Dates/2019/2/automatically-create-pages-for-contentreference-properties/2019-02-24T10:56:22.0000000Z<p>If you like me have tried to take an existing solution but wanted to start from scratch, maybe for a demo and you just gave up due to the amount of required properties on for example a settings page? Most of them are probably strings and ints that should be pretty easy to fix (or really should have had good defaults). But what about those pesky properties of type ContentReference which excpects a page of a certain type? And I bet those new pages have more pesky required properties as well! Gaah my blood pressure!</p>
<p>So to come closer to my (pipe?) dream of super easy site site setup even from scratch and using a "mature" solution that has developed over some years I decided to go with an attribute and initmodule approach.</p>
<p>Ok so the attribute is very simple it just takes one parameter with the type we want to get automatically created. So in my example here I have three page types: A startpage that needs a reference to a settingspage which have two references to a searchpage and a newsarchivepage.</p>
<p>So my page type looks like this (RequiredDependec is my custom attribute)</p>
<p><code> [RequiredDependency(typeof(Settings))]<br /> [AllowedTypes(typeof(Settings))]<br /> public virtual ContentReference SettingsPage {get; set;}</code></p>
<p>The settingspage looks like this:</p>
<p><code></code></p>
<p><code> [RequiredDependency(typeof(NewsArchive))]</code><br /><code> public virtual ContentReference NewsArchive { get; set; }</code></p>
<p><code></code></p>
<p><code> [RequiredDependency(typeof(ContactCards))]</code><br /><code> public virtual ContentReference ContactCards { get; set; }</code></p>
<p>To fix the automagic creating and setting or properties I did a initmodule that on the onpublish event scans the underlying type with reflection for properties decorated with the new attribute, creates a new page of that type and sets the property to that reference. The created pages are not automatically published since I name them "Automatically created - <pagetypename>" so I guess atleast the name should be changed before they are published. The new pages are created below the ContentReference.StartPage so the startpage need to be created and a site and start page needs to be configured in admin mode.</p>
<p>Ok so what does it look like:</p>
<p><strong>Here we have a unpublished startpage</strong></p>
<p><img src="/link/ceb6e48cd10844ff8d49f30e7d835939.aspx" /></p>
<p>
<p>
<p><strong>Here we have the automatically created settingspage</strong></p>
<p><img src="/link/20c9e74d5de941c9bfe2681681983b1c.aspx" /></p>
<p>
<p><img src="/link/8ba9a5de715044929895224bbb7439ab.aspx" /></p>
<p>
<p><strong>After publishing the settingspage we have a newsarchive and searchpage created</strong></p>
<p><img src="/link/5190bbc3968345be88f1ef2aba4d4c13.aspx" /></p>
<p>The code is what it is and you use it at your own risk but you can find a complete project over at my Pnergard <a href="https://github.com/PNergard/AutoCreateDependency">GitHub</a>. </p>
<p><code></code></p>
<p><code></code></p></p></p></p></p>Warning before deleting a page that is used in a property decorated with a SelectOne or SelectMany attribute/blogs/Per-Nergard/Dates/2019/2/warning-before-deleting-a-page-that-is-used-in-a-property-decorated-with-a-selectone-or-selectmany-attribute/2019-02-19T16:02:14.0000000Z<p>Long title and I hope it made some sense.</p>
<p>The case is that it's quite common that the underlying data for SelectionFactories which is then used with SelectOne and SelectMany attributes is normal Episerver pages. For example this is used to handle contact-cards in the Alloy site.</p>
<p>But since it's pages there is always a risk that someone by mistake deletes such a page causing problems. We would really like to have Episervers built in is this page used somewhere check.</p>
<p>The fix for a SelectOne attribute is as easy as having the underlying property to be of type ContentReference instead of a string. But if you have a SelectMany the underlying property needs to be a string and the chosen values is just added as a comma separated string.</p>
<p>To fix this for SelectMany I have created a custom attribute and a validation attribute class. When you add a SelectMany attribute where the SelectionFactory returns ContentReferences as id's you also add the new custom attribute which specifies an IList<ContentReference> property. The validation attribute then adds / removes references to the IList property automatically. With this when we try to delete a referenced page we get the builtin reference check functionality.</p>
<p><strong>Pseudo code:</strong></p>
<p>SelectMany(typeof(factoryclass))<br />SelectManyListProperty("ListPropertyName")<br />public virtual string SelectManyProp { get; set; }</p>
<p>public virtual IList ListPropertyName {get; set;}</p>
<p><strong>Before</strong></p>
<p><img src="/link/744223f60a83448f8f45485b136a6dc7.aspx" /></p>
<p><strong>After</strong></p>
<p><img src="/link/b85e3e6027c4481081a50e69849ca8e6.aspx" /></p>
<p>Note that the ContentReference property isn't updated until page is published (values are there) and ofcourse it should be hidden under an other tab or atleast disabled for editors.</p>
<p><a href="https://gist.github.com/PNergard/41d38a7daeb0c92845454d55c630f6f3">Code over at my Gist.</a></p>Plugin for viewing / filtering wastebasket content and delete single content items/blogs/Per-Nergard/Dates/2017/11/plugin-for-viewing--filtering-wastebasket-content-and-delete-single-content-items/2017-11-09T13:47:53.0000000Z<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>From time to time we have the need to delete single content from the waste basket in Episerver. Saddly there is no built in support for this. A year ago <a href="https://gregwiechec.com/2016/06/deleting-single-file-from-trash/">Grzegorz modified</a> the built in waste basket. It's great but I wanted to see some more information about the content and doing a Dojo solution is out of my comfort zone I decided to create yet another admin mode plugin.</p>
<p>It's very simple and uses datatables.js for search / filtering functionality. You can delete all or selected items. See below for what it looks like. Code over at my <a href="https://gist.github.com/PNergard/eba36f8c585419f1b65e27c0bd5f43fe">Gist</a>.</p>
<p><img src="/link/b5890876a6c142c3b6c4b706adb44cfa.aspx" alt="Image wastebasket.jpg" /></p>
</body>
</html>Plugin for viewing scheduled job run history/blogs/Per-Nergard/Dates/2017/9/plugin-for-viewing-scheduled-job-run-history/2017-09-14T22:21:44.0000000Z<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>A couple of times during the years I have had the need to view the scheduled job history log. In all these cases it has been jobs that are running frequently and therefor I need to use the paging since the default view doesn't display that many rows.</p>
<p>So I did a small plugin that let you choose between all scheduled jobs and display all the history in one table. Might not be the oste useful plugin but since I built it can as wll share it. You can find it over at my <a href="https://gist.github.com/PNergard/743e5cb4e0480be7994789b49490cfea">Gist</a>.</p>
<p><img src="/link/2a817b35c4c4458f9c0d2c5020fb933a.aspx" alt="Image logviewer.jpg" /></p>
</body>
</html>Plugin for deleting unreferenced media/blogs/Per-Nergard/Dates/2017/9/plugin-for-deleting-unreferenced-media/2017-09-05T23:12:05.0000000Z<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>Sometimes you need to synch a dev-environment with production database and media and the blob-storage is huge with likely a lot of unreferenced media or perphaps want to clean up a test-environment.</p>
<p>To help in those two scenarios I threw togheter a small plugin that lets you delete all or just selected unreferenced media. Really nothing to say about the code than it can be found over at my <a href="https://gist.github.com/PNergard/952e4225563a27a79b4671ad4dee0412">Gist</a>.</p>
<p>It looks like this:</p>
<p><img src="/link/0a4c82a652fb4defa1cd87926ad2ffd7.aspx" alt="Image cleaner.jpg" /></p>
</body>
</html>MenuProvider for easy display of key settings in a site/blogs/Per-Nergard/Dates/2017/2/menuprovider-for-easy-display-of-important-information/2017-02-26T11:25:07.7930000Z<h2>The problem (perceived at least)</h2>
<p>How many times have you got a question about something or just had the need to do a quick check of some setting or status of something in a site? I guess that it happens more often that you would like. </p>
<p>My experience is that most of the times you can find the answers by loggin in to the site but that you need to click around a bit to find what you are looking for. If unlucky we need to log on to the actual server and check an appsetting or something like that. Not really that hard but wouldn't it be great to have key information about a site in one place?</p>
<p>Atleast I think so, so here comes Overview dashboard to the rescue. (Failed to think of a better name so it will have to do).</p>
<h2>My solution</h2>
<p>So what is it? Overview dashboard is implemented as a menu provider that only has one view. The view uses reflection to look for classes that implements a specific interface and supplies the information. My initial thought with this was that the dashboard should only provide the means to easy display what ever you want and leave that to each project using it. So to have it this way it should be dead easy to have the dashboard included in your projects and if the need arise just implement a class with the correct interface to get a new menu option into the dashboard. </p>
<h2>What does it look like</h2>
<p>Each menu option to the left is equal to a class implementing the specific interface. The dashboard only supports two different rendering layouts for now: table and bootstrap alerts.</p>
<p>All options can consist of a list of settings to display and the different layouts can be combined. It's also possible to display a badge in the menu option if something need to be highlighted.</p>
<h3>Table example<em> </em></h3>
<p><img src="/link/da195848229c468e8a5437de301d5c00.aspx" alt="Image 2 menu and appsetting.jpg" /></p>
<h3><em>Bootsrap alert example</em></h3>
<p><img src="/link/f077770f03a44a08938a3e45e841cf50.aspx" alt="Image 3 general example.jpg" /></p>
<h3>Mixed example</h3>
<p><img src="/link/d99f2fb9871b4763a83666f9fcee5211.aspx" alt="Image 4 mixed.jpg" /></p>
<h2>Code</h2>
<p>Just create a class and implement the IDashboardInformation interface see below. </p>
<p><strong><em>public interface IDashboardInformation</em></strong></p>
<p><em>{</em></p>
<p><em>string Heading { get; } // The heading in the menu</em></p>
<p><em>List<DashboardData> Data(); // Data to display</em><br /><em> string Badge { get; set; } //Badge in menu option</em><br /><em> }</em></p>
<p>The DashboardData class looks like this:</p>
<p><strong>public class DashboardData</strong><br /> {<br /> public string RenderType { get; set; } //View to render data<br /> public Object Data { get; set; } // The data<br /> }</p>
<h3>Appsetting example</h3>
<p>One thing to note about the two different now existing render types is that Dictionary expects the data to be a generic Dictionary<string,string> and the general render type to be of the General model which contains three properties: Heading, Text and Alert type. Alert type is the boostrap alert style wanted if any.</p>
<p><strong>public class AppsettingsInformation : IDashboardInformation</strong><br /> {</p>
<p>public string Heading<br /> {<br /> get<br /> {<br /> return "AppSettings";<br /> }<br /> }</p>
<p>public List<DashboardData> Data()<br /> {<br /> var retList = new List<DashboardData>();</p>
<p>var dict =first ConfigurationManager.AppSettings.AllKeys<br /> .ToDictionary(k => k, v => ConfigurationManager.AppSettings[v]);<br /> var dbData = new DashboardData<br /> {<br /> RenderType = RenderTypes.Dictionary,<br /> Data = dict,</p>
<p>};</p>
<p>retList.Add(dbData);</p>
<p>return retList;<br /> }</p>
<p>public string Badge { get; set; }</p>
<p>}</p>
<h2>What is missing</h2>
<p>It still needs a bit work on the looks since I'm no frontend guy at all. Maybe som more rendertypes as well but as a first check in I think it does the trick, atleast for my needs.</p>
<h2>Where to get it</h2>
<p>You can get the code over at my <a href="https://github.com/PNergard/OverviewDashboard">GitHub</a>. Been thinking of doing it as a Nuget package but maybe it needs to be polished a bit more.</p>Lots of pages below the same parent and how it effects load time/blogs/Per-Nergard/Dates/2017/1/pages-and-load-time/2017-01-28T12:32:23.8830000Z<p>I guess everybody knows that having to many child pages under the same parent is bad for performance. But exactly how bad and where is the limit.</p>
<p>Since it's now so easy to create your own object and save it to Episerver it can be an option instead of using the DDS. So I decided to do a quick hack to see what type of performance I got on med development virtual machine when having lots of pages below the same parent.</p>
<p>If you aren't aware that you can easily store your own objects in Episerver and manipulate them in the same way you would do with pages read more about it in the <a href="/link/c4bef14c0de34bfa83acbeaca2d31e60.aspx">docs</a>.</p>
<p>Below is a screen dump of my test after a fresh IIS reset. Call times are in milliseconds. </p>
<p><img src="/link/1971ececec6c4772a5b834764cf3b4f8.aspx" alt="Image loadtimes.jpg" /></p>Weird problem with scheduled jobs not running as expected/blogs/Per-Nergard/Dates/2016/11/weird-scheduled-jobs-not-running-problem/2016-11-16T20:00:10.4900000Z<p>Two weeks ago I got an email from a customer that some data that was imported via a scheduled job seemed to be missing. So I logged into admin mode and checked the job history. And yes the job hadn't been run as it supposed to.I didn't think that much about it and settled for running it manually and changing the next scheduled date a couple of days ahead.</p>
<p>Since I was 100% sure this would be the end of the problem I didn't verify that the job actually did run on the new date which it didn't.</p>
<p>Hmm strange, and to make things even more strange I could see that other builtin jobs were running perfectly. </p>
<p>I never found out what the problem were exactly but clearing the scheduld job- and log-table fixed the issue. Thanks to the support for the script.</p>
<p>If you run into this and want to run the script below remember to do a db backup (you never now) and note down how the scheduled jobs are configured so you can reconfigure them after clearing the tables.</p>
<p>ALTER TABLE tblScheduledItemLog NOCHECK CONSTRAINT ALL<br />ALTER TABLE tblScheduledItemLog CHECK CONSTRAINT ALL</p>
<p>delete [tblScheduledItemLog]<br />delete [tblScheduledItem]</p>List editors and how many pages they have created./blogs/Per-Nergard/Dates/2016/10/which-editors-have-created-most-pages/2016-10-17T23:51:11.4900000Z<p>Wouldn't it be fun to have a list wich presented all editors and how many pages they have created? Maybe not so fun but in one case this is what I wanted to present. So i whipped togheter a simple aspx page that does just that.</p>
<p><img src="/link/8de17b34c87d4e7cbdd23fccb147a245.aspx" alt="Image highscore.jpg" /></p>
<p><a href="https://gist.github.com/PNergard/34d63e748650ee106bdb1edbaf335540">As usal code over at my Gist.</a></p>Special editor toolbuttons for administrators/blogs/Per-Nergard/Dates/2016/10/special-editor-toolbuttons-for-administrators/2016-10-09T16:31:35.6930000Z<p>In one recent project I had the need to give the administrators some extra editor toolbuttons over the default set setup for the general editor. I googled a bit but didn't find exactly what I was looking for.</p>
<p>Finally I found an exaample in the <a href="/link/865338a95e4a45398e4109ad59cc0035.aspx">documentation </a>on how to create a global editor settings from code with the possiblity to add buttons for administrators. </p>
<p>Ok so this seems to do the trick except that I wanted the SuperAdmins to be able to configure this from admin mode instead of having everything created from code.</p>
<p>So I solved this by defining two global settings via admin mode. On "Ordinary" for the general editor and one "ExtraOrdinary" for the admin editors and combining those in the global setting.</p>
<p>Code over at <a href="https://gist.github.com/PNergard/87b0648d8336aa3af53e71f51ac21e1e">my gist</a></p>
<p>This is how it looks in admin mode:</p>
<p>1. Settings</p>
<p><img src="/link/11f076ec44b641a1895c3b3d6518ddbc.aspx" width="889" alt="Image Profiles_overview.jpg" height="500" /></p>
<p>2. Ordinary toolbars</p>
<p><img src="/link/2e39e28df8094687b74a3fe6f6b165aa.aspx" width="860" alt="Image Ordinary_buttons.jpg" height="484" /></p>
<p>3. ExtraOrdinary toolbars</p>
<p>Here the last toolbar contains a duplicate that already exists in the Ordinary setting.</p>
<p><img src="/link/56c33a46c25a43c79ea9a3db31f6d9af.aspx" width="919" alt="Image extra_buttons.jpg" height="537" /></p>
<p>4. The result when looking in the code created profile logged in as an administrator.</p>
<p>Note that the duplicate link-button has been removed. If duplicates isn't removed the code doesn't work.</p>
<p><img src="/link/a0242f16093949d586e2f716c34242f7.aspx" width="775" alt="Image standard_result.jpg" height="436" /></p>
<p><span>Code over at</span><span> </span><a href="https://gist.github.com/PNergard/87b0648d8336aa3af53e71f51ac21e1e">my gist</a></p>Content type sorting initializationmodule/blogs/Per-Nergard/Dates/2016/7/content-type-sorting-initializationmodule/2016-07-02T20:41:13.3570000Z<p>Earlier this year I created a plugin to give admins / editors a quicker way to change sort order of content types <a href="/link/ea2e2e25160d4f9f97f6807f6e43f178.aspx">(post here)</a>. While it works I realialised that most of the time I really just wante to have the content types sorted in alfabetical order.</p>
<p>So I did a initializationmodule to accomplish just that. It's really easy and the only thing you need to decide is if you want to sort the types on name or localizedname.</p>
<p>You can get the code over at my <a href="https://gist.github.com/PNergard/8296cb61b26c8bb322da7c78933e51ad">gist</a>.</p>Overview of content type syncronization status/blogs/Per-Nergard/Dates/2016/6/overview-of-content-type-syncronization-status/2016-06-07T23:39:55.5200000Z<p>Ok time for another overview plugin. This time it's a plugin that gives you an overview of wich content types (both pages and blocks) wich are not fully synchronized due to one or many changes done via admin mode.</p>
<p>It's very simple, just an html table with some information about the type and the possiblity to tick a checkbox if you wan't to reset it. There are three buttons wich is self explanatory. On a reset the appdomain is unloaded and a redirect to the plugin is done. I guess that the save and reset only buttons are unnecessary but I was to lazy to remove them.</p>
<p>The background story for this plugin is that a collegaue of mine made changes to some models and the didn't get persisted. It was a bit odd since as far as I new no one had done any admin mode changes to this type. So I just tried to reset the offending type and voila the code changes took effect. </p>
<p>As usual you can get the code over at my <a href="https://gist.github.com/PNergard/8ca8936699f1ac43074beea75bdf9d8e">gist</a>.</p>
<p><img src="/link/10a3a2bb0dc449db9284f976ebf22ed3.aspx" alt="Image resetter1.jpg" /></p>Overview of access rights in a site/blogs/Per-Nergard/Dates/2016/5/overview-of-access-rights-in-a-site/2016-05-19T12:06:11.9370000Z<p>I really enjoy working with Episerver and developing new cool solutions with it, but sometimes it's hard to get a good overview of how things are configured. One of those things is access rights.</p>
<p>In a real simple solution there might only be a few groups with different access rights and they are all set from the root page. On the other hand I've seen some really messed up sites where there have been a myriad of different access rights configured all over the place, making it really hard to get a clear picture.</p>
<p>To get a better overview and a quicker way to go inte the accessrighs dialogs I created a admin plugin.</p>
<p>The plugin checks the page tree and assets folder and gives you some summarised data. It also lists all those pages, folders, blocks, media that doesn't inherit access right settings. It also lists all groups, users that have some access right. Group names, user names and the paths to pages etc (blocks and media exluded) are all linked to the corresponding admin view where you can manage or view the current settings.</p>
<p>If youre intrested you can get the code over at my <a href="https://gist.github.com/PNergard/2d09e075afa99f81f93ced842f40b064">Gist</a>. See picture below for how it looks:</p>
<p><img src="/link/dc59c054fcfa49d18d0548bdc8f6db95.aspx" alt="Image accessright2.jpg" /></p>Limit block and page types to be created only once (updated)/blogs/Per-Nergard/Dates/2016/4/limit-block-and-page-types-to-be-created-only-once-updated/2016-04-18T20:20:26.0200000Z<p>Two years ago I did a hack that let you as a developer specify if a block or page type should be allowed to only be created once. <a href="/link/acd42fb1118544a48d650ab9c0eaac9e.aspx">Old post here.</a> For some reason I can't remeber I used an interface to specify this. Now I have updated the code to use an attribute instead. </p>
<p>Just decorate your models with [Singleton] and the initializationmodule will handle the rest.</p>
<p>Code over at <a href="https://gist.github.com/PNergard/e931dc956492967d0cc0fe8c2c1b8c11">Gist</a>.</p>