The Console of Mass Content Management

This one definitely took more time than I initially expected, and before I devote even more to it I would very much like to hear your opinion. Do you find it useful? Which way should the development be going? But first things first?

Have you ever found yourself:

  • having to make a mundane change to a large number of pages?
  • in need of getting statistics on page properties or page type usages?
  • being curious of e.g. what?s the oldest page on your site?
  • having to copy or move a large number of files from one folder to another or between versioning and non versioning virtual path providers?
  • renaming or deleting files in your file store en-masse?

If the answer to any of those (and more) is a ?yes!?, I believe you might find my little plugin useful.

The idea is to create a scripting environment to work with EPiServer on a more granular level than the existing PowerShell SnapIn API enables us currently. Manipulate not just sites, but files and pages on a large scale or perform statistical analysis of your content using  a familiar and well documented query language.

PowerShell1

The PowerShell console for EPiServer provides you with two abstractions to work with:

Virtual Path Provider Drive

With the console you can browse the VPP and perform a number of file operations just like you were doing it in a regular PowerShell console on a regular disk drive. Especially?

  • move files between Virtual path providers
  • move, copy or rename files and folders

Known limitations:

  • You cannot load files from disk directly onto a VPP and vice versa (this however can be overcome by mapping the path you want to migrate into your CMS as a native path provider and copying from that).
  • some actions might not respect or might unintentionally force recursive operation.
  • the console might blow up unexpectedly (What do you mean crippled? I got all five fingers! Three on this hand, two on the other one!)

I think you might find it quite useful offloading files from versioning VPP onto a Native VPP once you decide that you want to access the content of the files outside the CMS. Or pulling your files into the Database VPP (available for download from EPiCode).

Page Store Drives

The console will map all your CMS page roots as drives based on the site name (site name should not have space in it for the current version to work). Now this one? the sky is the limit!

The items that the drive exposes are fully functional PageData?s, additionally ? for your scripting convenience all page properties are mapped so that you can access them like they were regular POCO properties.

By far this is the coolest little toy I?ve recently played with ? I would strongly advised that you look into the samples and put your imagination to work!

PowerShell2

You can create statistics, modify pages based on regular expressions, filter, delete, rename, move around?

PowerShell3

Naturally the Obligatory disclaimer is that you use the tool at your own responsibility. Make backups, test your script on staging before doing anything. Heck! Don?t use it on production at all yet (!) ? it?s very much an alpha and a technology demo.

[Download & Enjoy]

How to install?

Extract the DLL form the ZIP file into the BIN folder of your web application to install the plugin. Remove the DLL to uninstall it.

All constructive feedback appreciated!

Aparently I have written something on that note before for CMS 4 and it looks like someone still needs it as I got a request for an updated version for it a couple of days ago. So here we go:

for the most part the syntax for the call is equivalent to what is was before so go to my previous article regarding that (check out the old article for details). What I?ve added this time around is:

  • the @PropertyName can be declared as ?%? if you want to look in all property names
  • @PropertyType can be ?1 if you want to look in all property types otherwise you need to specify type id (this has changed from type name before due to database schema changes)
  • additionally this version of the stored proc will only look in the Master language Branch, so it will work for the single language pages and for multi-language but for language agnostic properties. (should you require the language to be variable the change is pretty simple ? I can send you the updated version by email.
/****** Object:  StoredProcedure [dbo].[PagedSearch]    Script Date: 07/07/2009 12:18:10 ******/
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[PagedSearch]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[PagedSearch]
GO

CREATE Procedure PagedSearch
    @Condition varchar(1024),
    @PropertyName varchar(1024),
    @PropertyType int,
    @PageSize int,
    @PageNumber int,
    @Offset int
AS
BEGIN

    DECLARE @RowStart int
    DECLARE @RowEnd int

    SET @RowStart = @PageSize * @PageNumber + @Offset;
    SET @RowEnd = @RowStart + @PageSize + @Offset;

    WITH PageRefs AS
        (SELECT page.pkID as PageId,
            ROW_NUMBER() OVER (ORDER BY pageLang.StartPublish DESC) as RowNumber
            FROM tblPage page, tblProperty propValue, tblPageDefinition propDef, tblPageLanguage pageLang
            WHERE page.pkID = propValue.fkPageID
                AND page.fkMasterLanguageBranchID = pageLang.fkLanguageBranchID
                AND page.pkID = pageLang.fkPageID
                AND propValue.fkPageDefinitionID = propDef.pkID
                AND (@propertyType = -1 or propDef.fkPageDefinitionTypeID = @propertyType) -- is proper type
                AND propDef.Searchable = 1 -- the property is searchable
                AND propValue.String like @Condition -- contains facets
                AND propDef.[Name] like @PropertyName) -- property of proper name
    SELECT PageId
        FROM PageRefs
        WHERE (RowNumber Between @RowStart and @RowEnd) or (@PageSize = 0);
END
GO

However… looking how the schema has changed over time, I am not convinced this approach is really the best one for someone who is not prepared to deal with the changes (e.g. you better be able to change the stored procedure based on the schema changes – or bribe me with pizza and beers for updates :) ).

