I’m working on a web application where I’m using the great mirco orm PetaPoco for my data access. Is a really great and super fast ORM that works with SQL Server, SQLCE. MySQL and more.

I’m not gonna cover the basics of PetaPoco in this blog post so if you have not worked with it please read the introduction from TopTen Software.

Now. In this solution we where working with stored procedures (SP) in the SQL Server which is quite simple with PetaPoco, to execute a SP called OutputDemo with two parameters, just write

 

var sql = Sql.Builder.Append(";EXEC OutputDemo @0, @1, "Markus",29);

 

So that's easy. But what if we need to grab some output parametersfrom the sp as well? That took me some more work to figure out. I googled a lot on the subject and there was not really any good recourse so i figured i had to share my solution.

First, let’s look look at the stored procedure that I’ve created for this demo

 

CREATE PROCEDURE [dbo].[OutputDemo]
    @name varchar(50),
    @age int,
    @resName varchar(50) OUTPUT,
    @resAge int OUTPUT
AS
SET @resAge= @age + 10
SET    @resName = 'Name: ' + @name   


A super simple sp that will set the values of the output parameters depending in the value in the input parameters for name and age. So the resAge-output parameter will have the value of the inputted age plus 10, and the resName-output parameter will just be prefixed with “Name:”.

Now. To use this and to get the values back from the query there is couple of thing we need to do. First we need to create variables that holds the returning values from the output parameters.

 

var opName = new SqlParameter("@resName", SqlDbType.VarChar);
opName .Direction = ParameterDirection.Output;
opName .Size = 50;

var opAge= new SqlParameter("@resAge", SqlDbType.Int);
opAge.Direction = ParameterDirection.Output;
opAge.Size = 20;

 

This is regular SqlParameters – I’ve just ignored the fact that this would “tie” me to SQL Server since my SP’s are created in SQL Server is just don’t care about this dependency. The important thing to notice is the Direction and the Size-properties that both are mandatory. Next wee need to create the query:

 

var s = Sql.Builder.Append(";EXEC OutputDemo @0, @1, @2 OUTPUT, @3 OUTPUT",
           "Markus",
           29, 
           opName ,
           opAge
          );

 

As you see here I’m adding the word “OUTPUT” after each variable for the output parameters – this tells the ADO.NET and PetaPoco that these variables should be populated with the return values of the output parameters.

 

So with this code executed the value of opName should be “Name: Markus” and opAge should be 39. Here’s the complete code:

 

      var opName = new SqlParameter("@resName", SqlDbType.VarChar);
       opName .Direction = ParameterDirection.Output;
       opName .Size = 50;
       var opAge= new SqlParameter("@resAge", SqlDbType.Int);
       opAge.Direction = ParameterDirection.Output;
       opAge.Size = 20;
       var s = Sql.Builder.Append(";EXEC OutputDemo @0, @1, @2 OUTPUT, @3 OUTPUT",
          "Markus",
          29, 
          opName ,
          opAge
         );
       new Database().Execute(s);


     

Yesterday I was listening to my favorite podcast .NET-ROCKS and heard about Troy Hunts great Azure demo - not not just a great demo - it's The world's greatest Azure demo, just wanted to share it here as well:

 

Since version 7.1 of Umbraco was released the core now contains a great image cropper. Not only that. It also contains a great image processing library called ImageProcessor written by James South (@james_m_south).

 

The image cropper in Umbraco 7 is really a piece of art based on the CropUp-package from Umbraco-genius Niels Kühnel (@nielskuhnel). The big “news” with the cropper is something called a “focal point” that the editor can set. When this point is in place Umbraco is smart enough to figure out any crop based on this point. This means that you don’t have to force the editor to make 20 different crops, they can just set the focus point and the different crops will be generated. We’re going to explore this more in this post and I'll show you how to quickly set up the image cropper and render the cropped image on the front end of your website.

 

Newsletter Studio -banner -580x 250

Here is how you do

 

1. Set up the data type in the developer-section of Umbraco 7. Right click data types and create a new data type. Let's call it "Image Cropper".

 

2. Just as with the cropper from earlier versions of Umbraco we now need to set up one or more crops. Let's just use a simple crop of 120x120 px.

imagecropper-datatype

 

3. Next, we need to add this data type to one of our document types. Let’s go and do so in the settings-section. I’m giving my new property the name “image” but you can choose what ever name that suites you’re solution.

 

imagecropper-doctype

 

4. Now let’s upload an image and set the focus point by dragging the blue dot to the part of the image that we want to focus on. Let’s don’t create any special settings for the 120x120 crop that we created – just hit “Save and publish”.

 

imagecropper-image

 

5. Let’s go to the settings-section and open the view/template for the document type that we’ve added the image cropper to. To render the crop in on the page we need to use a method called GetCropUrl() from the IPublishedContent-type in Umbraco. Let’s add this code the view and load the page in the browser.

 

<img src="@Model.Content.GetCropUrl("image", "normal")" />

 

The first parameter is the alias of the property and the second is the name of the crop, this should look something like this.

 

imagecropper-croppedimage

 

6. As you can see Umbraco 7 created a crop based on the focus point that we provided. To prove that this really works, let’s ignore the “normal” crop and set the width and height in the method call.

 

<img src="@Model.Content.GetCropUrl(propertyAlias:"image", width:300, height:100)" />

 

This will generate an image that’s 300x100 pixels, still with the face in focus

imagecropper-croppedimage2

 

7. Now, let’s try to move the focal point and look at the resulting crop

imagecropper-movedpoint

 

 

8. But, if we don’t like the default crops that Umbraco generates we can of course change them to look exactly like we want. Update the view-code to use the “normal” crop again and open the node with the crop back to the content-section. Click on the little thumbnail under the big picture, in the dialog that appears. Drag the slider to zoom and drag in the picture to adjust the part that you want to keep in the crop – click the “cross” in the upper right corner to save the custom crop beforeyou click save and publish.

 

 

imagecropper-customcrop

 

 

9. Going back to our view and refreshing the page will show our new crop

 

imagecrop-customcropfrontend 

 

 

The GetCropUrl()-method has a lot of properties that’s optional like width, height, quality, useCropDimensions, cacheBusterValue, ratioMode, upScale – see the source code of Umbraco 7 for more info on what they all means.

 

Hope you enjoy the new image cropper in Umbraco 7, follow this blog for most posts about Umbraco and please also follow me on twitter: @enkelmedia.

Tip: Looking for a integrated newsletter solution for Umbraco? Check out Newsletter Studio - sends newsletter from directly from the Umbraco backoffice.

 
Newsletter Studio -banner -580x 250

 

 

 

IMG_3739

 

It’s been a little more than a month since Umbraco 7 was released and it feels like a great timing that we announced new dates for Umbraco training in Stockholm, Sweden. Just like last time the course will be in Swedish but the course material (slides and workbook) is in English.

 

Please read more about the training here: /vi-erbjuder/utbildning-umbraco.aspx (in Swedish)

One requirement of Enkel Medias Umbraco-package Newsletter Studio is to render and use the built in rich text editor from Umbraco (TinyMCE) in the custom Newsletter Studio-section.

 

Newsletter Studio -banner -580x 250

 

TinyMCE in a custom Umbraco 7-section

 

 

image

Since the backoffice of Umbraco 7 is rebuilt using AngularJS all property editors are built using JavaScript and they also rely on the current AngularJS-scope to contain some information on how to render the control. So in order to render our rich text editor (rte) we need to provide this information.

 

There are some different ways to render the control, some are more “hacky” than others and I’m going to walk you through some options. Just to be clear –this is not a best practice guide for JavaScript so I’ve added the JavaScript controllers in script-elements inside the views. This is something that you should not do, they should live in their own .js-files – but for simplicity I ignore that in this blog post.

 

Option 1 –Copy the original view

The first option is to just copy the code from the original rte-view (from the Umbraco source code). It looks something like this:

<div ng-controller="Umbraco.PropertyEditors.RTEController" class="umb-editor umb-rte">
    <textarea ng-model="model.value" rows="10" id="{{model.alias}}_rte"></textarea>
</div>

This is super simple. But it won’t work. Since Umbraco loads information about all the tabs, content, property types, values and so on for a content page when it’s loaded the RTEController assumes that the current scope has all this information. So we need to simulate that with our own controller. Let’s change the view so it looks like this:

<div ng-controller="CustomSectionEditController">    
    <ng-form>
        <div ng-controller="Umbraco.PropertyEditors.RTEController" class="umb-editor umb-rte">
            <textarea ng-model="model.value" rows="10" id="{{model.alias}}_rte"></textarea>
        </div>            
        <pre>
            Value from the RTE {{model.value}}
        </pre>
    </ng-form>
</div>

And for this code we need a controller called “CustomSectionEditController”, let’s just add a simple version of this controller:

<script type="text/javascript">
    function CustomSectionEditController($scope) {

        $scope.model = {
            alias: 'myRichtexteditor',
            config: {
                editor: {
                    toolbar: ["code", "undo", "redo", "cut", "styleselect", "bold", "italic", "alignleft", "aligncenter", "alignright", "bullist", "numlist", "link", "umbmediapicker", "umbmacro", "table", "umbembeddialog"],
                    stylesheets: [],
                    dimensions: { height: 400, width: 250 }
                }

            }
        };
    }
</script>

With this code in place the rich text editor (rte) should be rendered and the HTML from the editor will be populated into the $scope.model.value-property.

 

While this works it’s not so very flexible and another problem is that it will be hard to “lazy load” properties, values and settings since the rendering of the rte-controller could start before all your data has been downloaded.

 

Option 2 – Use the umb-editor directive

In the views in Umbraco all the property editors are loaded dynamically the view for editing content only uses this simple tag:

<umb-editor model="myProperty"></umb-editor>

Umb-editor is a Umbraco-specific AngularJS directive that will look at the model attribute to find out which $scope-property to use for getting rendering information, in this case it’s $scope.myProperty – so let’s add that:

<script type="text/javascript">
    function CustomSectionEditController($scope) {
        $scope.myProperty= {
            label: 'bodyText',
            description: 'Load some stuff here',
            view: 'rte',
            config: {
                editor: {
                    toolbar: ["code", "undo", "redo", "cut", "styleselect", "bold", "italic", "alignleft", "aligncenter", "alignright", "bullist", "numlist", "link", "umbmediapicker", "umbmacro", "table", "umbembeddialog"],
                    stylesheets: [],
                    dimensions: { height: 400, width: 250 }
                }
            }
        };
    }
</script>

As you can see with this code the $scope.myProperty.view property is called “rte” which tells AngularJS to load the rte (rich text editor)-view as the current view for this umb-editor. If we were to set $scope.myProperty.view to ‘textbox’, a textbox would be loaded. Updating the view to look like this would get this code to run:

<div ng-controller="CustomSectionEditController">    
    <ng-form>
        <umb-editor model="myProperty"></umb-editor>      
        <pre>
            Value from the RTE {{myProperty.value}}
        </pre>
    </ng-form>
</div>

This is a little bit cleaner than the approach in option 1 but we still suffer from the problem that the directive could be processed before we have loaded all our external data. For example – we would probably like to set the $scope.myProperty.value to some value that's loaded from the backend –but with this approach the directive could be processed before that data is downloaded and we’ll be left with a ugly error message.

 

Option 3 – Use ng-repeat and an array to “lazy load”

As far as I have seen this is the best way to load data from the backend and then render the wysiwyg-editor. In my use case I want to have a specific data type configured and when the page loads I want to get the configuration (pre values) for that data type and put that data in $scope.myProperty.config. I also want to download some content from the backend and put that in $scope.myProperty.value.

So – How do we avoid the directive from being processed before the data is loaded? A loop. Let’s put this in our view

<umb-property 
    property="property"
    ng-repeat="property in properties">
    <umb-editor model="property"></umb-editor>
</umb-property>

And then put an array of properties on the scope:

$scope.properties = [{
                        label: 'bodyText',
                        description: '',
                        view: 'rte',
                        config: {
                            editor: {}, // empty for now
                            hideLabel: true
                        }, hideLabel: true
                    }];

This would look almost the same as option 2 but. Since the ng-repeat attribute is there the directives will be reprocessed each time the $scope.properties-property change and since $scope.properties is null until after the data is downloaded the umb-editor directives will note be loaded.

 

The full view could look something like this:

<div ng-controller="CustomSectionEditController">    
    <ng-form>
        <umb-property 
            property="property"
            ng-repeat="property in properties">
            <umb-editor model="property"></umb-editor>
        </umb-property>
        <pre>
            Value from the RTE {{properties[0].value}}
        </pre>
    </ng-form>
</div>

And the controller like this:

<script type="text/javascript">
    function CustomSectionEditController($scope) {
        $scope.property = {
            label: 'bodyText',
            description: 'Load some stuff here',
            view: 'rte',
            config: {
                editor: {
                    toolbar: ["code", "undo", "redo", "cut", "styleselect", "bold", "italic", "alignleft", "aligncenter", "alignright", "bullist", "numlist", "link", "umbmediapicker", "umbmacro", "table", "umbembeddialog"],
                    stylesheets: [],
                    dimensions: { height: 400, width: 250 }
                }
            }
        };
    }
</script>

Now the last step would be to make sure that the text-value for the editor is fetched from some backend service.

<script type="text/javascript">
    function CustomSectionEditController($scope, $http) {
        $http({ method: 'GET', url: '/url/to/our/cool/service' })
            .success(function (data) {
                $scope.property = {
                    label: 'bodyText',
                    description: 'Load some stuff here',
                    view: 'rte',
                    config: {
                        editor: {
                            toolbar: ["code", "undo", "redo", "cut", "styleselect", "bold", "italic", "alignleft", "aligncenter", "alignright", "bullist", "numlist", "link", "umbmediapicker", "umbmacro", "table", "umbembeddialog"],
                            stylesheets: [],
                            dimensions: { height: 400, width: 250 }
                        }
                    },
                    value: data
                };

            })
            .error(function () {
                $scope.error = "An Error has occured while loading!";
            });
    }
</script>

As you can see we added the $http-parameter to the controller and uses it to fetch the data that we need before assigning the values to the scope. This will prevent the umb-editor directive from starting to load before all our data is loaded.

 

This is how I’ve solved the this issue at the moment and there may be other ways as well, please feel free to post questions or comments here below.

 

Cheers!

In the last post we talked about how to add a new custom application (or section) and a new custom tree to your Umbraco 7 backoffice. Now I’ll show you how to add views so that your sections can do something meaningful.

 

You could use legacy views as well but since I was rewriting Newsletter Studio to work use AngularJS and work really nice with Umbraco 7 I took this approach.

 

Newsletter Studio -banner -580x 250

 

 

The routing

Since we added the PluginController(“CustomSection“)-attribute to our tree-class, Umbraco will route the cliend side requests to a folder in the app_plugins-folder. The logic is something like: /app_plugins/{applicationName}/{treeAlias}/{action}/itemId so in our case we’re looking at the url /#/CustomSection/CustomSectionTree/edit/dashboard and Umbraco will look for /app_plugins/customsection/backoffice/CustomSectionTree/edit.html to show as the view – so let’s create that file.

 

The view

Add this content to our new edit.html-file:

<script>

    function CustomSectionEditController($scope, $routeParams) {
        $scope.content = { tabs: [{ id: 1, label: "Tab 1" }, { id: 2, label: "Tab 2" }] };

        $scope.EditMode = function() {
            return $routeParams.create == 'true';
        };
    }
</script>

<div ng-controller="CustomSectionEditController">

    <umb-panel>
    <umb-header tabs="content.tabs">
        <div class="umb-headline-editor-wrapper span12 ng-scope">
            <h1 class="ng-binding">My custom section {{id}}</h1>
               </div>
    </umb-header>

    <umb-tab-view>
        <umb-tab id="tab1" rel="svensson">

        <div class="umb-pane">
            This is tab content for tab 1<br/>
           <p ng-show="EditMode()">
                   <span class="label label-warning">In create mode, this label is only showed when the controller sees the create-querystring item.</span>
           </p>
        </div>
        </umb-tab>

        <umb-tab id="tab2" rel="kalle">

        <div class="umb-pane">

                    This is tab content for tab 2
         </div>
        </umb-tab>

    </umb-tab-view>
</umb-panel>

</div>

 

This code will give us a view that looks like this:

 

image

 

Even if we could have added regular HTML in the view, I choose to include some AngularJS-stuff and some stuff that Umbraco adds on to AngularJS. The umb-tab, umb-tab-view, umb-panel-elements are something called directives which is a core concept in AngularJS. These directives hide complex logic for generating the view that’s on the right and side of our backoffice. Directives are very powerfull and can be used to create reusable code and "widgets" in your application – let’s just ignore the details of this for now and focus on the code above.

 

In the script-tag I create a regular JavaScript function that will act as the controller for the view, this function take a $scope-variable as parameter which will act as the "glue" between the controller and the view. $scope is a funamental part of AngularJS and should be familiar to you if you have worked with Angular before. Since the Umbraco's custom directives looks at the $scope.content.tabs-property when creating the tabs we need to populate this property with some static data – in this case the “Tab 1” and “Tab 2”-objects.

 

The only “magic” that you’ll need to be aware of is that Umbraco will match the id of the tab with the id of the <umb-tab>-tag. So <umb-tab id="tab1"> will be showed when you click the tab with id 1 – and <umb-tab id="tab2"> will be showed when you click the tab with id 2. Let’s look closer at the $routeParams and the CreateAction that we added to the TreeController-class in the last post.

 

The menu items

The MenuItemCollection, that the TreeController we created in the last post, returns a collection that just contains a ActionNew-item. This action will look for the view /app_plugins/CustomSection/Umbraco/CustomSectionTree/create.html which will be displayed when the user clicks the “Create new” button.

 

image

 

I have use some code from the create content-dialog – lets add this to our create.html-view.

<div class="umb-dialog-body with-footer">
    <div class="umb-pane">
    <h5><localize key="create_createUnder">Create something under </localize> {{currentNode.name}}</h5>

    <ul class="umb-actions umb-actions-child">
        <li>            
            <a href="#/CustomSection/CustomSectionTree/edit/dashboard?create=true" ng-click="nav.hideNavigation()">
                <i class="large icon-car"></i> 
                <span class="menu-label">New custom item
                    <small>Click here to create this super custom item</small>
                </span>
            </a>
        </li> 
    </ul>
    </div>        
</div>
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar">
        <button class="btn" ng-click="nav.hideDialog()">
            <localize key="buttons_somethingElse">Do something else</localize>
        </button>
</div>

 

Yesterday we finally got the the first release of Umbraco 7 which introduce a new look and feel for the backoffice. Not only that – the technicall differences from V6 is huge.

 

Since I'm writing the popular newsletter-package Newsletter Studio for Umbraco I had look really deep into the source of Umbraco 7 to get things right.

 

Newsletter Studio -banner -580x 250


I now want to show you how to add a custom section with a custom tree to the Umbraco backoffice – some of the things is similar to how it used to work (in V4-6) and some things are new.

 

Creating the application

Every section in Umbraco is called an application, so sections and applications is basically the same thing.The first thing we’ll need to do is to create the application. In this examples I will not fiddle with the xml-files or the database – I’ll use class annotations to create my section.

The first thing I’ll need to do is to create a class that implements the IApplication-interface so that Umbraco will initialize this class on start up.

 

[Application("CustomSection", "CustomSection","icon-car", 15)]
public class CustomSectionApplication : IApplication {}

 

This is not something new for V7, The "Application"-attribute basically tells Umbraco to create a new application:
Name: CustomSection
Alias: CustomSection
Icon: icon-car (the css class for the icon that will be displayed in the left side bar of the backoffice)
Sort order: 15

The next time Umbraco runs it will add an XML-element to the /config/applications.config-file that will add our new section/application to the Umbraco backoffice.

 

Creating the tree

Before adding the tree, Umbraco will not care about your new application. An application without a tree is not worth anything =D Right?

This part contains some new concepts for V7. Let's start with creating a new class that inherits from Umbraco.Web.Trees.TreeController, make sure to suffix the class name with “Controller” ie. CustomSectionTreeController.

public class CustomSectionTreeController : TreeController
{
}

 

Now we need to give Umbraco some extra information about our tree. Let's add two attributes on the class, the Tree and the PluginController-attributes.

[PluginController("CustomSection")]
[Umbraco.Web.Trees.Tree("CustomSection", "CustomSectionTree", "My custom section", iconClosed: "icon-doc")]
public class CustomSectionTreeController : TreeController
{
}

 

PluginController

This attribute tells Umbraco that this class is part of a plugin, and it also tells Umbraco the name of that plugin. This will make Umbraco look for views inside the /app_plugin/{NameOfApplication}/-folder and not in the folder of the core-views which is the default.

 

Tree

This attribute is “older” and has been around since somewhere around 4.7 I think. It tells Umbraco that this is a tree-class and Umbraco will add this to the /config/trees.config-file. In V7 this attribute is mandatory for a tree that inherits from the TreeController-class as some underlying logic is looking at the attribute values to determine the name of the tree.

 

The properties are:
Application: CustomSection (must match the name of the application we added before)
Alias: CustomSectionTree (the name/alias of the tree)
Title: The title of the tree (used as the name of the root node)
Icon: The icon (or class) used as the tree icon.

 

Alright. Almost there. Now we need to add some code to show items in the tree.

[PluginController("CustomSection")]
[Umbraco.Web.Trees.Tree("CustomSection", "CustomSectionTree","My custom section", iconClosed: "icon-doc")]
public class CustomSectionTreeController : TreeController
{
    protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
    {
        var nodes = new TreeNodeCollection();
        var item = this.CreateTreeNode("dashboard", id, queryStrings, "My item", "icon-truck", true);
        nodes.Add(item);
        return nodes;
    }

    protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
    {
       var menu = new MenuItemCollection();
       menu.DefaultMenuAlias = ActionNew.Instance.Alias;
        menu.Items.Add<ActionNew>("Create");
        return menu;
    }
}

 

This will give us something like this:

 

image

 

This code has two methods that are the least we need to do to create a new section.

 

GetTreeNodes (TreeNodeCollection)

This returns a collection of tree items, in our case we just return one item but we could of curse add more items to the collection. We use the CreateTreeNode-method from the base class to create a new node called “My item” with the id “dashboard”. Umbraco will append the id of the node to the URL later on so that we can handle the routing from our AngularJS-controllers.

 

GetMenuForNode (MenuItemCollection)

imageThis method handles the “right click alternatives”. The “DefaultMenuAlias” configures which action that should be fired when we click the “touch dots” .

 

There's a lot of actions that you can use and you can also build your own ones.

 

image

 

Displaying our new section

To display our new section we need to give the current user access to it. Go to the users-section and open the edit-view for the current logged on user. In the bottom, check the checkbox for [CustomSection] and hit save. Now you’ll probably need to refresh the page using F5 to show the new section in the left side bar.

 

Making the [CustomSection]-text look better

Since Umbraco can’t find any language translation for our section it will use the brackets and the application name. To make this nicer, open the /umbraco/config/lang/en.xml-field and look for the <area alias=”sections”>-element. Inside that element, just add:

 

<key alias="CustomSection">Super Custom Section</key>

 

image

 

You may need to touch the root web.config file to restart the application before the new translation gets visible.

 

This is my first blog post about custom sections and custom trees in Umbraco 7 – next time I’ll you show how you can create the views for the new tree items.

After weeks of hard work from the guys in the core team Umbraco 7 was released today! The biggest news is the new look and feel of the backoffice.

 

dashboard

 

If you have used Umbraco before you’ll probably find your way around as the over all concepts are the same. If you know how to build websites with previous versions of Umbraco you’ll feel comfortable with V7 as well. The new backoffice has been built with the editors in mind and I must say that we’re seeing a lot of improvements! I really love the why that the people behind the design is thinking.

 

I’ve looked at the beta and RC-versions of V7 and provided some feedback (ie. the drag and drop into the media dialog) and I really recommend you to download the latest version and play with it! Start building your new sites with it! But it’s important to don’t leave your frustrations in your mind – share them at issues.umbraco.org so that the core team can do something about it! It’s the least each and everyone can do to contribute to this great project!

 

Niels Hartvig posted a nice video of the new backoffice, have a look at it here: http://umbraco.com/follow-us/blog-archive/2013/11/21/umbraco-7.aspx

Last week I hosted the first Umbraco Training Courses in Sweden. We now have more than 20 new certified Umbraco developers and some new companies have become Certified Partners.

 

Since it was my first course I can admit that I was a little bit nervous i the beginning of the week – I always get that feeling when stepping out of my “comfort zone” and doing something that I have never done before. So far I have only got good feedback from the attendees, some even called me “excellent” – thank you very much for that. =D

 

I’ve been asked if we are going to have a new round of training in Sweden. Of course! But we have not decided the exact dates yet. If you want to be noticed – sign up for our newsletter.

 

 

I also would like to share to share some photos from the course =D

 

level1

Level 1 attendees working on one of the exercises.

 

level2-book

The Level 2 workbook, razor-sheet sheet and the super fancy Umbraco USB that all attendees got a copy of.

 

level2-grupp

Attendees at the level 2 course.

 

level2-grupp2

Closest in this picture we see attendees from Chalmers in Gothenburg and from the Örebro-based company Impera

feature-datatypeI you’re a long time reader of this blog you know that I’m working hard with my newsletter-package for Umbraco – Newsletter Studio.

Today I announced some news that I hope will make some of all the web agencies out there happy. As web agencies over the world will all get a free Newsletter Studio license for their own website.

So if you your company web site runs on Umbraco, don’t wait – request your free license today!