Additionally this procedure only searches for properties that store their value in Short string field. To make it look into long string you need to Change the highlighted line to.

AND (propValue.LongString like @Condition)

or alternatively to look in both change it to:

AND ((propValue.String like @Condition) or (propValue.LongString like @Condition))

Enjoy!

Advanced Language Manipulation Tool for EPiServer

Have you ever (or have your customers) created and edited a page in one language only to realize that their selected locale was wrong? Have you ever wished you could delete a master language branch of a page  after creating its localized counterpart but you could only delete the newly created slave language instead? Have a customer ever requested that they could copy a whole branch and you convert it to another language so that they could then translate in-place?

Well I have? and I?m sure I will. And so did Fredrikj on the our #epicode IRC channel ;).

Basically I had the tool that would convert from one language to another, but Fredrikj requested something that would switch master language of a page from one to another. Since I?ve already had some of the work done, I?ve updated the stored procedure I?ve written some time ago and slapped a nice GUI up on it. Here?s the result:

 

AndvancedLanguageTool

What the tool allows you to do is perform either language conversion or master branch switching on a selected page and all of its children (if you choose so).

The stored procedure have been updated to work on CMS5 R2 (will no longer work on R1 ? but if you need that functionality, comment here or give me a shout and I?ll create a compatible version for you).

A word of caution though ? I take no guarantee whatsoever about its operation. Especially, if you wreck your client?s database with it. I did what I could to prevent some of the obvious problems (like switching to a non existing master or converting to an existing one) but I will not be responsible if it won?t work for you. make a database backup and experiment there before you do any changes on the real data. That said ? it works for me, so I think it should also work for you.

You can download the archive containing the tool here. unzip it to your EPiServer web application folder keeping the folder structure or the plugin reference will be wrong. Include the *.aspx and the *.cs files in your project and apply the SQL file to your database (The manipulation is performed by a stored procedure located in the file).

Also if you?re performing the change in a load balanced environment, you may need to restart the other servers once you do the changes. I reset the DataFactory cache, but I am not sure it propagates through to other servers.

Simple registration for files served by EPiServer

With the culture of knowledge sharing and open source spreading, everyone races to show they have something valuable that you may want. And while you may not ask for money for your content you may still want to get something in return, say a contact, an email address that?s verified (or not), to keep in touch with the consumer of your content.

Yet a full fledged registration doesn?t seem like a proper thing to do ? cluttering your EPiServer user repository with (let?s face it ? for a large part fake or temporary email addresses that user create only to get your content).

While there may be a lot of ways to handle that (streaming it through a page Response.WriteFile might seem as one of the more obvious ones), I would like to show you a cleaner, simpler and more elegant way that I?ve come up with.

We really don?t want people to deep link to our files without them knowing the files are from our site, that?s just rude ? so hiding them behind an obscure URL wouldn?t work (thus we cannot use the regular file providers). We?ve already establish that we don?t want to log them in, so setting file rights are useless. But I want all the benefits including client-side caching.

Basically the solution boils down to creating a thin layer over the File provider of our choice, in my case the versioning file provider. The only method we need to override in it is GetFile. I want to allow downloading for logged in users and I want to allow downloading for all users that have a ?magic-cookie? set. If either of the conditions are met, the file just downloads using the underlying provider?s routines including all the logic EPiServer has put for caching and rights. But if neither of the requirements are met, the user is directed to a page of our choice.

Read the rest of this article »

WebParts based Sidebar for EPiServer ? how to use it?

Once you?ll update the framework to the extended one, you will immediately notice that? nothing has changed. Hmm? did something go wrong?

Well, not really. By default the framework will be run in the ?legacy mode?. Thanks to an old article by our own Marek Blotny, I?ve learned how to build Plugin settings which are just perfect for the purpose!

So to configure and enable the new features you need to open your admin UI and in the ?Config? click on the ?Plugin Manager? item and select our framework plugin as shown in the picture

WebPartFrameworkPluginSettings1

The available options are:

Read the rest of this article »

WebParts based Sidebar for EPiServer ? how to use it?

Once you?ll update the framework to the extended one, you will immediately notice that? nothing has changed. Hmm? did something go wrong?

Well, not really. By default the framework will be run in the ?legacy mode?. Thanks to an old article by our own Marek Blotny, I?ve learned how to build Plugin settings which are just perfect for the purpose!

So to configure and enable the new features you need to open your admin UI and in the ?Config? click on the ?Plugin Manager? item and select our framework plugin as shown in the picture

WebPartFrameworkPluginSettings1

The available options are:

Read the rest of this article »

Once you’ll update the framework to the extended one, you will immediately notice that… nothing has changed. Hmm… did something go wrong?

Well, not really. By default the framework will be run in the “legacy mode”. Thanks to an old article by our own Marek Blotny, I’ve learned how to build Plugin settings which are just perfect for the purpose!

So to configure and enable the new features you need to open your admin UI and in the “Config” click on the “Plugin Manager” item and select our framework plugin as shown in the picture

WebPartFrameworkPluginSettings1

The available options are:

Read the rest of this article »

Back in the day when we started designing our last project we’ve been presented with a following problem – a big number of templates with slightly different sidebars.

Hmm…

Is sidebar a part of content? No, rather not. We don’t want the editors to have to setup the sidebar for every article they write (and the site has a few dozens of articles created on it every day).

Is sidebar more of a template thing? Well… more like it, but still… we have articles all over the site with different sidebar elements when the articles are in different parts of the site (ok so we could add rules what controls display in which part of the site). But wait! There’s more! The sidebar will be different for every language (region). Now we’re talking a dozen of templates or a rules engine just to make the sidebar different. Customising the template with properties isn’t ideal either as it makes EPiServer UI very cluttered. Additionally we want to change sidebars across many templates so the whole branch/section of the site will be able to share the same sidebar.

To a degree this is an academic discussion as we’ve been through it with the previous version of the site and we already knew that integrating this stuff into templates just won’t work and we will be in a world of pain just changing the templates over and over adding little tweaks and changes while the customer ads promotions and performs ad campaigns. Well, we can do it, of course, but it’s not a work a programmer will enjoy, and we all want to do new and more exciting things, don’t we?

We have an internally developed  module to make something like that, that is fully home-grown by another internal team (we now have 3 “squads” capable or making incredible things with EPiServer and we tend to share a lot of technologies and try to rotate people around to adopt the good habits and experiences) and I was (and still am) VERY impressed by it. The technology uses EPiServer pages for defining every module (which are located somewhere outside the site root branch. and then you can mix and match them either declaratively in the code) or by handpicking them in the UI. It’s really cool, though, during the discussions it turned out that we might have to add big chunks of functionality and might end up with separate branches of module-pages for different languages/regions, but… frankly… about that time an article by Ted Nyberg reminded me about a technology I have read about quite a while ago in an article by Stein-Viggo Grenersen and ooohhhhhh… I got seduced. I really wanted to try if for a long time and Ted’s article made it a snap to try and get convinced, and more important… convince Stu ;) that it’s the right way to explore.

So I started to dig.

Read the rest of this article »

Back in the day when we started designing our last project we?ve been presented with a following problem ? a big number of templates with slightly different sidebars.

Hmm?

Is sidebar a part of content? No, rather not. We don?t want the editors to have to setup the sidebar for every article they write (and the site has a few dozens of articles created on it every day).

Is sidebar more of a template thing? Well? more like it, but still? we have articles all over the site with different sidebar elements when the articles are in different parts of the site (ok so we could add rules what controls display in which part of the site). But wait! There?s more! The sidebar will be different for every language (region). Now we?re talking a dozen of templates or a rules engine just to make the sidebar different. Customising the template with properties isn?t ideal either as it makes EPiServer UI very cluttered. Additionally we want to change sidebars across many templates so the whole branch/section of the site will be able to share the same sidebar.

To a degree this is an academic discussion as we?ve been through it with the previous version of the site and we already knew that integrating this stuff into templates just won?t work and we will be in a world of pain just changing the templates over and over adding little tweaks and changes while the customer ads promotions and performs ad campaigns. Well, we can do it, of course, but it?s not a work a programmer will enjoy, and we all want to do new and more exciting things, don?t we?

We have an internally developed  module to make something like that, that is fully home-grown by another internal team (we now have 3 ?squads? capable or making incredible things with EPiServer and we tend to share a lot of technologies and try to rotate people around to adopt the good habits and experiences) and I was (and still am) VERY impressed by it. The technology uses EPiServer pages for defining every module (which are located somewhere outside the site root branch. and then you can mix and match them either declaratively in the code) or by handpicking them in the UI. It?s really cool, though, during the discussions it turned out that we might have to add big chunks of functionality and might end up with separate branches of module-pages for different languages/regions, but? frankly? about that time an article by Ted Nyberg reminded me about a technology I have read about quite a while ago in an article by Stein-Viggo Grenersen and ooohhhhhh? I got seduced. I really wanted to try if for a long time and Ted?s article made it a snap to try and get convinced, and more important? convince Stu ;) that it?s the right way to explore.

So I started to dig.

Read the rest of this article »

Back in the day when we started designing our last project we?ve been presented with a following problem ? a big number of templates with slightly different sidebars.

Hmm?

Is sidebar a part of content? No, rather not. We don?t want the editors to have to setup the sidebar for every article they write (and the site has a few dozens of articles created on it every day).

Is sidebar more of a template thing? Well? more like it, but still? we have articles all over the site with different sidebar elements when the articles are in different parts of the site (ok so we could add rules what controls display in which part of the site). But wait! There?s more! The sidebar will be different for every language (region). Now we?re talking a dozen of templates or a rules engine just to make the sidebar different. Customising the template with properties isn?t ideal either as it makes EPiServer UI very cluttered. Additionally we want to change sidebars across many templates so the whole branch/section of the site will be able to share the same sidebar.

To a degree this is an academic discussion as we?ve been through it with the previous version of the site and we already knew that integrating this stuff into templates just won?t work and we will be in a world of pain just changing the templates over and over adding little tweaks and changes while the customer ads promotions and performs ad campaigns. Well, we can do it, of course, but it?s not a work a programmer will enjoy, and we all want to do new and more exciting things, don?t we?

We have an internally developed  module to make something like that, that is fully home-grown by another internal team (we now have 3 ?squads? capable or making incredible things with EPiServer and we tend to share a lot of technologies and try to rotate people around to adopt the good habits and experiences) and I was (and still am) VERY impressed by it. The technology uses EPiServer pages for defining every module (which are located somewhere outside the site root branch. and then you can mix and match them either declaratively in the code) or by handpicking them in the UI. It?s really cool, though, during the discussions it turned out that we might have to add big chunks of functionality and might end up with separate branches of module-pages for different languages/regions, but? frankly? about that time an article by Ted Nyberg reminded me about a technology I have read about quite a while ago in an article by Stein-Viggo Grenersen and ooohhhhhh? I got seduced. I really wanted to try if for a long time and Ted?s article made it a snap to try and get convinced, and more important? convince Stu ;) that it?s the right way to explore.

So I started to dig.

Read the rest of this article »